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

Commit 5c1e977b authored by Chris Manton's avatar Chris Manton
Browse files

shim: Add acl tests

Bug: 184604254
Test: gd/cert/run
Tag: #refactor
BYPASS_LONG_LINES_REASON: Bluetooth likes 120 lines

Change-Id: Ic589759cec3190e99f0a1659985740f415569ab2
parent 263c5e8b
Loading
Loading
Loading
Loading
+255 −32
Original line number Diff line number Diff line
@@ -16,20 +16,35 @@

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <condition_variable>
#include <map>
#include <thread>

#include "device/include/controller.h"
#include "gd/btaa/activity_attribution.h"
#include "gd/hal/hci_hal.h"
#include "gd/hci/acl_manager_mock.h"
#include "gd/hci/controller_mock.h"
#include "gd/module.h"
#include "gd/os/mock_queue.h"
#include "gd/os/queue.h"
#include "gd/packet/packet_view.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager/classic_acl_connection.h"
#include "hci/acl_manager/connection_callbacks.h"
#include "hci/acl_manager/connection_management_callbacks.h"
#include "hci/acl_manager/le_acl_connection.h"
#include "hci/acl_manager/le_connection_callbacks.h"
#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/include/hci_layer.h"
#include "hci/include/hci_packet_factory.h"
#include "hci/include/hci_packet_parser.h"
#include "hci/include/packet_fragmenter.h"
#include "include/hardware/bt_activity_attribution.h"
#include "main/shim/acl.h"
#include "main/shim/acl_legacy_interface.h"
#include "main/test/common/main_handler.h"
#include "main/test/common/mock_entry.h"
#include "os/handler.h"
#include "os/thread.h"
#include "stack/btm/btm_int_types.h"
@@ -39,11 +54,116 @@
using namespace bluetooth;
using namespace testing;

std::map<std::string, int> mock_function_count_map;
namespace test = bluetooth::hci::testing;

const uint8_t kMaxLeAcceptlistSize = 16;
std::map<std::string, int> mock_function_count_map;
tL2C_CB l2cb;
tBTM_CB btm_cb;

namespace {
std::map<std::string, std::promise<uint16_t>> mock_function_handle_promise_map;
}

uint8_t mock_get_ble_acceptlist_size() { return 123; }

struct controller_t mock_controller {
  .get_ble_acceptlist_size = mock_get_ble_acceptlist_size,
};

const controller_t* controller_get_interface() { return &mock_controller; }

void mock_on_send_data_upwards(BT_HDR*) { mock_function_count_map[__func__]++; }

void mock_on_packets_completed(uint16_t handle, uint16_t num_packets) {
  mock_function_count_map[__func__]++;
}

void mock_connection_classic_on_connected(const RawAddress& bda,
                                          uint16_t handle, uint8_t enc_mode) {
  mock_function_count_map[__func__]++;
}

void mock_connection_classic_on_failed(const RawAddress& bda,
                                       tHCI_STATUS status) {
  mock_function_count_map[__func__]++;
}

void mock_connection_classic_on_disconnected(tHCI_STATUS status,
                                             uint16_t handle,
                                             tHCI_STATUS reason) {
  mock_function_count_map[__func__]++;
  ASSERT_TRUE(mock_function_handle_promise_map.find(__func__) !=
              mock_function_handle_promise_map.end());
  mock_function_handle_promise_map[__func__].set_value(handle);
}
void mock_connection_le_on_connected(
    const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role,
    uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout,
    const RawAddress& local_rpa, const RawAddress& peer_rpa,
    uint8_t peer_addr_type) {
  mock_function_count_map[__func__]++;
}
void mock_connection_le_on_failed(const tBLE_BD_ADDR& address_with_type,
                                  uint16_t handle, bool enhanced,
                                  tHCI_STATUS status) {
  mock_function_count_map[__func__]++;
}
void mock_connection_le_on_disconnected(tHCI_STATUS status, uint16_t handle,
                                        tHCI_STATUS reason) {
  mock_function_count_map[__func__]++;
}

