blob: 379d8d84fffdcbbae86f6142e252e600469c52d0 [file] [log] [blame]
// 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.h"
#include "mock-device-thread.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,
fit::promise<void, std::string>* add_done_out) {
fit::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(::fit::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,
fit::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(fit::promise<void, std::string>* unbind_reply_done_out) {
fit::bridge<void, std::string> bridge;
AppendUnbindReply(std::move(bridge.completer));
*unbind_reply_done_out =
bridge.consumer.promise_or(::fit::error("unbind reply abandoned")).box();
}
void ActionList::AppendUnbindReply(fit::completer<void, std::string> unbind_reply_done) {
Action action;
auto& unbind_reply = action.unbind_reply();
unbind_reply.action_id = next_action_id_++;
fit::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