blob: b1c2943971ccb742e87d2eecf9084c7a6a30a5a8 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/transport.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/inspect.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
namespace bt::hci {
namespace {
using TransportTest =
bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
using TransportDeathTest = TransportTest;
TEST_F(TransportTest,
CommandChannelTimeoutShutsDownChannelAndNotifiesClosedCallback) {
CommandChannel::WeakPtr cmd_chan_weak = cmd_channel()->AsWeakPtr();
size_t closed_cb_count = 0;
transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
constexpr pw::chrono::SystemClock::duration kCommandTimeout =
std::chrono::seconds(12);
StaticByteBuffer req_reset(LowerBits(hci_spec::kReset),
UpperBits(hci_spec::kReset), // HCI_Reset opcode
0x00 // parameter_total_size
);
// Expect the HCI_Reset command but dont send a reply back to make the command
// time out.
EXPECT_CMD_PACKET_OUT(test_device(), req_reset);
size_t cb_count = 0;
CommandChannel::TransactionId id1, id2;
auto cb = [&cb_count](CommandChannel::TransactionId callback_id,
const EventPacket& event) { cb_count++; };
auto packet =
hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
hci_spec::kReset);
id1 = cmd_channel()->SendCommand(std::move(packet), cb);
ASSERT_NE(0u, id1);
packet =
hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
hci_spec::kReset);
id2 = cmd_channel()->SendCommand(std::move(packet), cb);
ASSERT_NE(0u, id2);
// Run the loop until the command timeout task gets scheduled.
RunUntilIdle();
ASSERT_EQ(0u, cb_count);
EXPECT_EQ(0u, closed_cb_count);
RunFor(kCommandTimeout);
EXPECT_EQ(0u, cb_count);
EXPECT_EQ(1u, closed_cb_count);
EXPECT_TRUE(cmd_chan_weak.is_alive());
}
TEST_F(TransportDeathTest, AttachInspectBeforeInitializeACLDataChannelCrashes) {
inspect::Inspector inspector;
EXPECT_DEATH_IF_SUPPORTED(transport()->AttachInspect(inspector.GetRoot()),
".*");
}
TEST_F(TransportTest, HciErrorClosesTransportWithSco) {
size_t closed_cb_count = 0;
transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
EXPECT_TRUE(transport()->InitializeScoDataChannel(
DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
RunUntilIdle();
test_device()->Stop();
RunUntilIdle();
EXPECT_EQ(closed_cb_count, 1u);
}
class TransportTestWithoutSco : public TransportTest {
public:
void SetUp() override {
// Disable the SCO feature bit.
TransportTest::SetUp(testing::MockController::FeaturesBits{0});
}
};
TEST_F(TransportTestWithoutSco, GetScoChannelFailure) {
size_t closed_cb_count = 0;
transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
EXPECT_FALSE(transport()->InitializeScoDataChannel(
DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
RunUntilIdle();
EXPECT_EQ(closed_cb_count, 0u);
}
TEST_F(TransportTest, InitializeScoFailsBufferNotAvailable) {
EXPECT_FALSE(transport()->InitializeScoDataChannel(
DataBufferInfo(/*max_data_length=*/0, /*max_num_packets=*/0)));
}
} // namespace
} // namespace bt::hci