const shim::legacy::acl_interface_t GetMockAclInterface() {
  shim::legacy::acl_interface_t acl_interface{
      .on_send_data_upwards = mock_on_send_data_upwards,
      .on_packets_completed = mock_on_packets_completed,

      .connection.classic.on_connected = mock_connection_classic_on_connected,
      .connection.classic.on_failed = mock_connection_classic_on_failed,
      .connection.classic.on_disconnected =
          mock_connection_classic_on_disconnected,

      .connection.le.on_connected = mock_connection_le_on_connected,
      .connection.le.on_failed = mock_connection_le_on_failed,
      .connection.le.on_disconnected = mock_connection_le_on_disconnected,

      .connection.sco.on_esco_connect_request = nullptr,
      .connection.sco.on_sco_connect_request = nullptr,
      .connection.sco.on_disconnected = nullptr,

      .link.classic.on_authentication_complete = nullptr,
      .link.classic.on_central_link_key_complete = nullptr,
      .link.classic.on_change_connection_link_key_complete = nullptr,
      .link.classic.on_encryption_change = nullptr,
      .link.classic.on_flow_specification_complete = nullptr,
      .link.classic.on_flush_occurred = nullptr,
      .link.classic.on_mode_change = nullptr,
      .link.classic.on_packet_type_changed = nullptr,
      .link.classic.on_qos_setup_complete = nullptr,
      .link.classic.on_read_afh_channel_map_complete = nullptr,
      .link.classic.on_read_automatic_flush_timeout_complete = nullptr,
      .link.classic.on_sniff_subrating = nullptr,
      .link.classic.on_read_clock_complete = nullptr,
      .link.classic.on_read_clock_offset_complete = nullptr,
      .link.classic.on_read_failed_contact_counter_complete = nullptr,
      .link.classic.on_read_link_policy_settings_complete = nullptr,
      .link.classic.on_read_link_quality_complete = nullptr,
      .link.classic.on_read_link_supervision_timeout_complete = nullptr,
      .link.classic.on_read_remote_version_information_complete = nullptr,
      .link.classic.on_read_remote_extended_features_complete = nullptr,
      .link.classic.on_read_rssi_complete = nullptr,
      .link.classic.on_read_transmit_power_level_complete = nullptr,
      .link.classic.on_role_change = nullptr,
      .link.classic.on_role_discovery_complete = nullptr,

      .link.le.on_connection_update = nullptr,
      .link.le.on_data_length_change = nullptr,
      .link.le.on_read_remote_version_information_complete = nullptr,
  };
  return acl_interface;
}

const hci_packet_factory_t* hci_packet_factory_get_interface() {
  return nullptr;
}
@@ -52,24 +172,78 @@ const hci_t* hci_layer_get_interface() { return nullptr; }
const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}

template <typename T>
class MockEnQueue : public os::IQueueEnqueue<T> {
  using EnqueueCallback = base::Callback<std::unique_ptr<T>()>;

  void RegisterEnqueue(os::Handler* handler,
                       EnqueueCallback callback) override {}
  void UnregisterEnqueue() override {}
};

template <typename T>
class MockDeQueue : public os::IQueueDequeue<T> {
  using DequeueCallback = base::Callback<void()>;

  void RegisterDequeue(os::Handler* handler,
                       DequeueCallback callback) override {}
  void UnregisterDequeue() override {}
  std::unique_ptr<T> TryDequeue() override { return nullptr; }
};

class MockClassicAclConnection
    : public bluetooth::hci::acl_manager::ClassicAclConnection {
 public:
  MockClassicAclConnection(const hci::Address& address, uint16_t handle) {
    address_ = address;  // ClassicAclConnection
    handle_ = handle;    // AclConnection
  }

  void RegisterCallbacks(
      hci::acl_manager::ConnectionManagementCallbacks* callbacks,
      os::Handler* handler) override {
    callbacks_ = callbacks;
    handler_ = handler;
  }

  // Returns the bidi queue for this mock connection
  AclConnection::QueueUpEnd* GetAclQueueEnd() const override {
    return &mock_acl_queue_;
  }

  mutable common::BidiQueueEnd<hci::BasePacketBuilder,
                               packet::PacketView<hci::kLittleEndian>>
      mock_acl_queue_{&tx_, &rx_};

  MockEnQueue<hci::BasePacketBuilder> tx_;
  MockDeQueue<packet::PacketView<hci::kLittleEndian>> rx_;

  bool ReadRemoteVersionInformation() override { return true; }
  bool ReadRemoteSupportedFeatures() override { return true; }

  bool Disconnect(hci::DisconnectReason reason) override {
    disconnect_cnt_++;
    disconnect_promise_.set_value(handle_);
    return true;
  }

  std::promise<uint16_t> disconnect_promise_;

  hci::acl_manager::ConnectionManagementCallbacks* callbacks_{nullptr};
  os::Handler* handler_{nullptr};

  int disconnect_cnt_{0};
};

namespace bluetooth {
namespace shim {
void init_activity_attribution() {}

namespace testing {
extern os::Handler* mock_handler_;
}  // namespace testing

}  // namespace shim

namespace hci {
namespace testing {

extern MockController* mock_controller_;
extern MockAclManager* mock_acl_manager_;

}  // namespace testing
}  // namespace hci
}  // namespace shim

