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

Commit 1a6d62c6 authored by Qasim Javed's avatar Qasim Javed
Browse files

Add HCI timeout related unit tests using fake timers.

Bug: 245578454
Bug: 243824983
Tag: #gd-refactor
Test: atest bluetooth_test_gd_unit

Change-Id: Ie828a432ca42f1e01add09de7e7759c7d2344661
(cherry picked from commit c7966ad1)
Merged-In: Ie828a432ca42f1e01add09de7e7759c7d2344661
parent df147047
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ filegroup {
        "address_unittest.cc",
        "address_with_type_test.cc",
        "class_of_device_unittest.cc",
        "hci_layer_unittest.cc",
        "hci_packets_test.cc",
        "uuid_unittest.cc",
        "le_periodic_sync_manager_test.cc",
+188 −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.h"

#include <gtest/gtest.h>

#include <chrono>
#include <future>

#include "common/bind.h"
#include "common/init_flags.h"
#include "common/testing/log_capture.h"
#include "hal/hci_hal.h"
#include "hci/address.h"
#include "hci/address_with_type.h"
#include "hci/class_of_device.h"
#include "hci/controller.h"
#include "module.h"
#include "os/fake_timer/fake_timerfd.h"
#include "os/handler.h"
#include "os/thread.h"
#include "packet/raw_builder.h"

using namespace std::chrono_literals;

namespace bluetooth {
namespace hci {

using common::BidiQueue;
using common::BidiQueueEnd;
using common::InitFlags;
using os::fake_timer::fake_timerfd_advance;
using packet::kLittleEndian;
using packet::PacketView;
using packet::RawBuilder;
using testing::LogCapture;

class TestHciHal : public hal::HciHal {
 public:
  TestHciHal() : hal::HciHal() {}

  ~TestHciHal() {
    ASSERT_LOG(callbacks == nullptr, "unregisterIncomingPacketCallback() must be called");
  }

  void registerIncomingPacketCallback(hal::HciHalCallbacks* callback) override {
    callbacks = callback;
  }

  void unregisterIncomingPacketCallback() override {
    callbacks = nullptr;
  }

  void sendHciCommand(hal::HciPacket command) override {
    outgoing_commands_.push_back(std::move(command));
    LOG_DEBUG("Enqueued HCI command in HAL.");
  }

  void sendScoData(hal::HciPacket data) override {}
  void sendIsoData(hal::HciPacket data) override {}
  void sendAclData(hal::HciPacket data) override {}

  hal::HciHalCallbacks* callbacks = nullptr;

  PacketView<kLittleEndian> GetPacketView(hal::HciPacket data) {
    auto shared = std::make_shared<std::vector<uint8_t>>(data);
    return PacketView<kLittleEndian>(shared);
  }

  CommandView GetSentCommand() {
    auto packetview = GetPacketView(std::move(outgoing_commands_.front()));
    outgoing_commands_.pop_front();
    return CommandView::Create(packetview);
  }

  void Start() override {}

  void Stop() override {}

  void ListDependencies(ModuleList*) const override {}

  int GetPendingCommands() {
    return outgoing_commands_.size();
  }

  std::string ToString() const override {
    return std::string("TestHciHal");
  }

  static const ModuleFactory Factory;

 private:
  std::list<hal::HciPacket> outgoing_commands_;
  std::unique_ptr<std::promise<void>> sent_command_promise_;
};

const ModuleFactory TestHciHal::Factory = ModuleFactory([]() { return new TestHciHal(); });

class HciLayerTest : public ::testing::Test {
 protected:
  void SetUp() override {
    log_capture_ = std::make_unique<LogCapture>();
    hal_ = new TestHciHal();
    fake_registry_.InjectTestModule(&hal::HciHal::Factory, hal_);
    fake_registry_.Start<HciLayer>(&fake_registry_.GetTestThread());
    hci_ = static_cast<HciLayer*>(fake_registry_.GetModuleUnderTest(&HciLayer::Factory));
    hci_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
    ASSERT_TRUE(fake_registry_.IsStarted<HciLayer>());
    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
    InitFlags::SetAllForTesting();
  }

  void TearDown() override {
    fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
    fake_registry_.StopAll();
  }

  void FakeTimerAdvance(uint64_t ms) {
    hci_handler_->Post(common::BindOnce(fake_timerfd_advance, ms));
  }

  void FailIfResetNotSent() {
    std::promise<void> promise;
    log_capture_->WaitUntilLogContains(&promise, "Enqueued HCI command in HAL.");
    auto sent_command = hal_->GetSentCommand();
    auto reset_view = ResetView::Create(CommandView::Create(sent_command));
    ASSERT_TRUE(reset_view.IsValid());
  }

  TestHciHal* hal_ = nullptr;
  HciLayer* hci_ = nullptr;
  os::Handler* hci_handler_ = nullptr;
  TestModuleRegistry fake_registry_;
  std::unique_ptr<LogCapture> log_capture_;
};

TEST_F(HciLayerTest, setup_teardown) {}

TEST_F(HciLayerTest, reset_command_sent_on_start) {
  FailIfResetNotSent();
}

TEST_F(HciLayerTest, controller_debug_info_requested_on_hci_timeout) {
  FailIfResetNotSent();
  FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());

  std::promise<void> promise;
  log_capture_->WaitUntilLogContains(&promise, "Enqueued HCI command in HAL.");
  auto sent_command = hal_->GetSentCommand();
  auto debug_info_view = ControllerDebugInfoView::Create(VendorCommandView::Create(sent_command));
  ASSERT_TRUE(debug_info_view.IsValid());
}

TEST_F(HciLayerTest, abort_after_hci_restart_timeout) {
  FailIfResetNotSent();
  FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());

  std::promise<void> promise;
  log_capture_->WaitUntilLogContains(&promise, "Enqueued HCI command in HAL.");
  auto sent_command = hal_->GetSentCommand();
  auto debug_info_view = ControllerDebugInfoView::Create(VendorCommandView::Create(sent_command));
  ASSERT_TRUE(debug_info_view.IsValid());

  ASSERT_DEATH(
      {
        FakeTimerAdvance(HciLayer::kHciTimeoutRestartMs.count());
        std::promise<void> promise;
        log_capture_->WaitUntilLogContains(&promise, "Done waiting for debug information after HCI timeout");
      },
      "");
}

}  // namespace hci
}  // namespace bluetooth