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

Commit 040aed1c authored by Chris Manton's avatar Chris Manton
Browse files

Introduce bluetooth_test_gd_unit.ClassicImplTest

Bug: 286546816
Test: atest bluetooth_test_gd_unit

Change-Id: Iedbd75959a316a6f06aebc8ee8b5640952f5a297
parent 86b81be1
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ filegroup {
        "acl_builder_test.cc",
        "acl_builder_test.cc",
        "acl_manager/acl_scheduler_test.cc",
        "acl_manager/acl_scheduler_test.cc",
        "acl_manager/classic_acl_connection_test.cc",
        "acl_manager/classic_acl_connection_test.cc",
        "acl_manager/classic_impl_test.cc",
        "acl_manager/le_acl_connection_test.cc",
        "acl_manager/le_acl_connection_test.cc",
        "acl_manager/le_impl_test.cc",
        "acl_manager/le_impl_test.cc",
        "acl_manager/round_robin_scheduler_test.cc",
        "acl_manager/round_robin_scheduler_test.cc",
+3 −3
Original line number Original line Diff line number Diff line
@@ -46,7 +46,7 @@ class AclScheduler : public bluetooth::Module {


  // Report that an ACL connection has completed, and dispatch to the appropriate callback based on the internal
  // Report that an ACL connection has completed, and dispatch to the appropriate callback based on the internal
  // state. Then, start the next operation.
  // state. Then, start the next operation.
  void ReportAclConnectionCompletion(
  virtual void ReportAclConnectionCompletion(
      Address address,
      Address address,
      common::ContextualOnceCallback<void()> handle_outgoing_connection,
      common::ContextualOnceCallback<void()> handle_outgoing_connection,
      common::ContextualOnceCallback<void()> handle_incoming_connection,
      common::ContextualOnceCallback<void()> handle_incoming_connection,
@@ -93,7 +93,7 @@ class AclScheduler : public bluetooth::Module {
 public:
 public:
  static const ModuleFactory Factory;
  static const ModuleFactory Factory;
  AclScheduler();
  AclScheduler();
  ~AclScheduler();
  virtual ~AclScheduler();
};
};


}  // namespace acl_manager
}  // namespace acl_manager
+281 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2023 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/acl_manager/classic_impl.h"

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

#include <chrono>
#include <mutex>

#include "common/bidi_queue.h"
#include "common/callback.h"
#include "common/testing/log_capture.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager/acl_scheduler.h"
#include "hci/acl_manager/connection_callbacks_mock.h"
#include "hci/acl_manager/connection_management_callbacks_mock.h"
#include "hci/address.h"
#include "hci/controller_mock.h"
#include "hci/hci_layer_fake.h"
#include "hci/hci_packets.h"
#include "os/handler.h"
#include "os/log.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"

using namespace bluetooth;
using namespace std::chrono_literals;

using ::bluetooth::common::BidiQueue;
using ::bluetooth::common::Callback;
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
using ::bluetooth::packet::BitInserter;
using ::bluetooth::packet::RawBuilder;
using ::bluetooth::testing::LogCapture;

using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Mock;
using ::testing::MockFunction;
using ::testing::SaveArg;
using ::testing::VariantWith;
using ::testing::WithArg;

namespace {
constexpr bool kCrashOnUnknownHandle = true;
constexpr char kFixedAddress[] = "c0:aa:bb:cc:dd:ee";
const bluetooth::hci::Address kRemoteAddress =
    bluetooth::hci::Address({0x00, 0x11, 0x22, 0x33, 0x44, 0x55});
[[maybe_unused]] constexpr uint16_t kHciHandle = 123;
template <typename B>
std::shared_ptr<std::vector<uint8_t>> Serialize(std::unique_ptr<B> build) {
  auto bytes = std::make_shared<std::vector<uint8_t>>();
  BitInserter bi(*bytes);
  build->Serialize(bi);
  return bytes;
}

template <typename T>
T CreateCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return T::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}

template <typename T>
T CreateAclCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return T::Create(CreateCommandView<hci::AclCommandView>(bytes));
}

template <typename T>
T CreateConnectionManagementCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return T::Create(CreateAclCommandView<hci::ConnectionManagementCommandView>(bytes));
}

template <typename T>
T CreateSecurityCommandView(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return T::Create(CreateCommandView<hci::SecurityCommandView>(bytes));
}

template <typename T>
T CreateEventView(std::shared_ptr<std::vector<uint8_t>> bytes) {
  return T::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}

