blob: c0dfe9609f1517df359b912601399a25914dd9a5 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/sys/fuzzing/common/tests/integration-tests.h"
#include "src/sys/fuzzing/common/artifact.h"
#include "src/sys/fuzzing/common/async-socket.h"
#include "src/sys/fuzzing/common/engine.h"
#include "src/sys/fuzzing/common/testing/component-context.h"
namespace fuzzing {
using ::fuchsia::fuzzer::FUZZ_MODE;
void EngineIntegrationTest::SetUp() {
AsyncTest::SetUp();
context_ = ComponentContextForTest::Create(executor());
engine_ = std::make_unique<ChildProcess>(executor());
}
ZxPromise<ControllerPtr> EngineIntegrationTest::Start() {
registrar_ = std::make_unique<FakeRegistrar>(executor());
return fpromise::make_promise([this]() -> ZxResult<> {
fidl::InterfaceHandle<Registrar> registrar = registrar_->NewBinding();
engine_->Reset();
engine_->AddArg(program_binary());
engine_->AddArg(component_url());
for (const auto& arg : extra_args()) {
engine_->AddArg(arg);
}
engine_->AddArg(FUZZ_MODE);
engine_->AddChannel(ComponentContextForTest::kRegistrarId, registrar.TakeChannel());
engine_->AddChannel(ComponentContextForTest::kCoverageId, fuzz_coverage());
return fpromise::ok();
})
.and_then([this]() { return AsZxResult(engine_->Spawn()); })
.and_then(registrar_->TakeProvider())
.and_then([this, consumer_fut = Future<>(), controller = ControllerPtr()](
Context& context,
ControllerProviderHandle& handle) mutable -> ZxResult<ControllerPtr> {
// Connect a controller to the spawned process.
if (!consumer_fut) {
auto request = controller.NewRequest(executor()->dispatcher());
Bridge<> bridge;
provider_ = handle.Bind();
provider_->Connect(std::move(request), bridge.completer.bind());
consumer_fut = bridge.consumer.promise();
}
if (!consumer_fut(context)) {
return fpromise::pending();
}
return fpromise::ok(std::move(controller));
})
.and_then(
[this, consumer_fut = Future<zx_status_t>()](
Context& context, ControllerPtr& controller) mutable -> ZxResult<ControllerPtr> {
if (!consumer_fut) {
Bridge<zx_status_t> bridge;
Options options;
set_options(options);
controller->Configure(std::move(options), bridge.completer.bind());
consumer_fut = bridge.consumer.promise();
}
if (!consumer_fut(context)) {
return fpromise::pending();
}
if (consumer_fut.is_error()) {
return fpromise::error(ZX_ERR_CANCELED);
}
if (auto status = consumer_fut.take_value(); status != ZX_OK) {
return fpromise::error(status);
}
return fpromise::ok(std::move(controller));
})
.wrap_with(scope_);
}
void EngineIntegrationTest::TearDown() {
Schedule(engine_->Kill());
RunUntilIdle();
AsyncTest::TearDown();
}
void EngineIntegrationTest::Crash() {
ControllerPtr controller;
FUZZING_EXPECT_OK(Start(), &controller);
RunUntilIdle();
Input input("FUZZ");
ZxBridge<FuzzResult> bridge1;
controller->Execute(AsyncSocketWrite(executor(), input.Duplicate()),
ZxBind<FuzzResult>(std::move(bridge1.completer)));
FUZZING_EXPECT_OK(bridge1.consumer.promise(), FuzzResult::CRASH);
Bridge<Status> bridge2;
controller->GetStatus(bridge2.completer.bind());
Status status;
FUZZING_EXPECT_OK(bridge2.consumer.promise(), &status);
RunUntilIdle();
EXPECT_TRUE(status.has_elapsed());
ZxBridge<FidlArtifact> bridge3;
controller->GetResults([completer = std::move(bridge3.completer)](FuzzResult fuzz_result,
FidlInput fidl_input) mutable {
completer.complete_ok(MakeFidlArtifact(fuzz_result, std::move(fidl_input)));
});
auto task = bridge3.consumer.promise().and_then([this](FidlArtifact& fidl_artifact) {
return AsyncSocketRead(executor(), std::move(fidl_artifact));
});
Artifact artifact;
FUZZING_EXPECT_OK(task, &artifact);
RunUntilIdle();
EXPECT_EQ(artifact.fuzz_result(), FuzzResult::CRASH);
EXPECT_EQ(artifact.input(), input);
}
} // namespace fuzzing