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::EmbossCommandPacket::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 =
63 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
64 hci_spec::kReset);
65 id2 = cmd_channel()->SendCommand(std::move(packet), cb);
66 ASSERT_NE(0u, id2);
67
68 // Run the loop until the command timeout task gets scheduled.
69 RunUntilIdle();
70 ASSERT_EQ(0u, cb_count);
71 EXPECT_EQ(0u, closed_cb_count);
72
73 RunFor(kCommandTimeout);
74 EXPECT_EQ(0u, cb_count);
75 EXPECT_EQ(1u, closed_cb_count);
76 EXPECT_TRUE(cmd_chan_weak.is_alive());
77 }
78
TEST_F(TransportDeathTest,AttachInspectBeforeInitializeACLDataChannelCrashes)79 TEST_F(TransportDeathTest, AttachInspectBeforeInitializeACLDataChannelCrashes) {
80 inspect::Inspector inspector;
81 EXPECT_DEATH_IF_SUPPORTED(transport()->AttachInspect(inspector.GetRoot()),
82 ".*");
83 }
84
TEST_F(TransportTest,HciErrorClosesTransportWithSco)85 TEST_F(TransportTest, HciErrorClosesTransportWithSco) {
86 size_t closed_cb_count = 0;
87 transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
88
89 EXPECT_TRUE(transport()->InitializeScoDataChannel(
90 DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
91 RunUntilIdle();
92
93 test_device()->Stop();
94 RunUntilIdle();
95 EXPECT_EQ(closed_cb_count, 1u);
96 }
97
98 class TransportTestWithoutSco : public TransportTest {
99 public:
SetUp()100 void SetUp() override {
101 // Disable the SCO feature bit.
102 TransportTest::SetUp(testing::MockController::FeaturesBits{0});
103 }
104 };
105
TEST_F(TransportTestWithoutSco,GetScoChannelFailure)106 TEST_F(TransportTestWithoutSco, GetScoChannelFailure) {
107 size_t closed_cb_count = 0;
108 transport()->SetTransportErrorCallback([&] { closed_cb_count++; });
109 EXPECT_FALSE(transport()->InitializeScoDataChannel(
110 DataBufferInfo(/*max_data_length=*/1, /*max_num_packets=*/1)));
111 RunUntilIdle();
112 EXPECT_EQ(closed_cb_count, 0u);
113 }
114
TEST_F(TransportTest,InitializeScoFailsBufferNotAvailable)115 TEST_F(TransportTest, InitializeScoFailsBufferNotAvailable) {
116 EXPECT_FALSE(transport()->InitializeScoDataChannel(
117 DataBufferInfo(/*max_data_length=*/0, /*max_num_packets=*/0)));
118 }
119
120 } // namespace
121 } // namespace bt::hci
122