• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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