blob: c5759cfc6815ee19bb58af3208c8b6950e4cb024 [file] [log] [blame]
// Copyright 2021 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 <fuchsia/fuzzer/cpp/fidl.h>
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/process.h>
#include <zircon/status.h>
#include <memory>
#include <gtest/gtest.h>
#include "src/sys/fuzzing/common/testing/async-test.h"
#include "src/sys/fuzzing/common/testing/integration-test-base.h"
#include "src/sys/fuzzing/testing/runner.h"
namespace fuzzing {
namespace {
using fuchsia::fuzzer::ControllerPtr;
using fuchsia::fuzzer::Options;
using fuchsia::fuzzer::Registrar;
using fuchsia::fuzzer::Registry;
using fuchsia::fuzzer::RegistryPtr;
// Test fixtures.
const char* kFuzzerUrl = "an arbitrary string";
// This class maintains the component context and connection to the fuzz-registry.
class RegistryIntegrationTest : public IntegrationTestBase {
protected:
void SetUp() override {
IntegrationTestBase::SetUp();
context_ = sys::ComponentContext::Create();
}
// Launch a fuzzer and give it a channel to register itself with the fuzz-registry.
void Register() {
// Connect a channel to the fuzz-registry.
fidl::InterfaceHandle<Registrar> handle;
auto status = context_->svc()->Connect(handle.NewRequest());
ASSERT_EQ(status, ZX_OK) << zx_status_get_string(status);
auto result = Start("/pkg/bin/component_fuzzing_test_fuzzer", handle.TakeChannel());
ASSERT_TRUE(result.is_ok());
}
// Promises to connect the |controller| once a fuzzer is registered.
ZxPromise<> Connect(ControllerPtr* controller, zx::duration timeout) {
auto status = context_->svc()->Connect(registry_.NewRequest());
if (status != ZX_OK) {
return fpromise::make_promise([status]() -> ZxResult<> { return fpromise::error(status); });
}
Bridge<zx_status_t> bridge;
registry_->Connect(kFuzzerUrl, controller->NewRequest(), timeout.get(),
bridge.completer.bind());
return bridge.consumer.promise().then(
[](Result<zx_status_t>& result) { return AsZxResult(result); });
}
// Promises to stop a fuzzer if running.
ZxPromise<> Disconnect() {
Bridge<zx_status_t> bridge;
registry_->Disconnect(kFuzzerUrl, bridge.completer.bind());
return bridge.consumer.promise()
.then([](Result<zx_status_t>& result) { return AsZxResult(result); })
.and_then(AwaitTermination());
}
private:
std::unique_ptr<sys::ComponentContext> context_;
RegistryPtr registry_;
};
} // namespace
// Unit tests
TEST_F(RegistryIntegrationTest, RegisterThenConnect) {
ASSERT_NO_FATAL_FAILURE(Register());
ControllerPtr controller;
FUZZING_EXPECT_OK(Connect(&controller, zx::sec(1)));
RunUntilIdle();
// Verify connected.
Bridge<Options> bridge;
controller->GetOptions(bridge.completer.bind());
FUZZING_EXPECT_OK(bridge.consumer.promise_or(fpromise::error()));
RunUntilIdle();
FUZZING_EXPECT_OK(Disconnect());
RunUntilIdle();
}
TEST_F(RegistryIntegrationTest, ConnectThenRegister) {
ControllerPtr controller;
FUZZING_EXPECT_OK(Connect(&controller, zx::sec(1)));
ASSERT_NO_FATAL_FAILURE(Register());
RunUntilIdle();
// Verify connected.
Bridge<Options> bridge;
controller->GetOptions(bridge.completer.bind());
FUZZING_EXPECT_OK(bridge.consumer.promise_or(fpromise::error()));
RunUntilIdle();
FUZZING_EXPECT_OK(Disconnect());
RunUntilIdle();
}
TEST_F(RegistryIntegrationTest, ConnectThenTimeout) {
ControllerPtr controller;
FUZZING_EXPECT_ERROR(Connect(&controller, zx::msec(1)), ZX_ERR_TIMED_OUT);
RunUntilIdle();
}
} // namespace fuzzing