blob: 720f7d78ebe51a04f9b8acb521852f3c6924b8ed [file] [log] [blame]
// Copyright 2024 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.
#ifndef SRC_DEVICES_BIN_DRIVER_MANAGER_TESTS_DRIVER_RUNNER_TEST_FIXTURE_H_
#define SRC_DEVICES_BIN_DRIVER_MANAGER_TESTS_DRIVER_RUNNER_TEST_FIXTURE_H_
#include <fidl/fuchsia.component.decl/cpp/test_base.h>
#include <fidl/fuchsia.component/cpp/test_base.h>
#include <fidl/fuchsia.driver.framework/cpp/test_base.h>
#include <fidl/fuchsia.driver.host/cpp/test_base.h>
#include <fidl/fuchsia.io/cpp/test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fit/defer.h>
#include <lib/inspect/cpp/reader.h>
#include <lib/inspect/testing/cpp/inspect.h>
#include <bind/fuchsia/platform/cpp/bind.h>
#include "src/devices/bin/driver_manager/driver_runner.h"
#include "src/devices/bin/driver_manager/testing/fake_driver_index.h"
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
namespace driver_runner {
namespace fdfw = fuchsia_driver_framework;
namespace fdh = fuchsia_driver_host;
namespace fio = fuchsia_io;
namespace fprocess = fuchsia_process;
namespace fdecl = fuchsia_component_decl;
const std::string root_driver_url = "fuchsia-boot:///#meta/root-driver.cm";
const std::string root_driver_binary = "driver/root-driver.so";
const std::string second_driver_url = "fuchsia-boot:///#meta/second-driver.cm";
const std::string second_driver_binary = "driver/second-driver.so-";
using driver_manager::Devfs;
using driver_manager::DriverRunner;
using driver_manager::InspectManager;
struct NodeChecker {
std::vector<std::string> node_name;
std::vector<std::string> child_names;
std::map<std::string, std::string> str_properties;
};
struct CreatedChild {
std::optional<fidl::Client<fdfw::Node>> node;
std::optional<fidl::Client<fdfw::NodeController>> node_controller;
};
void CheckNode(const inspect::Hierarchy& hierarchy, const NodeChecker& checker);
class TestRealm : public fidl::testing::TestBase<fuchsia_component::Realm> {
public:
using CreateChildHandler = fit::function<void(fdecl::CollectionRef collection, fdecl::Child decl,
std::vector<fdecl::Offer> offers)>;
using OpenExposedDirHandler =
fit::function<void(fdecl::ChildRef child, fidl::ServerEnd<fio::Directory> exposed_dir)>;
void SetCreateChildHandler(CreateChildHandler create_child_handler) {
create_child_handler_ = std::move(create_child_handler);
}
void SetOpenExposedDirHandler(OpenExposedDirHandler open_exposed_dir_handler) {
open_exposed_dir_handler_ = std::move(open_exposed_dir_handler);
}
fidl::VectorView<fprocess::wire::HandleInfo> TakeHandles(fidl::AnyArena& arena);
void AssertDestroyedChildren(const std::vector<fdecl::ChildRef>& expected);
private:
void CreateChild(CreateChildRequest& request, CreateChildCompleter::Sync& completer) override;
void DestroyChild(DestroyChildRequest& request, DestroyChildCompleter::Sync& completer) override;
void OpenExposedDir(OpenExposedDirRequest& request,
OpenExposedDirCompleter::Sync& completer) override;
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
printf("Not implemented: Realm::%s\n", name.c_str());
}
CreateChildHandler create_child_handler_;
OpenExposedDirHandler open_exposed_dir_handler_;
std::optional<std::vector<fprocess::HandleInfo>> handles_;
std::vector<fdecl::ChildRef> destroyed_children_;
};
class TestDirectory : public fidl::testing::TestBase<fio::Directory> {
public:
using OpenHandler =
fit::function<void(const std::string& path, fidl::ServerEnd<fio::Node> object)>;
explicit TestDirectory(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
void Bind(fidl::ServerEnd<fio::Directory> request);
void SetOpenHandler(OpenHandler open_handler) { open_handler_ = std::move(open_handler); }
private:
void Clone(CloneRequest& request, CloneCompleter::Sync& completer) override;
void Open(OpenRequest& request, OpenCompleter::Sync& completer) override;
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
printf("Not implemented: Directory::%s\n", name.c_str());
}
async_dispatcher_t* dispatcher_;
fidl::ServerBindingGroup<fio::Directory> bindings_;
OpenHandler open_handler_;
};
struct Driver {
std::string url;
std::string binary;
bool colocate = false;
bool close = false;
bool host_restart_on_crash = false;
bool use_next_vdso = false;
};
class TestDriver : public fidl::testing::TestBase<fdh::Driver> {
public:
explicit TestDriver(async_dispatcher_t* dispatcher, fidl::ClientEnd<fdfw::Node> node,
fidl::ServerEnd<fdh::Driver> server)
: dispatcher_(dispatcher),
stop_handler_([]() {}),
node_(std::move(node), dispatcher),
driver_binding_(dispatcher, std::move(server), this, fidl::kIgnoreBindingClosure) {}
fidl::Client<fdfw::Node>& node() { return node_; }
using StopHandler = fit::function<void()>;
void SetStopHandler(StopHandler handler) { stop_handler_ = std::move(handler); }
void SetDontCloseBindingInStop() { dont_close_binding_in_stop_ = true; }
void Stop(StopCompleter::Sync& completer) override;
void DropNode() { node_ = {}; }
void CloseBinding() { driver_binding_.Close(ZX_OK); }
std::shared_ptr<CreatedChild> AddChild(std::string_view child_name, bool owned, bool expect_error,
const std::string& class_name = "driver_runner_test");
std::shared_ptr<CreatedChild> AddChild(
fdfw::NodeAddArgs child_args, bool owned, bool expect_error,
fit::function<void()> on_bind = []() {});
private:
async_dispatcher_t* dispatcher_;
StopHandler stop_handler_;
fidl::Client<fdfw::Node> node_;
fidl::ServerBinding<fdh::Driver> driver_binding_;
bool dont_close_binding_in_stop_ = false;
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
printf("Not implemented: Driver::%s\n", name.c_str());
}
};
class TestDriverHost : public fidl::testing::TestBase<fdh::DriverHost> {
public:
using StartHandler =
fit::function<void(fdfw::DriverStartArgs start_args, fidl::ServerEnd<fdh::Driver> driver)>;
void SetStartHandler(StartHandler start_handler) { start_handler_ = std::move(start_handler); }
private:
void Start(StartRequest& request, StartCompleter::Sync& completer) override {
start_handler_(std::move(request.start_args()), std::move(request.driver()));
completer.Reply(zx::ok());
}
void InstallLoader(InstallLoaderRequest& request,
InstallLoaderCompleter::Sync& completer) override {}
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
printf("Not implemented: DriverHost::%s\n", name.data());
}
StartHandler start_handler_;
};
fidl::AnyTeardownObserver TeardownWatcher(size_t index, std::vector<size_t>& indices);
fdecl::ChildRef CreateChildRef(std::string name, std::string collection);
struct Driver;
class DriverRunnerTest : public gtest::TestLoopFixture {
public:
void TearDown() override { Unbind(); }
protected:
InspectManager& inspect() { return inspect_; }
TestRealm& realm() { return realm_; }
TestDirectory& driver_dir() { return driver_dir_; }
TestDriverHost& driver_host() { return driver_host_; }
fidl::WireClient<fuchsia_device::Controller> ConnectToDeviceController(
std::string_view child_name);
fidl::ClientEnd<fuchsia_component::Realm> ConnectToRealm();
FakeDriverIndex CreateDriverIndex();
void SetupDriverRunner(FakeDriverIndex driver_index);
void SetupDriverRunner();
void PrepareRealmForDriverComponentStart(const std::string& name, const std::string& url);
void PrepareRealmForSecondDriverComponentStart();
void PrepareRealmForStartDriverHost(bool use_next_vdso);
void StopDriverComponent(
fidl::ClientEnd<fuchsia_component_runner::ComponentController> component);
struct StartDriverResult {
std::unique_ptr<TestDriver> driver;
fidl::ClientEnd<fuchsia_component_runner::ComponentController> controller;
};
using StartDriverHandler = fit::function<void(TestDriver*, fdfw::DriverStartArgs)>;
StartDriverResult StartDriver(Driver driver,
std::optional<StartDriverHandler> start_handler = std::nullopt);
zx::result<StartDriverResult> StartRootDriver();
StartDriverResult StartSecondDriver(bool colocate = false, bool host_restart_on_crash = false,
bool use_next_vdso = false);
void Unbind();
static void ValidateProgram(std::optional<::fuchsia_data::Dictionary>& program,
std::string_view binary, std::string_view colocate,
std::string_view host_restart_on_crash,
std::string_view use_next_vdso);
static void AssertNodeBound(const std::shared_ptr<CreatedChild>& child);
static void AssertNodeNotBound(const std::shared_ptr<CreatedChild>& child);
static void AssertNodeControllerBound(const std::shared_ptr<CreatedChild>& child);
static void AssertNodeControllerNotBound(const std::shared_ptr<CreatedChild>& child);
inspect::Hierarchy Inspect();
void SetupDevfs();
Devfs& devfs() {
ZX_ASSERT(devfs_.has_value());
return devfs_.value();
}
DriverRunner& driver_runner() { return driver_runner_.value(); }
FakeDriverIndex& driver_index() { return driver_index_.value(); }
private:
TestRealm realm_;
TestDirectory driver_host_dir_{dispatcher()};
TestDirectory driver_dir_{dispatcher()};
TestDriverHost driver_host_;
std::optional<fidl::ServerBinding<fuchsia_component::Realm>> realm_binding_;
std::optional<fidl::ServerBinding<fdh::DriverHost>> driver_host_binding_;
std::optional<Devfs> devfs_;
InspectManager inspect_{dispatcher()};
std::optional<FakeDriverIndex> driver_index_;
std::optional<DriverRunner> driver_runner_;
};
} // namespace driver_runner
#endif // SRC_DEVICES_BIN_DRIVER_MANAGER_TESTS_DRIVER_RUNNER_TEST_FIXTURE_H_