blob: 65af12600b035c748231bf325e17e5f1aede4d93 [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.
#include "passthrough.h"
#include <lib/async-loop/default.h>
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/driver/compat/cpp/device_server.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/testing/cpp/driver_lifecycle.h>
#include <lib/driver/testing/cpp/driver_runtime.h>
#include <lib/driver/testing/cpp/test_environment.h>
#include <lib/driver/testing/cpp/test_node.h>
#include <lib/fdf/env.h>
#include <lib/fdf/testing.h>
#include <gtest/gtest.h>
namespace {
class HciTransportServer : public fidl::WireServer<fuchsia_hardware_bluetooth::HciTransport> {
public:
fuchsia_hardware_bluetooth::HciService::InstanceHandler GetInstanceHandler() {
fuchsia_hardware_bluetooth::HciService::InstanceHandler handler;
zx::result result = handler.add_hci_transport(bindings_.CreateHandler(
this, fdf::Dispatcher::GetCurrent()->async_dispatcher(), fidl::kIgnoreBindingClosure));
ZX_ASSERT(result.is_ok());
return handler;
}
std::vector<std::vector<uint8_t>>& sent_command_packets() { return sent_command_packets_; }
private:
// WireServer<HciTransport> overrides:
void Send(::fuchsia_hardware_bluetooth::wire::SentPacket* request,
SendCompleter::Sync& completer) override {
if (request->is_command()) {
sent_command_packets_.emplace_back(request->command().begin(), request->command().end());
completer.Reply();
}
}
void AckReceive(AckReceiveCompleter::Sync& completer) override {}
void ConfigureSco(::fuchsia_hardware_bluetooth::wire::HciTransportConfigureScoRequest* request,
ConfigureScoCompleter::Sync& completer) override {}
void SetSnoop(::fuchsia_hardware_bluetooth::wire::HciTransportSetSnoopRequest* request,
SetSnoopCompleter::Sync& completer) override {}
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {}
std::vector<std::vector<uint8_t>> sent_command_packets_;
fidl::ServerBindingGroup<fuchsia_hardware_bluetooth::HciTransport> bindings_;
};
} // namespace
class PassthroughTest : public ::testing::Test {
public:
void SetUp() override {
node_server_.emplace("root");
zx::result start_args = node_server_->CreateStartArgsAndServe();
ASSERT_EQ(ZX_OK, start_args.status_value());
test_environment_.emplace();
zx::result result =
test_environment_->Initialize(std::move(start_args->incoming_directory_server));
ASSERT_EQ(ZX_OK, result.status_value());
auto hci_proto_handler = hci_server_.GetInstanceHandler();
zx::result add_service_result =
test_environment_->incoming_directory().AddService<fuchsia_hardware_bluetooth::HciService>(
std::move(hci_proto_handler));
ASSERT_EQ(ZX_OK, add_service_result.status_value());
zx::result start_result =
runtime_.RunToCompletion(driver_.Start(std::move(start_args->start_args)));
ASSERT_EQ(ZX_OK, start_result.status_value());
}
void TearDown() override {
zx::result prepare_stop_result = runtime_.RunToCompletion(driver_.PrepareStop());
EXPECT_EQ(ZX_OK, prepare_stop_result.status_value());
test_environment_.reset();
node_server_.reset();
runtime_.ShutdownAllDispatchers(fdf::Dispatcher::GetCurrent()->get());
}
fdf_testing::DriverUnderTest<bt::passthrough::PassthroughDevice>& driver() { return driver_; }
std::optional<fdf_testing::TestNode>& node_server() { return node_server_; }
async_dispatcher_t* dispatcher() { return fdf::Dispatcher::GetCurrent()->async_dispatcher(); }
HciTransportServer& hci_server() { return hci_server_; }
private:
// Attaches a foreground dispatcher for us automatically.
fdf_testing::DriverRuntime runtime_;
HciTransportServer hci_server_;
std::optional<fdf_testing::TestNode> node_server_;
std::optional<fdf_testing::TestEnvironment> test_environment_;
fdf_testing::DriverUnderTest<bt::passthrough::PassthroughDevice> driver_;
};
TEST_F(PassthroughTest, Lifecycle) {}
TEST_F(PassthroughTest, DevfsConnectAndSendCommand) {
zx::result<zx::channel> connect_result =
node_server()->children().at("bt-hci-passthrough").ConnectToDevice();
ASSERT_TRUE(connect_result.is_ok());
fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> client_end(std::move(connect_result.value()));
fidl::WireClient<fuchsia_hardware_bluetooth::Vendor> client(std::move(client_end), dispatcher());
std::optional<fidl::ClientEnd<fuchsia_hardware_bluetooth::HciTransport>> hci_client_end;
client->OpenHciTransport().Then(
[&](fidl::WireUnownedResult<fuchsia_hardware_bluetooth::Vendor::OpenHciTransport>& result) {
ASSERT_TRUE(result->is_ok());
hci_client_end = std::move(result->value()->channel);
});
fdf_testing_run_until_idle();
ASSERT_TRUE(hci_client_end);
fidl::WireClient<fuchsia_hardware_bluetooth::HciTransport> hci_client(std::move(*hci_client_end),
dispatcher());
bool responded = false;
uint8_t arr[1] = {3};
fidl::VectorView vec_view = fidl::VectorView<uint8_t>::FromExternal(arr);
fidl::ObjectView object_view =
fidl::ObjectView<fidl::VectorView<uint8_t>>::FromExternal(&vec_view);
hci_client->Send(::fuchsia_hardware_bluetooth::wire::SentPacket::WithCommand(object_view))
.Then([&](fidl::WireUnownedResult<fuchsia_hardware_bluetooth::HciTransport::Send>& result) {
responded = true;
});
fdf_testing_run_until_idle();
ASSERT_TRUE(responded);
ASSERT_EQ(hci_server().sent_command_packets().size(), 1u);
EXPECT_EQ(hci_server().sent_command_packets()[0][0], arr[0]);
auto endpoint = hci_client.UnbindMaybeGetEndpoint();
}