Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98c3f597 authored by Rahul Arya's avatar Rahul Arya
Browse files

Move TestHciLayer into a separate file

Previously we were copy/pasting it everywhere. Not only was this huge code
duplication, it also violated ODR since we were not always correctly namespacing
it. This CL wraps all its copies inside an anonymous namespace, and also exposes
it in bluetooth::hci in a separate file.

Test: all existing
Bug: 247839849

Change-Id: Icff2eafa5f74baae8d8f1af79395b9359ce9e19f
parent 735aeb1e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ filegroup {
        "class_of_device_unittest.cc",
        "controller_test.cc",
        "controller_unittest.cc",
        "hci_layer_fake.cc",
        "hci_layer_test.cc",
        "hci_layer_unittest.cc",
        "hci_packets_test.cc",
+3 −0
Original line number Diff line number Diff line
@@ -162,6 +162,8 @@ namespace bluetooth {
namespace hci {
namespace acl_manager {

namespace {

PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
  auto bytes = std::make_shared<std::vector<uint8_t>>();
  BitInserter i(*bytes);
@@ -381,6 +383,7 @@ class TestHciLayer : public HciLayer {
  std::unique_ptr<std::future<void>> command_future_;
  CommandInterfaceImpl<AclCommandBuilder> le_acl_connection_manager_interface_{*this};
};
}  // namespace

class MockLeConnectionCallbacks : public LeConnectionCallbacks {
 public:
+17 −10
Original line number Diff line number Diff line
@@ -64,13 +64,15 @@ PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilde

}  // namespace

namespace {

class TestHciLayer : public HciLayer {
 public:
  void EnqueueCommand(
      std::unique_ptr<CommandBuilder> command,
      common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
    GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleCommand, common::Unretained(this), std::move(command),
                                        std::move(on_complete)));
    GetHandler()->Post(common::BindOnce(
        &TestHciLayer::HandleCommand, common::Unretained(this), std::move(command), std::move(on_complete)));
  }

  void EnqueueCommand(
@@ -100,8 +102,8 @@ class TestHciLayer : public HciLayer {
        local_version_information.lmp_version_ = LmpVersion::V_4_2;
        local_version_information.manufacturer_name_ = 0xBAD;
        local_version_information.lmp_subversion_ = 0x5678;
        event_builder = ReadLocalVersionInformationCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
                                                                           local_version_information);
        event_builder = ReadLocalVersionInformationCompleteBuilder::Create(
            num_packets, ErrorCode::SUCCESS, local_version_information);
      } break;
      case (OpCode::READ_LOCAL_SUPPORTED_COMMANDS): {
        std::array<uint8_t, 64> supported_commands;
@@ -120,13 +122,17 @@ class TestHciLayer : public HciLayer {
        uint8_t page_bumber = read_command.GetPageNumber();
        uint64_t lmp_features = 0x012345678abcdef;
        lmp_features += page_bumber;
        event_builder = ReadLocalExtendedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, page_bumber,
                                                                         0x02, lmp_features);
        event_builder = ReadLocalExtendedFeaturesCompleteBuilder::Create(
            num_packets, ErrorCode::SUCCESS, page_bumber, 0x02, lmp_features);
      } break;
      case (OpCode::READ_BUFFER_SIZE): {
        event_builder = ReadBufferSizeCompleteBuilder::Create(
            num_packets, ErrorCode::SUCCESS, acl_data_packet_length, synchronous_data_packet_length,
            total_num_acl_data_packets, total_num_synchronous_data_packets);
            num_packets,
            ErrorCode::SUCCESS,
            acl_data_packet_length,
            synchronous_data_packet_length,
            total_num_acl_data_packets,
            total_num_synchronous_data_packets);
      } break;
      case (OpCode::READ_BD_ADDR): {
        event_builder = ReadBdAddrCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, Address::kAny);
@@ -178,8 +184,8 @@ class TestHciLayer : public HciLayer {
          payload->AddOctets2(feature_spec_version);
          payload->AddOctets(payload_bytes);
        }
        event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
                                                                       base_vendor_capabilities, std::move(payload));
        event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create(
            num_packets, ErrorCode::SUCCESS, base_vendor_capabilities, std::move(payload));
      } break;
      case (OpCode::SET_EVENT_MASK): {
        auto view = SetEventMaskView::Create(command);
@@ -303,6 +309,7 @@ class ControllerTest : public ::testing::Test {
  os::Handler* client_handler_ = nullptr;
  uint16_t feature_spec_version_ = 98;
};
}  // namespace

class Controller055Test : public ControllerTest {
 protected:
+160 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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/hci_layer_fake.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <algorithm>
#include <chrono>

namespace bluetooth {
namespace hci {

using packet::kLittleEndian;
using packet::PacketView;
using packet::RawBuilder;

PacketView<packet::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);
}

void TestHciLayer::EnqueueCommand(
    std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) {
  std::lock_guard<std::mutex> lock(mutex_);
  command_queue_.push(std::move(command));
  command_status_callbacks.push_back(std::move(on_status));
  command_count_--;
  if (command_promise_ != nullptr && command_count_ == 0) {
    command_promise_->set_value();
    command_promise_.reset();
  }
}

void TestHciLayer::EnqueueCommand(
    std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) {
  std::lock_guard<std::mutex> lock(mutex_);
  command_queue_.push(std::move(command));
  command_complete_callbacks.push_back(std::move(on_complete));
  command_count_--;
  if (command_promise_ != nullptr && command_count_ == 0) {
    command_promise_->set_value();
    command_promise_.reset();
  }
}

void TestHciLayer::SetCommandFuture(uint16_t num_command) {
  ASSERT_TRUE(command_promise_ == nullptr) << "Promises, Promises, ... Only one at a time.";
  command_count_ = num_command;
  command_promise_ = std::make_unique<std::promise<void>>();
  command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
}

CommandView TestHciLayer::GetCommand() {
  // Wait for EnqueueCommand if command_queue_ is empty
  if (command_queue_.empty() && command_future_ != nullptr) {
    command_future_->wait_for(std::chrono::milliseconds(1000));
  }

  std::lock_guard<std::mutex> lock(mutex_);
  if (command_queue_.empty()) {
    LOG_ERROR("Command queue is empty");
    return empty_command_view_;
  }

  auto last = std::move(command_queue_.front());
  command_queue_.pop();
  CommandView command_packet_view = CommandView::Create(GetPacketView(std::move(last)));
  if (!command_packet_view.IsValid()) {
    LOG_ERROR("Got invalid command");
    return empty_command_view_;
  }
  return command_packet_view;
}

void TestHciLayer::RegisterEventHandler(
    EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) {
  registered_events_[event_code] = event_handler;
}

void TestHciLayer::UnregisterEventHandler(EventCode event_code) {
  registered_events_.erase(event_code);
}

void TestHciLayer::RegisterLeEventHandler(
    SubeventCode subevent_code, common::ContextualCallback<void(LeMetaEventView)> event_handler) {
  registered_le_events_[subevent_code] = event_handler;
}

void TestHciLayer::UnregisterLeEventHandler(SubeventCode subevent_code) {
  registered_le_events_.erase(subevent_code);
}

void TestHciLayer::IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
  auto packet = GetPacketView(std::move(event_builder));
  EventView event = EventView::Create(packet);
  ASSERT_TRUE(event.IsValid());
  EventCode event_code = event.GetEventCode();
  ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
  registered_events_[event_code].Invoke(event);
}

void TestHciLayer::IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
  auto packet = GetPacketView(std::move(event_builder));
  EventView event = EventView::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());
  registered_le_events_[subevent_code].Invoke(meta_event_view);
}