namespace activity_attribution {
ActivityAttributionInterface* get_activity_attribution_instance() {
@@ -90,41 +264,90 @@ class MainShimTest : public testing::Test {
 public:
 protected:
  void SetUp() override {
    thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
    main_thread_start_up();

    thread_ = new os::Thread("acl_thread", os::Thread::Priority::NORMAL);
    handler_ = new os::Handler(thread_);

    hci::testing::mock_acl_manager_ = new hci::testing::MockAclManager();
    hci::testing::mock_controller_ = new hci::testing::MockController();
    /* extern */ test::mock_controller_ =
        new bluetooth::hci::testing::MockController();
    /* extern */ test::mock_acl_manager_ =
        new bluetooth::hci::testing::MockAclManager();
  }
  void TearDown() override {
    delete hci::testing::mock_controller_;
    delete hci::testing::mock_acl_manager_;
    delete test::mock_controller_;
    test::mock_controller_ = nullptr;
    delete test::mock_acl_manager_;
    test::mock_acl_manager_ = nullptr;

    handler_->Clear();
    delete handler_;
    delete thread_;

    main_thread_shut_down();
  }
  os::Thread* thread_{nullptr};
  os::Handler* handler_{nullptr};
};

TEST_F(MainShimTest, Nop) {}

TEST_F(MainShimTest, Acl_Lifecycle) {
  EXPECT_CALL(*hci::testing::mock_acl_manager_, RegisterCallbacks(_, _))
      .Times(1);
  EXPECT_CALL(*hci::testing::mock_acl_manager_, RegisterLeCallbacks(_, _))
      .Times(1);
  EXPECT_CALL(*hci::testing::mock_controller_,
  // Convenience method to create ACL objects
  std::unique_ptr<shim::legacy::Acl> MakeAcl() {
    EXPECT_CALL(*test::mock_acl_manager_, RegisterCallbacks(_, _)).Times(1);
    EXPECT_CALL(*test::mock_acl_manager_, RegisterLeCallbacks(_, _)).Times(1);
    EXPECT_CALL(*test::mock_controller_,
                RegisterCompletedMonitorAclPacketsCallback(_))
        .Times(1);
  EXPECT_CALL(*hci::testing::mock_acl_manager_,
              HACK_SetScoDisconnectCallback(_))
    EXPECT_CALL(*test::mock_acl_manager_, HACK_SetScoDisconnectCallback(_))
        .Times(1);
  EXPECT_CALL(*hci::testing::mock_controller_,
    EXPECT_CALL(*test::mock_controller_,
                UnregisterCompletedMonitorAclPacketsCallback)
        .Times(1);
    return std::make_unique<shim::legacy::Acl>(handler_, GetMockAclInterface(),
                                               kMaxLeAcceptlistSize);
  }
};

TEST_F(MainShimTest, Nop) {}

TEST_F(MainShimTest, Acl_Lifecycle) {
  auto acl = MakeAcl();
  acl.reset();
  acl = MakeAcl();
}

TEST_F(MainShimTest, connect_and_disconnect) {
  hci::Address address({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});

  auto acl = MakeAcl();

  // Create connection
  EXPECT_CALL(*test::mock_acl_manager_, CreateConnection(_)).Times(1);
  acl->CreateClassicConnection(address);

  // Respond with a mock connection created
  auto connection = std::make_unique<MockClassicAclConnection>(address, 123);
  ASSERT_EQ(123, connection->GetHandle());
  ASSERT_EQ(hci::Address({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}),
            connection->GetAddress());
  MockClassicAclConnection* raw_connection = connection.get();

  acl->OnConnectSuccess(std::move(connection));
  ASSERT_EQ(nullptr, connection);

  // Specify local disconnect request
  auto tx_disconnect_future = raw_connection->disconnect_promise_.get_future();
  acl->DisconnectClassic(123, HCI_SUCCESS);

  // Wait for disconnect to be received
  uint16_t result = tx_disconnect_future.get();
  ASSERT_EQ(123, result);

  // Now emulate the remote disconnect response
  auto handle_promise = std::promise<uint16_t>();
  auto rx_disconnect_future = handle_promise.get_future();
  mock_function_handle_promise_map["mock_connection_classic_on_disconnected"] =
      std::move(handle_promise);
  raw_connection->callbacks_->OnDisconnection(hci::ErrorCode::SUCCESS);

  auto acl = std::make_unique<shim::legacy::Acl>(
      handler_, shim::legacy::GetAclInterface(), 16);
  result = rx_disconnect_future.get();
  ASSERT_EQ(123, result);
}