| // 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 "action-list.h" |
| |
| #include <gtest/gtest.h> |
| |
| #include "mock-device-thread.h" |
| #include "mock-device.h" |
| |
| namespace libdriver_integration_test { |
| |
| ActionList::ActionList() = default; |
| ActionList::~ActionList() = default; |
| |
| void ActionList::AppendAction(Action action) { actions_.push_back(std::move(action)); } |
| |
| void ActionList::AppendAddMockDevice(async_dispatcher_t* dispatcher, const std::string& parent_path, |
| std::string name, std::vector<zx_device_prop_t> props, |
| zx_status_t expect_status, |
| std::unique_ptr<MockDevice>* new_device_out, |
| fpromise::promise<void, std::string>* add_done_out) { |
| fpromise::bridge<void, std::string> bridge; |
| AppendAddMockDevice(dispatcher, parent_path, std::move(name), std::move(props), expect_status, |
| std::move(bridge.completer), new_device_out); |
| *add_done_out = bridge.consumer.promise_or(::fpromise::error("add device abandoned")).box(); |
| } |
| |
| void ActionList::AppendAddMockDevice(async_dispatcher_t* dispatcher, const std::string& parent_path, |
| std::string name, std::vector<zx_device_prop_t> props, |
| zx_status_t expect_status, |
| fpromise::completer<void, std::string> add_done, |
| std::unique_ptr<MockDevice>* new_device_out) { |
| fidl::InterfaceHandle<fuchsia::device::mock::MockDevice> client; |
| fidl::InterfaceRequest<fuchsia::device::mock::MockDevice> server(client.NewRequest()); |
| if (!server.is_valid()) { |
| EXPECT_TRUE(server.is_valid()); |
| return; |
| } |
| |
| std::string path(parent_path + "/" + name); |
| *new_device_out = std::make_unique<MockDevice>(std::move(server), dispatcher, std::move(path)); |
| |
| fuchsia::device::mock::Action action; |
| auto& add_device = action.add_device(); |
| add_device.do_bind = false; |
| add_device.controller = std::move(client); |
| add_device.name = std::move(name); |
| add_device.expect_status = expect_status; |
| |
| static_assert(sizeof(uint64_t) == sizeof(props[0])); |
| for (zx_device_prop_t prop : props) { |
| add_device.properties.push_back(*reinterpret_cast<uint64_t*>(&prop)); |
| } |
| |
| add_device.action_id = next_action_id_++; |
| |
| local_action_map_[add_device.action_id] = std::move(add_done); |
| return AppendAction(std::move(action)); |
| } |
| |
| void ActionList::AppendUnbindReply(fpromise::promise<void, std::string>* unbind_reply_done_out) { |
| fpromise::bridge<void, std::string> bridge; |
| AppendUnbindReply(std::move(bridge.completer)); |
| *unbind_reply_done_out = |
| bridge.consumer.promise_or(::fpromise::error("unbind reply abandoned")).box(); |
| } |
| |
| void ActionList::AppendUnbindReply(fpromise::completer<void, std::string> unbind_reply_done) { |
| Action action; |
| auto& unbind_reply = action.unbind_reply(); |
| unbind_reply.action_id = next_action_id_++; |
| |
| fpromise::bridge<void, std::string> bridge; |
| local_action_map_[unbind_reply.action_id] = std::move(unbind_reply_done); |
| return AppendAction(std::move(action)); |
| } |
| |
| void ActionList::AppendAsyncRemoveDevice() { |
| Action action; |
| action.set_async_remove_device(true); |
| return AppendAction(std::move(action)); |
| } |
| |
| void ActionList::AppendCreateThread(async_dispatcher_t* dispatcher, |
| std::unique_ptr<MockDeviceThread>* out) { |
| fidl::InterfacePtr<MockDeviceThread::Interface> interface; |
| Action action; |
| action.set_create_thread(interface.NewRequest(dispatcher)); |
| AppendAction(std::move(action)); |
| *out = std::make_unique<MockDeviceThread>(std::move(interface)); |
| } |
| |
| void ActionList::AppendReturnStatus(zx_status_t status) { |
| Action action; |
| action.set_return_status(status); |
| return AppendAction(std::move(action)); |
| } |
| |
| // Consume this action list, updating the given |map| and action counter. |
| std::vector<ActionList::Action> ActionList::FinalizeActionList(CompleterMap* map, |
| uint64_t* next_action_id) { |
| CompleterMap local_ids; |
| for (auto& action : actions_) { |
| uint64_t* action_id = nullptr; |
| if (action.is_add_device()) { |
| action_id = &action.add_device().action_id; |
| } else if (action.is_unbind_reply()) { |
| action_id = &action.unbind_reply().action_id; |
| } else { |
| continue; |
| } |
| uint64_t local_action_id = *action_id; |
| auto itr = local_action_map_.find(local_action_id); |
| ZX_ASSERT(itr != local_action_map_.end()); |
| uint64_t remote_action_id = (*next_action_id)++; |
| (*map)[remote_action_id] = std::move(itr->second); |
| local_action_map_.erase(itr); |
| *action_id = remote_action_id; |
| } |
| return std::move(actions_); |
| } |
| |
| } // namespace libdriver_integration_test |