void TestHciLayer::CommandCompleteCallback(EventView event) {
  CommandCompleteView complete_view = CommandCompleteView::Create(event);
  ASSERT_TRUE(complete_view.IsValid());
  std::move(command_complete_callbacks.front()).Invoke(complete_view);
  command_complete_callbacks.pop_front();
}

void TestHciLayer::CommandStatusCallback(EventView event) {
  CommandStatusView status_view = CommandStatusView::Create(event);
  ASSERT_TRUE(status_view.IsValid());
  std::move(command_status_callbacks.front()).Invoke(status_view);
  command_status_callbacks.pop_front();
}

void TestHciLayer::InitEmptyCommand() {
  auto payload = std::make_unique<bluetooth::packet::RawBuilder>();
  auto command_builder = CommandBuilder::Create(OpCode::NONE, std::move(payload));
  empty_command_view_ = CommandView::Create(GetPacketView(std::move(command_builder)));
  ASSERT_TRUE(empty_command_view_.IsValid());
}

void TestHciLayer::ListDependencies(ModuleList* list) const {}
void TestHciLayer::Start() {
  InitEmptyCommand();
  RegisterEventHandler(EventCode::COMMAND_COMPLETE, GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
  RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
}
void TestHciLayer::Stop() {}

}  // namespace hci
}  // namespace bluetooth
 No newline at end of file
+87 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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 <future>
#include <map>

#include "common/bind.h"
#include "hci/address.h"
#include "hci/hci_layer.h"
#include "packet/raw_builder.h"

namespace bluetooth {
namespace hci {

using packet::kLittleEndian;
using packet::PacketView;

PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet);

class TestHciLayer : public HciLayer {
 public:
  void EnqueueCommand(
      std::unique_ptr<CommandBuilder> command,
      common::ContextualOnceCallback<void(CommandStatusView)> on_status) override;

  void EnqueueCommand(
      std::unique_ptr<CommandBuilder> command,
      common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override;

  // Set command future for 'num_command' commands are expected
  void SetCommandFuture(uint16_t num_command);

  CommandView GetCommand();

  void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override;

  void UnregisterEventHandler(EventCode event_code) override;

  void RegisterLeEventHandler(
      SubeventCode subevent_code, common::ContextualCallback<void(LeMetaEventView)> event_handler) override;

  void UnregisterLeEventHandler(SubeventCode subevent_code) override;

  void IncomingEvent(std::unique_ptr<EventBuilder> event_builder);

  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder);

  void CommandCompleteCallback(EventView event);

  void CommandStatusCallback(EventView event);

  void InitEmptyCommand();

 protected:
  void ListDependencies(ModuleList* list) const override;
  void Start() override;
  void Stop() override;

 private:
  std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
  std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
  std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
  std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
  std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
  std::unique_ptr<std::promise<void>> command_promise_;
  std::unique_ptr<std::future<void>> command_future_;
  mutable std::mutex mutex_;
  uint16_t command_count_ = 0;
  CommandView empty_command_view_ =
      CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
};

}  // namespace hci
}  // namespace bluetooth
 No newline at end of file
Loading