| // Copyright 2019 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 <fidl/fuchsia.driver.test.logger/cpp/wire.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/ddk/binding.h> |
| #include <lib/ddk/driver.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fidl/coding.h> |
| #include <lib/fidl/cpp/message.h> |
| #include <string.h> |
| #include <threads.h> |
| #include <zircon/fidl.h> |
| |
| #include <vector> |
| |
| #include <fbl/algorithm.h> |
| #include <fbl/vector.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "coordinator_test_utils.h" |
| #include "devfs.h" |
| #include "driver_host.h" |
| #include "fdio.h" |
| #include "src/devices/bin/driver_manager/fake_driver_index.h" |
| |
| constexpr char kDriverPath[] = "/pkg/driver/mock-device.so"; |
| |
| static CoordinatorConfig NullConfig() { return DefaultConfig(nullptr, nullptr, nullptr); } |
| |
| namespace { |
| |
| class FidlTransaction : public fidl::Transaction { |
| public: |
| FidlTransaction(FidlTransaction&&) = default; |
| explicit FidlTransaction(zx_txid_t transaction_id, zx::unowned_channel channel) |
| : txid_(transaction_id), channel_(channel) {} |
| |
| std::unique_ptr<fidl::Transaction> TakeOwnership() override { |
| return std::make_unique<FidlTransaction>(std::move(*this)); |
| } |
| |
| zx_status_t Reply(fidl::OutgoingMessage* message, fidl::WriteOptions write_options) override { |
| ZX_ASSERT(txid_ != 0); |
| message->set_txid(txid_); |
| txid_ = 0; |
| message->Write(channel_, std::move(write_options)); |
| return message->status(); |
| } |
| |
| void Close(zx_status_t epitaph) override { ZX_ASSERT(false); } |
| |
| void InternalError(fidl::UnbindInfo info, fidl::ErrorOrigin origin) override { |
| detected_error_ = info; |
| } |
| |
| ~FidlTransaction() override = default; |
| |
| const std::optional<fidl::UnbindInfo>& detected_error() const { return detected_error_; } |
| |
| private: |
| zx_txid_t txid_; |
| zx::unowned_channel channel_; |
| std::optional<fidl::UnbindInfo> detected_error_; |
| }; |
| |
| class FakeDevice : public fidl::WireServer<fuchsia_device_manager::DeviceController> { |
| public: |
| FakeDevice(fidl::ServerEnd<fuchsia_driver_test_logger::Logger> test_output, |
| const fidl::StringView expected_driver = {}) |
| : test_output_(std::move(test_output)), expected_driver_(expected_driver) {} |
| |
| void BindDriver(BindDriverRequestView request, BindDriverCompleter::Sync& completer) override { |
| if (expected_driver_.empty() || expected_driver_.get() == request->driver_path.get()) { |
| bind_called_ = true; |
| completer.Reply(ZX_OK, test_output_.TakeChannel()); |
| } else { |
| completer.Reply(ZX_ERR_INTERNAL, zx::channel{}); |
| } |
| } |
| void ConnectProxy(ConnectProxyRequestView request, |
| ConnectProxyCompleter::Sync& _completer) override {} |
| void Init(InitRequestView request, InitCompleter::Sync& completer) override {} |
| void Suspend(SuspendRequestView request, SuspendCompleter::Sync& completer) override {} |
| void Resume(ResumeRequestView request, ResumeCompleter::Sync& completer) override {} |
| void Unbind(UnbindRequestView request, UnbindCompleter::Sync& completer) override {} |
| void CompleteRemoval(CompleteRemovalRequestView request, |
| CompleteRemovalCompleter::Sync& completer) override {} |
| void Open(OpenRequestView request, OpenCompleter::Sync& _completer) override {} |
| |
| bool bind_called() { return bind_called_; } |
| |
| private: |
| fidl::ServerEnd<fuchsia_driver_test_logger::Logger> test_output_; |
| const fidl::StringView expected_driver_; |
| bool bind_called_ = false; |
| }; |
| |
| // Reads a BindDriver request from remote, checks that it is for the expected |
| // driver, and then sends a ZX_OK response. |
| void CheckBindDriverReceived( |
| const fidl::ServerEnd<fuchsia_device_manager::DeviceController>& controller, |
| const fidl::StringView expected_driver) { |
| uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES]; |
| zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES]; |
| fidl_channel_handle_metadata_t handle_metadata[ZX_CHANNEL_MAX_MSG_HANDLES]; |
| fidl::IncomingMessage msg = fidl::MessageRead( |
| controller.channel(), fidl::ChannelMessageStorageView{ |
| .bytes = fidl::BufferSpan(bytes, std::size(bytes)), |
| .handles = handles, |
| .handle_metadata = handle_metadata, |
| .handle_capacity = ZX_CHANNEL_MAX_MSG_HANDLES, |
| }); |
| ASSERT_TRUE(msg.ok()); |
| |
| auto* header = msg.header(); |
| FidlTransaction txn(header->txid, zx::unowned(controller.channel())); |
| |
| FakeDevice fake(fidl::ServerEnd<fuchsia_driver_test_logger::Logger>(), expected_driver); |
| fidl::WireDispatch( |
| static_cast<fidl::WireServer<fuchsia_device_manager::DeviceController>*>(&fake), |
| std::move(msg), &txn); |
| ASSERT_FALSE(txn.detected_error()); |
| ASSERT_TRUE(fake.bind_called()); |
| } |
| |
| } // namespace |
| |
| TEST(MiscTestCase, InitCoreDevices) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| coordinator.InitCoreDevices(kSystemDriverPath); |
| } |
| |
| TEST(MiscTestCase, DumpState) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| coordinator.InitCoreDevices(kSystemDriverPath); |
| |
| constexpr int32_t kBufSize = 256; |
| char buf[kBufSize + 1] = {0}; |
| |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(kBufSize, 0, &vmo)); |
| VmoWriter writer(std::move(vmo)); |
| |
| coordinator.debug_dump()->DumpState(&writer); |
| |
| ASSERT_EQ(writer.written(), writer.available()); |
| ASSERT_LT(writer.written(), kBufSize); |
| ASSERT_GT(writer.written(), 0); |
| ASSERT_OK(writer.vmo().read(buf, 0, writer.written())); |
| |
| ASSERT_NE(nullptr, strstr(buf, "[root]")); |
| } |
| |
| TEST(MiscTestCase, LoadDriver) { |
| bool found_driver = false; |
| auto callback = [&found_driver](Driver* drv, const char* version) { |
| delete drv; |
| found_driver = true; |
| }; |
| load_driver(nullptr, kDriverPath, callback); |
| ASSERT_TRUE(found_driver); |
| } |
| |
| TEST(MiscTestCase, LoadDisabledDriver) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| ASSERT_OK(loop.StartThread("mock-boot-args")); |
| mock_boot_arguments::Server boot_args{{{"driver.mock_device.disable", "true"}}}; |
| fidl::WireSyncClient<fuchsia_boot::Arguments> client; |
| boot_args.CreateClient(loop.dispatcher(), &client); |
| |
| bool found_driver = false; |
| auto callback = [&found_driver](Driver* drv, const char* version) { |
| delete drv; |
| found_driver = true; |
| }; |
| load_driver(&client, kDriverPath, callback); |
| ASSERT_FALSE(found_driver); |
| } |
| |
| TEST(MiscTestCase, BindDrivers) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| |
| coordinator.InitCoreDevices(kSystemDriverPath); |
| coordinator.set_running(true); |
| |
| Driver* driver; |
| auto callback = [&coordinator, &driver](Driver* drv, const char* version) { |
| driver = drv; |
| return coordinator.DriverAdded(drv, version); |
| }; |
| load_driver(nullptr, kDriverPath, callback); |
| loop.RunUntilIdle(); |
| ASSERT_EQ(1, coordinator.drivers().size_slow()); |
| ASSERT_EQ(driver, &coordinator.drivers().front()); |
| } |
| |
| TEST(MiscTestCase, BindDevices) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| |
| ASSERT_NO_FATAL_FAILURE(InitializeCoordinator(&coordinator)); |
| |
| // Add the device. |
| auto controller_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::DeviceController>(); |
| ASSERT_OK(controller_endpoints.status_value()); |
| |
| auto coordinator_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Coordinator>(); |
| ASSERT_OK(coordinator_endpoints.status_value()); |
| |
| fbl::RefPtr<Device> device; |
| auto status = coordinator.device_manager()->AddDevice( |
| coordinator.sys_device(), std::move(controller_endpoints->client), |
| std::move(coordinator_endpoints->server), nullptr /* props_data */, 0 /* props_count */, |
| nullptr /* str_props_data */, 0 /* str_props_count */, "mock-device", ZX_PROTOCOL_TEST, |
| {} /* driver_path */, {} /* args */, false /* skip_autobind */, false /* has_init */, |
| true /* always_init */, zx::vmo() /*inspect*/, zx::channel() /* client_remote */, |
| fidl::ClientEnd<fio::Directory>() /* outgoing_dir */, &device); |
| ASSERT_OK(status); |
| ASSERT_EQ(1, coordinator.device_manager()->devices().size_slow()); |
| |
| // Add the driver. |
| load_driver(nullptr, kDriverPath, fit::bind_member(&coordinator, &Coordinator::DriverAdded)); |
| loop.RunUntilIdle(); |
| ASSERT_FALSE(coordinator.drivers().is_empty()); |
| |
| // The device has no driver_host, so the init task should automatically complete. |
| ASSERT_TRUE(device->is_visible()); |
| ASSERT_EQ(Device::State::kActive, device->state()); |
| |
| // Bind the device to a fake driver_host. |
| fbl::RefPtr<Device> dev = fbl::RefPtr(&coordinator.device_manager()->devices().front()); |
| auto host = fbl::MakeRefCounted<DriverHost>( |
| &coordinator, fidl::ClientEnd<fuchsia_device_manager::DriverHostController>(), |
| fidl::ClientEnd<fuchsia_io::Directory>(), zx::process{}); |
| dev->set_host(std::move(host)); |
| status = coordinator.bind_driver_manager()->BindDevice(dev, kDriverPath, true /* new device */); |
| ASSERT_OK(status); |
| |
| // Check the BindDriver request. |
| ASSERT_NO_FATAL_FAILURE( |
| CheckBindDriverReceived(controller_endpoints->server, fidl::StringView(kDriverPath))); |
| loop.RunUntilIdle(); |
| |
| // Reset the fake driver_host connection. |
| dev->set_host(nullptr); |
| coordinator_endpoints->client.reset(); |
| controller_endpoints->server.reset(); |
| loop.RunUntilIdle(); |
| } |
| |
| void CompareStrProperty(const fuchsia_device_manager::wire::DeviceStrProperty expected, |
| const StrProperty actual) { |
| ASSERT_STREQ(expected.key.get(), actual.key); |
| |
| if (expected.value.is_int_value()) { |
| auto* value = std::get_if<StrPropValueType::Integer>(&actual.value); |
| ASSERT_TRUE(value); |
| ASSERT_EQ(expected.value.int_value(), *value); |
| } else if (expected.value.is_str_value()) { |
| auto* value = std::get_if<StrPropValueType::String>(&actual.value); |
| ASSERT_TRUE(value); |
| ASSERT_STREQ(expected.value.str_value(), *value); |
| } else if (expected.value.is_bool_value()) { |
| auto* value = std::get_if<StrPropValueType::Bool>(&actual.value); |
| ASSERT_TRUE(value); |
| ASSERT_EQ(expected.value.bool_value(), *value); |
| } else if (expected.value.is_enum_value()) { |
| auto* value = std::get_if<StrPropValueType::Enum>(&actual.value); |
| ASSERT_TRUE(value); |
| ASSERT_STREQ(expected.value.enum_value(), *value); |
| } |
| } |
| |
| // Adds a device with the given properties to the device coordinator, then checks that the |
| // coordinator contains the device, and that its properties are correct. |
| void AddDeviceWithProperties(const fuchsia_device_manager::wire::DeviceProperty* props_data, |
| size_t props_count, |
| const fuchsia_device_manager::wire::DeviceStrProperty* str_props_data, |
| size_t str_props_count) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| |
| ASSERT_NO_FATAL_FAILURE(InitializeCoordinator(&coordinator)); |
| |
| auto controller_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::DeviceController>(); |
| ASSERT_OK(controller_endpoints.status_value()); |
| |
| auto coordinator_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Coordinator>(); |
| ASSERT_OK(coordinator_endpoints.status_value()); |
| |
| fbl::RefPtr<Device> device; |
| auto status = coordinator.device_manager()->AddDevice( |
| coordinator.sys_device(), std::move(controller_endpoints->client), |
| std::move(coordinator_endpoints->server), props_data, props_count, str_props_data, |
| str_props_count, "mock-device", ZX_PROTOCOL_TEST, {} /* driver_path */, {} /* args */, |
| false /* skip_autobind */, false /* has_init */, true /* always_init */, |
| zx::vmo() /*inspect*/, zx::channel() /* client_remote */, |
| fidl::ClientEnd<fio::Directory>() /* outgoing_dir */, &device); |
| ASSERT_OK(status); |
| |
| // Check that the device has been added to the coordinator, with the correct properties. |
| ASSERT_EQ(1, coordinator.device_manager()->devices().size_slow()); |
| const Device& dev = coordinator.device_manager()->devices().front(); |
| ASSERT_EQ(dev.props().size(), props_count); |
| for (size_t i = 0; i < props_count; i++) { |
| ASSERT_EQ(dev.props()[i].id, props_data[i].id); |
| ASSERT_EQ(dev.props()[i].reserved, props_data[i].reserved); |
| ASSERT_EQ(dev.props()[i].value, props_data[i].value); |
| } |
| |
| ASSERT_EQ(dev.str_props().size(), str_props_count); |
| for (size_t i = 0; i < str_props_count; i++) { |
| CompareStrProperty(str_props_data[i], dev.str_props()[i]); |
| } |
| |
| controller_endpoints->server.reset(); |
| coordinator_endpoints->client.reset(); |
| loop.RunUntilIdle(); |
| } |
| |
| TEST(MiscTestCase, DeviceProperties) { |
| // No properties. |
| AddDeviceWithProperties(nullptr, 0, nullptr, 0); |
| |
| // Multiple device properties. No string properties. |
| fuchsia_device_manager::wire::DeviceProperty props[] = { |
| fuchsia_device_manager::wire::DeviceProperty{1, 0, 1}, |
| fuchsia_device_manager::wire::DeviceProperty{2, 0, 1}, |
| }; |
| AddDeviceWithProperties(props, std::size(props), nullptr, 0); |
| |
| uint32_t int_val = 1000; |
| auto str_val = fidl::StringView::FromExternal("timberdoodle"); |
| |
| // Multiple device string properties. No device properties. |
| fuchsia_device_manager::wire::DeviceStrProperty str_props[] = { |
| fuchsia_device_manager::wire::DeviceStrProperty{ |
| "snipe", fuchsia_device_manager::wire::PropertyValue::WithStrValue( |
| fidl::ObjectView<fidl::StringView>::FromExternal(&str_val))}, |
| fuchsia_device_manager::wire::DeviceStrProperty{ |
| "sandpiper", fuchsia_device_manager::wire::PropertyValue::WithIntValue(int_val)}, |
| }; |
| AddDeviceWithProperties(nullptr, 0, str_props, std::size(str_props)); |
| |
| // Multiple device properties and device string properties. |
| AddDeviceWithProperties(props, std::size(props), str_props, std::size(str_props)); |
| } |
| |
| TEST(MiscTestCase, InvalidStringProperties) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| InspectManager inspect_manager(loop.dispatcher()); |
| Coordinator coordinator(NullConfig(), &inspect_manager, loop.dispatcher(), loop.dispatcher()); |
| |
| ASSERT_NO_FATAL_FAILURE(InitializeCoordinator(&coordinator)); |
| |
| auto controller_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::DeviceController>(); |
| ASSERT_OK(controller_endpoints.status_value()); |
| |
| auto coordinator_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Coordinator>(); |
| ASSERT_OK(coordinator_endpoints.status_value()); |
| |
| // Create an invalid string with invalid UTF-8 characters. |
| const char kInvalidStr[] = {static_cast<char>(0xC0), 0}; |
| auto str_val = fidl::StringView::FromExternal("ovenbird"); |
| fuchsia_device_manager::wire::DeviceStrProperty str_props[] = { |
| fuchsia_device_manager::wire::DeviceStrProperty{ |
| fidl::StringView::FromExternal(kInvalidStr, std::size(kInvalidStr)), |
| fuchsia_device_manager::wire::PropertyValue::WithStrValue( |
| fidl::ObjectView<fidl::StringView>::FromExternal(&str_val))}, |
| }; |
| |
| fbl::RefPtr<Device> device; |
| auto status = coordinator.device_manager()->AddDevice( |
| coordinator.sys_device(), std::move(controller_endpoints->client), |
| std::move(coordinator_endpoints->server), nullptr /* props */, 0 /* props_count */, str_props, |
| std::size(str_props), "mock-device", ZX_PROTOCOL_TEST, {} /* driver_path */, {} /* args */, |
| false /* skip_autobind */, false /* has_init */, true /* always_init */, |
| zx::vmo() /*inspect*/, zx::channel() /* client_remote */, |
| fidl::ClientEnd<fio::Directory>() /* outgoing_dir */, &device); |
| ASSERT_EQ(ZX_ERR_INVALID_ARGS, status); |
| } |
| |
| TEST(MiscTestCase, DeviceAlreadyBoundFromDriverIndex) { |
| constexpr const char kFakeDriverUrl[] = "#driver/mock-device.so"; |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| async::Loop index_loop(&kAsyncLoopConfigNeverAttachToThread); |
| ASSERT_OK(index_loop.StartThread("test-thread")); |
| InspectManager inspect_manager(loop.dispatcher()); |
| FakeDriverIndex fake(index_loop.dispatcher(), |
| [&](auto args) -> zx::status<FakeDriverIndex::MatchResult> { |
| return zx::ok(FakeDriverIndex::MatchResult{ |
| .url = kFakeDriverUrl, |
| }); |
| }); |
| auto config = NullConfig(); |
| config.driver_index = fidl::WireSharedClient<fdi::DriverIndex>(std::move(fake.Connect().value()), |
| loop.dispatcher()); |
| Coordinator coordinator(std::move(config), &inspect_manager, loop.dispatcher(), |
| loop.dispatcher()); |
| |
| ASSERT_NO_FATAL_FAILURE(InitializeCoordinator(&coordinator)); |
| |
| // Add the device. |
| auto controller_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::DeviceController>(); |
| ASSERT_OK(controller_endpoints.status_value()); |
| |
| auto coordinator_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Coordinator>(); |
| ASSERT_OK(coordinator_endpoints.status_value()); |
| |
| fbl::RefPtr<Device> device; |
| auto status = coordinator.device_manager()->AddDevice( |
| coordinator.sys_device(), std::move(controller_endpoints->client), |
| std::move(coordinator_endpoints->server), nullptr /* props_data */, 0 /* props_count */, |
| nullptr /* str_props_data */, 0 /* str_props_count */, "mock-device", ZX_PROTOCOL_TEST, |
| {} /* driver_path */, {} /* args */, true /* skip_autobind */, false /* has_init */, |
| true /* always_init */, zx::vmo() /*inspect*/, zx::channel() /* client_remote */, |
| fidl::ClientEnd<fio::Directory>() /*outgoing_dir*/, &device); |
| ASSERT_OK(status); |
| ASSERT_EQ(1, coordinator.device_manager()->devices().size_slow()); |
| |
| // Bind the device to a fake driver_host. |
| fbl::RefPtr<Device> dev = fbl::RefPtr(&coordinator.device_manager()->devices().front()); |
| auto host = fbl::MakeRefCounted<DriverHost>( |
| &coordinator, fidl::ClientEnd<fuchsia_device_manager::DriverHostController>(), |
| fidl::ClientEnd<fuchsia_io::Directory>(), zx::process{}); |
| dev->set_host(std::move(host)); |
| status = |
| coordinator.bind_driver_manager()->BindDevice(dev, kFakeDriverUrl, true /* new device */); |
| ASSERT_OK(status); |
| loop.RunUntilIdle(); |
| |
| status = |
| coordinator.bind_driver_manager()->BindDevice(dev, kFakeDriverUrl, true /* new device */); |
| ASSERT_STATUS(status, ZX_ERR_ALREADY_BOUND); |
| loop.RunUntilIdle(); |
| |
| // Reset the fake driver_host connection. |
| dev->set_host(nullptr); |
| coordinator_endpoints->client.reset(); |
| controller_endpoints->server.reset(); |
| loop.RunUntilIdle(); |
| } |
| |
| TEST(MiscTestCase, AddDeviceGroup) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| async::Loop index_loop(&kAsyncLoopConfigNeverAttachToThread); |
| ASSERT_OK(index_loop.StartThread("test-thread")); |
| |
| InspectManager inspect_manager(loop.dispatcher()); |
| FakeDriverIndex fake_driver_index(index_loop.dispatcher(), |
| [&](auto args) -> zx::status<FakeDriverIndex::MatchResult> { |
| return zx::error(ZX_ERR_NOT_FOUND); |
| }); |
| |
| auto config = NullConfig(); |
| config.driver_index = fidl::WireSharedClient<fdi::DriverIndex>( |
| std::move(fake_driver_index.Connect().value()), loop.dispatcher()); |
| |
| Coordinator coordinator(std::move(config), &inspect_manager, loop.dispatcher(), |
| loop.dispatcher()); |
| |
| ASSERT_NO_FATAL_FAILURE(InitializeCoordinator(&coordinator)); |
| |
| auto controller_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::DeviceController>(); |
| ASSERT_OK(controller_endpoints.status_value()); |
| |
| auto coordinator_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Coordinator>(); |
| ASSERT_OK(coordinator_endpoints.status_value()); |
| |
| // Add the device. |
| fbl::RefPtr<Device> device; |
| auto status = coordinator.device_manager()->AddDevice( |
| coordinator.sys_device(), std::move(controller_endpoints->client), |
| std::move(coordinator_endpoints->server), nullptr /* props_data */, 0 /* props_count */, |
| nullptr /* str_props_data */, 0 /* str_props_count */, "mock-device", ZX_PROTOCOL_TEST, |
| {} /* driver_path */, {} /* args */, true /* skip_autobind */, false /* has_init */, |
| true /* always_init */, zx::vmo() /*inspect*/, zx::channel() /* client_remote */, |
| fidl::ClientEnd<fio::Directory>() /*outgoing_dir*/, &device); |
| ASSERT_OK(status); |
| ASSERT_EQ(1, coordinator.device_manager()->devices().size_slow()); |
| |
| fidl::Arena allocator; |
| fidl::VectorView<fuchsia_device_manager::wire::DeviceStrProperty> str_props(allocator, 2); |
| str_props[0] = fuchsia_device_manager::wire::DeviceStrProperty{ |
| fidl::StringView(allocator, "scoter"), |
| fuchsia_device_manager::wire::PropertyValue::WithStrValue( |
| allocator, fidl::StringView(allocator, "bufflehead"))}; |
| str_props[1] = fuchsia_device_manager::wire::DeviceStrProperty{ |
| fidl::StringView(allocator, "merganser"), |
| fuchsia_device_manager::wire::PropertyValue::WithIntValue(1000)}; |
| |
| fidl::VectorView<fuchsia_device_manager::wire::DeviceProperty> props(allocator, 2); |
| props[0] = fuchsia_device_manager::wire::DeviceProperty{1, 0, 1}; |
| props[1] = fuchsia_device_manager::wire::DeviceProperty{2, 0, 1}; |
| |
| fidl::VectorView<fdf::wire::DeviceGroupProperty> node_properties(allocator, 2); |
| |
| auto prop_vals_1 = fidl::VectorView<fdf::wire::NodePropertyValue>(allocator, 1); |
| prop_vals_1[0] = fdf::wire::NodePropertyValue::WithBoolValue(false); |
| node_properties[0] = fdf::wire::DeviceGroupProperty{ |
| .key = fdf::wire::NodePropertyKey::WithIntValue(100), |
| .condition = fdf::wire::Condition::kAccept, |
| .values = prop_vals_1, |
| }; |
| |
| auto prop_vals_2 = fidl::VectorView<fdf::wire::NodePropertyValue>(allocator, 1); |
| prop_vals_2[0] = fdf::wire::NodePropertyValue::WithIntValue(20); |
| node_properties[1] = fdf::wire::DeviceGroupProperty{ |
| .key = fdf::wire::NodePropertyKey::WithIntValue(5), |
| .condition = fdf::wire::Condition::kAccept, |
| .values = prop_vals_2, |
| }; |
| |
| fidl::VectorView<fdf::wire::DeviceGroupNode> fragments(allocator, 1); |
| fragments[0] = fdf::wire::DeviceGroupNode{ |
| .name = fidl::StringView(allocator, "mallard"), |
| .properties = node_properties, |
| }; |
| |
| fidl::VectorView<fuchsia_device_manager::wire::DeviceMetadata> metadata(allocator, 0); |
| |
| fuchsia_device_manager::wire::DeviceGroupDescriptor group_desc = |
| fuchsia_device_manager::wire::DeviceGroupDescriptor{ |
| .props = props, |
| .str_props = str_props, |
| .fragments = fragments, |
| .spawn_colocated = false, |
| .metadata = metadata, |
| }; |
| |
| ASSERT_OK(coordinator.AddDeviceGroup(device, "group", group_desc)); |
| loop.RunUntilIdle(); |
| ZX_ASSERT( |
| coordinator.bind_driver_manager()->device_groups().count("/dev/sys/mock-device/group") != 0); |
| |
| controller_endpoints->server.reset(); |
| coordinator_endpoints->client.reset(); |
| loop.RunUntilIdle(); |
| } |
| |
| int main(int argc, char** argv) { return RUN_ALL_TESTS(argc, argv); } |