[[maybe_unused]] hci::CommandCompleteView ReturnCommandComplete(
    hci::OpCode op_code, hci::ErrorCode error_code) {
  std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
  auto builder = hci::CommandCompleteBuilder::Create(
      uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
  auto bytes = Serialize<hci::CommandCompleteBuilder>(std::move(builder));
  return hci::CommandCompleteView::Create(
      hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}

[[maybe_unused]] hci::CommandStatusView ReturnCommandStatus(
    hci::OpCode op_code, hci::ErrorCode error_code) {
  std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
  auto builder = hci::CommandStatusBuilder::Create(
      hci::ErrorCode::SUCCESS, uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
  auto bytes = Serialize<hci::CommandStatusBuilder>(std::move(builder));
  return hci::CommandStatusView::Create(
      hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
}

bool handle_outgoing_connection_ = false;
bool handle_incoming_connection_ = false;

}  // namespace

namespace bluetooth {
namespace hci {
namespace acl_manager {

class MockAclScheduler : public AclScheduler {
 public:
  virtual void ReportAclConnectionCompletion(
      Address address,
      common::ContextualOnceCallback<void()> handle_outgoing_connection,
      common::ContextualOnceCallback<void()> handle_incoming_connection,
      common::ContextualOnceCallback<void(std::string)> handle_unknown_connection) override {
    if (handle_outgoing_connection_) {
      handle_outgoing_connection.InvokeIfNotEmpty();
      return;
    }

    if (handle_incoming_connection_) {
      handle_incoming_connection.InvokeIfNotEmpty();
    } else {
      handle_unknown_connection.InvokeIfNotEmpty("set_of_incoming_connecting_addresses()");
    }
  }
};

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 ClassicImplTest : public ::testing::Test {
 protected:
  void SetUp() override {
    bluetooth::common::InitFlags::SetAllForTesting();
    thread_ = new Thread("thread", Thread::Priority::NORMAL);
    handler_ = new Handler(thread_);
    hci_layer_ = new TestHciLayer();
    controller_ = new testing::MockController();

    EXPECT_CALL(*controller_, GetNumAclPacketBuffers);
    EXPECT_CALL(*controller_, GetAclPacketLength);
    EXPECT_CALL(*controller_, GetLeBufferSize);
    EXPECT_CALL(*controller_, RegisterCompletedAclPacketsCallback);
    EXPECT_CALL(*controller_, UnregisterCompletedAclPacketsCallback);

    round_robin_scheduler_ =
        new acl_manager::RoundRobinScheduler(handler_, controller_, hci_queue_.GetUpEnd());
    hci_queue_.GetDownEnd()->RegisterDequeue(
        handler_, common::Bind(&ClassicImplTest::HciDownEndDequeue, common::Unretained(this)));
    acl_scheduler_ = new MockAclScheduler();
    rnr_ = new RemoteNameRequestModule();
    classic_impl_ = new acl_manager::classic_impl(
        hci_layer_,
        controller_,
        handler_,
        round_robin_scheduler_,
        kCrashOnUnknownHandle,
        acl_scheduler_,
        rnr_);
    classic_impl_->handle_register_callbacks(&mock_connection_callback_, handler_);

    Address address;
    Address::FromString(kFixedAddress, address);
  }

  void TearDown() override {
    sync_handler();
    delete classic_impl_;

    hci_queue_.GetDownEnd()->UnregisterDequeue();

    delete rnr_;
    delete acl_scheduler_;
    delete round_robin_scheduler_;
    delete controller_;
    delete hci_layer_;

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

  MockAclScheduler* acl_scheduler_;
  RemoteNameRequestModule* rnr_;

  void sync_handler() {
    thread_->GetReactor()->WaitForIdle(2s);
  }

  void HciDownEndDequeue() {
    auto packet = hci_queue_.GetDownEnd()->TryDequeue();
    // Convert from a Builder to a View
    auto bytes = std::make_shared<std::vector<uint8_t>>();
    bluetooth::packet::BitInserter i(*bytes);
    bytes->reserve(packet->size());
    packet->Serialize(i);
    auto packet_view = bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>(bytes);
    AclView acl_packet_view = AclView::Create(packet_view);
    ASSERT_TRUE(acl_packet_view.IsValid());
    PacketView<true> count_view = acl_packet_view.GetPayload();
    sent_acl_packets_.push(acl_packet_view);

    packet_count_--;
    if (packet_count_ == 0) {
      packet_promise_->set_value();
      packet_promise_ = nullptr;
    }
  }

 protected:
  Address remote_address_;

  uint16_t packet_count_;
  std::unique_ptr<std::promise<void>> packet_promise_;
  std::unique_ptr<std::future<void>> packet_future_;
  std::queue<AclView> sent_acl_packets_;

  BidiQueue<AclView, AclBuilder> hci_queue_{3};

  Thread* thread_;
  Handler* handler_;
  TestHciLayer* hci_layer_{nullptr};
  testing::MockController* controller_;
  acl_manager::RoundRobinScheduler* round_robin_scheduler_{nullptr};

  acl_manager::MockConnectionCallback mock_connection_callback_;
  acl_manager::MockConnectionManagementCallbacks connection_management_callbacks_;

  struct acl_manager::classic_impl* classic_impl_;
};

TEST_F(ClassicImplTest, nop) {}

TEST_F(ClassicImplTest, on_classic_event_CONNECTION_COMPLETE__SUCCESS) {
  // Expecting valid response
  EXPECT_CALL(mock_connection_callback_, OnConnectSuccess);
  handle_outgoing_connection_ = true;

  auto command = ConnectionCompleteBuilder::Create(
      ErrorCode::SUCCESS,
      kHciHandle,
      kRemoteAddress,
      LinkType::ACL,
      bluetooth::hci::Enable::ENABLED);

  auto bytes = Serialize<ConnectionCompleteBuilder>(std::move(command));
  auto view = CreateEventView<hci::ConnectionCompleteView>(bytes);
  ASSERT_TRUE(view.IsValid());
  classic_impl_->on_classic_event(view);
}

}  // namespace acl_manager
}  // namespace hci
}  // namespace bluetooth