| // Copyright 2020 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 <elf.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/async/cpp/executor.h> |
| #include <lib/ddk/binding.h> |
| #include <zircon/errors.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "multiple_device_test.h" |
| #include "package_resolver.h" |
| |
| class FakePackageResolver : public internal::PackageResolverInterface { |
| public: |
| struct DriverInfo { |
| std::string package_url; |
| std::string libname; |
| zx::vmo vmo; |
| }; |
| |
| // Saves the |libname| and |vmo| that will be returned when |FetchDriverVmo| is queried |
| // with |package_url|. |
| void Register(std::string package_url, std::string libname, zx::vmo vmo) { |
| registered_drivers_.push_back(DriverInfo{package_url, libname, std::move(vmo)}); |
| } |
| |
| zx::status<std::unique_ptr<Driver>> FetchDriver(const std::string& package_url) override { |
| for (auto& driver_info : registered_drivers_) { |
| if (driver_info.package_url != package_url) { |
| continue; |
| } |
| Driver* driver = nullptr; |
| DriverLoadCallback callback = [&driver](Driver* d, const char* version) mutable { |
| driver = d; |
| }; |
| |
| zx_status_t status = load_driver_vmo(nullptr, driver_info.libname, std::move(driver_info.vmo), |
| std::move(callback)); |
| if (status != ZX_OK) { |
| return zx::error(status); |
| } |
| return zx::ok(std::unique_ptr<Driver>(driver)); |
| } |
| return zx::error(ZX_ERR_NOT_FOUND); |
| } |
| |
| private: |
| std::vector<DriverInfo> registered_drivers_; |
| }; |
| |
| class LoadDriverPackageTestCase : public MultipleDeviceTestCase { |
| public: |
| LoadDriverPackageTestCase() : MultipleDeviceTestCase(true /* enable_ephemeral */) {} |
| }; |
| |
| TEST_F(LoadDriverPackageTestCase, LoadRegisteredDriver) { |
| auto& drivers = coordinator().drivers(); |
| size_t num_drivers = drivers.size_slow(); |
| |
| // Borrow a valid driver vmo that can be duplicated as executable. |
| zx::vmo driver_vmo; |
| ASSERT_OK(coordinator().LibnameToVmo(coordinator().fragment_driver()->libname, &driver_vmo)); |
| |
| std::string package_url("test_driver_url"); |
| std::string libname("test_driver_libname"); |
| |
| FakePackageResolver resolver; |
| resolver.Register(package_url, libname, std::move(driver_vmo)); |
| |
| ASSERT_OK(coordinator().LoadEphemeralDriver(&resolver, package_url.c_str())); |
| coordinator_loop()->RunUntilIdle(); |
| |
| // A new driver should be added. |
| ASSERT_EQ(drivers.size_slow(), num_drivers + 1); |
| ASSERT_EQ(drivers.back().libname, libname); |
| } |
| |
| TEST_F(LoadDriverPackageTestCase, LoadUnregisteredDriver) { |
| auto& drivers = coordinator().drivers(); |
| size_t num_drivers = drivers.size_slow(); |
| |
| FakePackageResolver resolver; |
| std::string package_url("test_driver_url"); |
| ASSERT_NOT_OK(coordinator().LoadEphemeralDriver(&resolver, package_url)); |
| |
| coordinator_loop()->RunUntilIdle(); |
| // No new driver should be added. |
| ASSERT_EQ(drivers.size_slow(), num_drivers); |
| } |
| |
| // Test that loading drivers ephemerally can be disabled. |
| class EphemeralDisabledTestCase : public MultipleDeviceTestCase { |
| public: |
| EphemeralDisabledTestCase() : MultipleDeviceTestCase(false /* enable_ephemeral */) {} |
| }; |
| |
| TEST_F(EphemeralDisabledTestCase, LoadingDriverFails) { |
| ASSERT_DEATH([&] { |
| FakePackageResolver resolver; |
| std::string package_url("test_driver_url"); |
| coordinator().LoadEphemeralDriver(&resolver, package_url); |
| }); |
| } |