blob: 8af2757e2432ad32d12c66a6ae470ada8944d060 [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_TEST_PKG_H_
#define SRC_DEVICES_BIN_DRIVER_MANAGER_TESTS_TEST_PKG_H_
#include <fidl/fuchsia.io/cpp/test_base.h>
#include <fuchsia/io/cpp/fidl_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/binding.h>
#include <zircon/errors.h>
#include <gtest/gtest.h>
namespace test_utils {
class TestFile : public fuchsia::io::testing::File_TestBase {
public:
explicit TestFile(std::string_view path) : path_(std::move(path)) {}
private:
void GetBackingMemory(fuchsia::io::VmoFlags flags, GetBackingMemoryCallback callback) override {
EXPECT_EQ(fuchsia::io::VmoFlags::READ | fuchsia::io::VmoFlags::EXECUTE |
fuchsia::io::VmoFlags::PRIVATE_CLONE,
flags);
auto [client, server] = fidl::Endpoints<fuchsia_io::File>::Create();
EXPECT_EQ(ZX_OK, fdio_open3(path_.data(),
uint64_t{fuchsia::io::PERM_READABLE | fuchsia::io::PERM_EXECUTABLE},
server.TakeChannel().release()));
fidl::WireSyncClient<fuchsia_io::File> file(std::move(client));
fidl::WireResult result = file->GetBackingMemory(fuchsia_io::wire::VmoFlags(uint32_t(flags)));
EXPECT_TRUE(result.ok()) << result.FormatDescription();
auto* res = result.Unwrap();
if (res->is_error()) {
callback(fuchsia::io::File_GetBackingMemory_Result::WithErr(std::move(res->error_value())));
return;
}
callback(fuchsia::io::File_GetBackingMemory_Result::WithResponse(
fuchsia::io::File_GetBackingMemory_Response(std::move(res->value()->vmo))));
}
void NotImplemented_(const std::string& name) override {
printf("Not implemented: File::%s\n", name.data());
}
std::string path_;
};
class TestDirectory : public fuchsia::io::testing::Directory_TestBase {
public:
using OpenHandler =
fit::function<void(fuchsia::io::Flags flags, const std::string& path, zx::channel object)>;
void SetOpenHandler(OpenHandler open_handler) { open_handler_ = std::move(open_handler); }
void Open(std::string path, fuchsia::io::Flags flags, fuchsia::io::Options mode,
zx::channel object) override {
open_handler_(flags, path, std::move(object));
}
void NotImplemented_(const std::string& name) override {
printf("Not implemented: Directory::%s\n", name.data());
}
OpenHandler open_handler_;
};
// Implementation of a /pkg directory that can be passed as a component namespace entry
// for the started driver host or driver component.
class TestPkg {
public:
struct ModuleConfig {
// Where the module is located in the test's package. e.g.
// /pkg/bin/driver_host2.
std::string_view test_pkg_path;
// The path that will be requested to the /pkg open
// handler for the module. e.g. bin/driver_host2.
std::string_view open_path;
};
struct Config {
ModuleConfig main_module;
// The names of the libraries that are needed by the main module.
// This list will be used to construct the test files that the driver host runner
// or driver runner expects to be present in the "/pkg/libs" dir that will be passed
// to the dynamic linker. No additional validation is done on the strings in |expected_libs|.
std::vector<std::string_view> expected_libs;
// Modules that need to be load with the main module.
// For example, the DFv1 driver to be loaded with the compatibility shim.
// Additional libs are not supported.
std::vector<ModuleConfig> additional_modules;
};
// |server| is the channel that will be served by |TestPkg|.
//
// |module_test_pkg_path| is where the module is located in the test's package. e.g.
// /pkg/bin/driver_host2.
//
// |module_open_path| is the path that will be requested to the /pkg open
// handler for the module. e.g. bin/driver_host2.
//
// |expected_libs| holds that names of the libraries that are needed by the module.
// This list will be used to construct the test files that the driver host runner
// or driver runner expects to be present in the "/pkg/libs" dir that will be passed
// to the dynamic linker. No additional validation is done on the strings in |expected_libs|.
TestPkg(fidl::ServerEnd<fuchsia_io::Directory> server, std::string_view module_test_pkg_path,
std::string_view module_open_path, const std::vector<std::string_view> expected_libs,
const std::vector<ModuleConfig> additional_modules_configs = std::vector<ModuleConfig>());
TestPkg(fidl::ServerEnd<fuchsia_io::Directory> server, Config config)
: TestPkg(std::move(server), config.main_module.test_pkg_path, config.main_module.open_path,
config.expected_libs, config.additional_modules) {}
~TestPkg() {
loop_.Quit();
loop_.JoinThreads();
}
private:
static constexpr std::string_view kLibPathPrefix = "/pkg/lib/";
struct Module {
TestFile file;
std::unique_ptr<fidl::Binding<fuchsia::io::File>> binding;
// The path that will be requested to the /pkg open
// handler for the module. e.g. bin/driver_host2.
std::string open_path;
};
async::Loop loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
TestDirectory pkg_dir_;
fidl::Binding<fuchsia::io::Directory> pkg_binding_{&pkg_dir_};
TestDirectory lib_dir_;
fidl::Binding<fuchsia::io::Directory> lib_dir_binding_{&lib_dir_};
std::map<std::string, TestFile> libname_to_file_;
std::vector<std::unique_ptr<fidl::Binding<fuchsia::io::File>>> lib_file_bindings_;
TestFile module_;
fidl::Binding<fuchsia::io::File> module_binding_{&module_};
// The fake test files and bindings for the additional modules.
std::vector<Module> additional_modules_;
};
} // namespace test_utils
#endif // SRC_DEVICES_BIN_DRIVER_MANAGER_TESTS_TEST_PKG_H_