diff options
Diffstat (limited to 'gd/hci/le_advertising_manager_test.cc')
-rw-r--r-- | gd/hci/le_advertising_manager_test.cc | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/gd/hci/le_advertising_manager_test.cc b/gd/hci/le_advertising_manager_test.cc new file mode 100644 index 000000000..c4f40ad22 --- /dev/null +++ b/gd/hci/le_advertising_manager_test.cc @@ -0,0 +1,356 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/le_advertising_manager.h" + +#include <algorithm> +#include <chrono> +#include <future> +#include <map> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "common/bind.h" +#include "hci/address.h" +#include "hci/controller.h" +#include "hci/hci_layer.h" +#include "os/thread.h" +#include "packet/raw_builder.h" + +namespace bluetooth { +namespace hci { +namespace { + +using packet::kLittleEndian; +using packet::PacketView; +using packet::RawBuilder; + +PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) { + auto bytes = std::make_shared<std::vector<uint8_t>>(); + BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + return packet::PacketView<packet::kLittleEndian>(bytes); +} + +class TestController : public Controller { + public: + bool IsSupported(OpCode op_code) const override { + return supported_opcodes_.count(op_code) == 1; + } + + void AddSupported(OpCode op_code) { + supported_opcodes_.insert(op_code); + } + + uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const override { + return num_advertisers; + } + + uint16_t num_advertisers{0}; + + protected: + void Start() override {} + void Stop() override {} + void ListDependencies(ModuleList* list) override {} + + private: + std::set<OpCode> supported_opcodes_{}; +}; + +class TestHciLayer : public HciLayer { + public: + TestHciLayer() { + RegisterEventHandler(EventCode::COMMAND_COMPLETE, + base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr); + RegisterEventHandler(EventCode::COMMAND_STATUS, + base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr); + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override { + command_queue_.push_back(std::move(command)); + command_status_callbacks.push_back(std::move(on_status)); + if (command_promise_ != nullptr) { + command_promise_->set_value(command_queue_.size()); + command_promise_.reset(); + } + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override { + command_queue_.push_back(std::move(command)); + command_complete_callbacks.push_back(std::move(on_complete)); + if (command_promise_ != nullptr) { + command_promise_->set_value(command_queue_.size()); + command_promise_.reset(); + } + } + + std::future<size_t> GetCommandFuture() { + ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); + command_promise_ = std::make_unique<std::promise<size_t>>(); + return command_promise_->get_future(); + } + + std::unique_ptr<CommandPacketBuilder> GetLastCommand() { + ASSERT(!command_queue_.empty()); + auto last = std::move(command_queue_.front()); + command_queue_.pop_front(); + return last; + } + + ConnectionManagementCommandView GetCommandPacket(OpCode op_code) { + auto packet_view = GetPacketView(GetLastCommand()); + CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); + ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); + ASSERT(command.IsValid()); + EXPECT_EQ(command.GetOpCode(), op_code); + + return command; + } + + void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler, + os::Handler* handler) override { + registered_events_[event_code] = event_handler; + } + + void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler, + os::Handler* handler) override { + registered_le_events_[subevent_code] = event_handler; + } + + void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + ASSERT_TRUE(event.IsValid()); + EventCode event_code = event.GetEventCode(); + ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code); + registered_events_[event_code].Run(event); + } + + void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + LeMetaEventView meta_event_view = LeMetaEventView::Create(event); + ASSERT_TRUE(meta_event_view.IsValid()); + SubeventCode subevent_code = meta_event_view.GetSubeventCode(); + ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end()) + << SubeventCodeText(subevent_code); + registered_le_events_[subevent_code].Run(meta_event_view); + } + + void CommandCompleteCallback(EventPacketView event) { + CommandCompleteView complete_view = CommandCompleteView::Create(event); + ASSERT(complete_view.IsValid()); + std::move(command_complete_callbacks.front()).Run(complete_view); + command_complete_callbacks.pop_front(); + } + + void CommandStatusCallback(EventPacketView event) { + CommandStatusView status_view = CommandStatusView::Create(event); + ASSERT(status_view.IsValid()); + std::move(command_status_callbacks.front()).Run(status_view); + command_status_callbacks.pop_front(); + } + + void ListDependencies(ModuleList* list) override {} + void Start() override {} + void Stop() override {} + + private: + std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_; + std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_; + std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks; + std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks; + + std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_; + mutable std::mutex mutex_; + std::unique_ptr<std::promise<size_t>> command_promise_{}; +}; + +class LeAdvertisingManagerTest : public ::testing::Test { + protected: + void SetUp() override { + test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry + test_controller_ = new TestController; + test_controller_->AddSupported(param_opcode_); + fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); + fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); + client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); + ASSERT_NE(client_handler_, nullptr); + test_controller_->num_advertisers = 1; + fake_registry_.Start<LeAdvertisingManager>(&thread_); + le_advertising_manager_ = + static_cast<LeAdvertisingManager*>(fake_registry_.GetModuleUnderTest(&LeAdvertisingManager::Factory)); + } + + void TearDown() override { + fake_registry_.SynchronizeModuleHandler(&LeAdvertisingManager::Factory, std::chrono::milliseconds(20)); + fake_registry_.StopAll(); + } + + TestModuleRegistry fake_registry_; + TestHciLayer* test_hci_layer_ = nullptr; + TestController* test_controller_ = nullptr; + os::Thread& thread_ = fake_registry_.GetTestThread(); + LeAdvertisingManager* le_advertising_manager_ = nullptr; + os::Handler* client_handler_ = nullptr; + + const common::Callback<void(Address, AddressType)> scan_callback = + common::Bind(&LeAdvertisingManagerTest::on_scan, common::Unretained(this)); + const common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback = + common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this)); + + std::future<Address> GetOnScanPromise() { + ASSERT_LOG(address_promise_ == nullptr, "Promises promises ... Only one at a time"); + address_promise_ = std::make_unique<std::promise<Address>>(); + return address_promise_->get_future(); + } + void on_scan(Address address, AddressType address_type) { + if (address_promise_ == nullptr) { + return; + } + address_promise_->set_value(address); + address_promise_.reset(); + } + + std::future<ErrorCode> GetSetTerminatedPromise() { + ASSERT_LOG(set_terminated_promise_ == nullptr, "Promises promises ... Only one at a time"); + set_terminated_promise_ = std::make_unique<std::promise<ErrorCode>>(); + return set_terminated_promise_->get_future(); + } + void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) { + if (set_terminated_promise_ != nullptr) { + return; + } + set_terminated_promise_->set_value(error_code); + set_terminated_promise_.reset(); + } + + std::unique_ptr<std::promise<Address>> address_promise_{}; + std::unique_ptr<std::promise<ErrorCode>> set_terminated_promise_{}; + + OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS}; +}; + +class LeAndroidHciAdvertisingManagerTest : public LeAdvertisingManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_MULTI_ADVT; + LeAdvertisingManagerTest::SetUp(); + test_controller_->num_advertisers = 3; + } +}; + +class LeExtendedAdvertisingManagerTest : public LeAdvertisingManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS; + LeAdvertisingManagerTest::SetUp(); + test_controller_->num_advertisers = 5; + } +}; + +TEST_F(LeAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeAndroidHciAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeExtendedAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { + AdvertisingConfig advertising_config{}; + advertising_config.event_type = AdvertisingEventType::ADV_IND; + advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + + auto next_command_future = test_hci_layer_->GetCommandFuture(); + auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, + client_handler_); + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + std::vector<OpCode> adv_opcodes = { + OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS, OpCode::LE_SET_SCAN_RESPONSE_DATA, + OpCode::LE_SET_ADVERTISING_DATA, OpCode::LE_SET_ADVERTISING_ENABLE, + }; + auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + size_t num_commands = next_command_future.get(); + for (size_t i = 0; i < adv_opcodes.size(); i++) { + auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); + std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; + test_hci_layer_->IncomingEvent( + CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); + if (i < adv_opcodes.size() - 1 && --num_commands == 1) { + next_command_future = test_hci_layer_->GetCommandFuture(); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + num_commands = next_command_future.get(); + } + } +} + +TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { + AdvertisingConfig advertising_config{}; + advertising_config.event_type = AdvertisingEventType::ADV_IND; + advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + + auto next_command_future = test_hci_layer_->GetCommandFuture(); + auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, + client_handler_); + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + std::vector<SubOcf> sub_ocf = { + SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE, + }; + auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + size_t num_commands = next_command_future.get(); + for (size_t i = 0; i < sub_ocf.size(); i++) { + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT); + std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])}; + test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT, + std::make_unique<RawBuilder>(success_vector))); + if (i < sub_ocf.size() - 1 && --num_commands == 1) { + next_command_future = test_hci_layer_->GetCommandFuture(); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + num_commands = next_command_future.get(); + } + } +} + +} // namespace +} // namespace hci +} // namespace bluetooth |