1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
18 #include "pw_bluetooth_sapphire/internal/host/common/inspect.h"
19 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
23
24 namespace bt::hci {
25
26 namespace {
27
28 using TransportTest =
29 bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
30 using TransportDeathTest = TransportTest;
31
TEST_F(TransportTest,CommandChannelTimeoutShutsDownChannelAndNotifiesClosedCallback)32 TEST_F(TransportTest,
33 CommandChannelTimeoutShutsDownChannelAndNotifiesClosedCallback) {
34 CommandChannel::WeakPtr cmd_chan_weak = cmd_channel()->AsWeakPtr();
35
36 size_t closed_cb_count = 0;
37 transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
38
39 constexpr pw::chrono::SystemClock::duration kCommandTimeout =
40 std::chrono::seconds(12);
41
42 StaticByteBuffer req_reset(LowerBits(hci_spec::kReset),
43 UpperBits(hci_spec::kReset), // HCI_Reset opcode
44 0x00 // parameter_total_size
45 );
46
47 // Expect the HCI_Reset command but dont send a reply back to make the command
48 // time out.
49 EXPECT_CMD_PACKET_OUT(test_device(), req_reset);
50
51 size_t cb_count = 0;
52 CommandChannel::TransactionId id1, id2;
53 auto cb = [&cb_count](CommandChannel::TransactionId /*callback_id*/,
54 const EventPacket& /*event*/) { cb_count++; };
55
56 auto packet =
57 hci::CommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
58 hci_spec::kReset);
59 id1 = cmd_channel()->SendCommand(std::move(packet), cb);
60 ASSERT_NE(0u, id1);
61
62 packet = hci::CommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
63 hci_spec::kReset);
64 id2 = cmd_channel()->SendCommand(std::move(packet), cb);
65 ASSERT_NE(0u, id2);
66
67 // Run the loop until the command timeout task gets scheduled.
68 RunUntilIdle();
69 ASSERT_EQ(0u, cb_count);
70 EXPECT_EQ(0u, closed_cb_count);
71
72 RunFor(kCommandTimeout);
73 EXPECT_EQ(0u, cb_count);
74 EXPECT_EQ(1u, closed_cb_count);
75 EXPECT_TRUE(cmd_chan_weak.is_alive());
76 }
77
TEST_F(TransportDeathTest,AttachInspectBeforeInitializeACLDataChannelCrashes)78 TEST_F(TransportDeathTest, AttachInspectBeforeInitializeACLDataChannelCrashes) {
79 inspect::Inspector inspector;
80 EXPECT_DEATH_IF_SUPPORTED(transport()->AttachInspect(inspector.GetRoot()),
81 ".*");
82 }
83
TEST_F(TransportTest,HciErrorClosesTransportWithSco)84 TEST_F(TransportTest, HciErrorClosesTransportWithSco) {
85 size_t closed_cb_count = 0;
86 transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
87
88 EXPECT_TRUE(transport()->InitializeScoDataChannel(
89 DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
90 RunUntilIdle();
91
92 test_device()->Stop();
93 RunUntilIdle();
94 EXPECT_EQ(closed_cb_count, 1u);
95 }
96
97 class TransportTestWithoutSco : public TransportTest {
98 public:
SetUp()99 void SetUp() override {
100 // Disable the SCO feature bit.
101 TransportTest::SetUp(testing::MockController::FeaturesBits{0});
102 }
103 };
104
TEST_F(TransportTestWithoutSco,GetScoChannelFailure)105 TEST_F(TransportTestWithoutSco, GetScoChannelFailure) {
106 size_t closed_cb_count = 0;
107 transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
108 EXPECT_FALSE(transport()->InitializeScoDataChannel(
109 DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
110 RunUntilIdle();
111 EXPECT_EQ(closed_cb_count, 0u);
112 }
113
TEST_F(TransportTest,InitializeScoFailsBufferNotAvailable)114 TEST_F(TransportTest, InitializeScoFailsBufferNotAvailable) {
115 EXPECT_FALSE(transport()->InitializeScoDataChannel(
116 DataBufferInfo(/*max_data_length=*/0, /*max_num_packets=*/0)));
117 }
118
119 } // namespace
120 } // namespace bt::hci
121