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 #pragma once
16 #include <pw_async/heap_dispatcher.h>
17 
18 #include <memory>
19 
20 #include "pw_async/fake_dispatcher_fixture.h"
21 #include "pw_bluetooth/controller.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_channel.h"
24 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
25 #include "pw_bluetooth_sapphire/internal/host/transport/sco_data_channel.h"
26 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
27 
28 namespace bt::testing {
29 
30 class ControllerTestDoubleBase;
31 
32 // ControllerTest is a test harness intended for tests that rely on HCI
33 // transactions. It is templated on ControllerTestDoubleType which must derive
34 // from ControllerTestDoubleBase and must be able to send and receive HCI
35 // packets over Zircon channels, acting as the controller endpoint of HCI.
36 //
37 // The testing library provides two such types:
38 //
39 //   - MockController (mock_controller.h): Routes HCI packets directly to the
40 //     test harness. It allows tests to setup expectations based on the receipt
41 //     of HCI packets.
42 //
43 //   - FakeController (fake_controller.h): Emulates a Bluetooth controller. This
44 //     can respond to HCI commands the way a real controller would (albeit in a
45 //     contrived fashion), emulate discovery and connection events, etc.
46 template <class ControllerTestDoubleType>
47 class ControllerTest {
48  public:
49   // Default data buffer information used by ACLDataChannel.
50   static constexpr size_t kDefaultMaxAclDataPacketLength = 1024;
51   static constexpr size_t kDefaultMaxAclPacketCount = 5;
52 
53   // Default data buffer information used by ScoDataChannel.
54   static constexpr size_t kDefaultMaxScoPacketLength = 255;
55   static constexpr size_t kDefaultMaxScoPacketCount = 5;
56 
ControllerTest(pw::async::Dispatcher & dispatcher)57   ControllerTest(pw::async::Dispatcher& dispatcher) : dispatcher_(dispatcher) {}
58   ~ControllerTest() = default;
59 
60  protected:
61   void Initialize(pw::bluetooth::Controller::FeaturesBits features,
62                   bool initialize_transport = true) {
63     std::unique_ptr<pw::bluetooth::Controller> controller =
64         ControllerTest<ControllerTestDoubleType>::SetUpTestController();
65     test_device_->set_features(features);
66     transport_ =
67         std::make_unique<hci::Transport>(std::move(controller), dispatcher_);
68 
69     if (initialize_transport) {
70       std::optional<bool> init_result;
71       transport_->Initialize(
72           [&init_result](bool success) { init_result = success; });
73       ASSERT_TRUE(init_result.has_value());
74       ASSERT_TRUE(init_result.value());
75     }
76   }
77 
78   // Directly initializes the ACL data channel and wires up its data rx
79   // callback. It is OK to override the data rx callback after this is called.
80   //
81   // If data buffer information isn't provided, the ACLDataChannel will be
82   // initialized with shared BR/EDR/LE buffers using the constants declared
83   // above.
84   bool InitializeACLDataChannel(
85       const hci::DataBufferInfo& bredr_buffer_info = hci::DataBufferInfo(
86           kDefaultMaxAclDataPacketLength, kDefaultMaxAclPacketCount),
87       const hci::DataBufferInfo& le_buffer_info = hci::DataBufferInfo()) {
88     if (!transport_->InitializeACLDataChannel(bredr_buffer_info,
89                                               le_buffer_info)) {
90       return false;
91     }
92 
93     transport_->acl_data_channel()->SetDataRxHandler(
94         std::bind(&ControllerTest<ControllerTestDoubleType>::OnAclDataReceived,
95                   this,
96                   std::placeholders::_1));
97 
98     return true;
99   }
100 
101   // Directly initializes the SCO data channel.
102   bool InitializeScoDataChannel(
103       const hci::DataBufferInfo& buffer_info = hci::DataBufferInfo(
104           kDefaultMaxScoPacketLength, kDefaultMaxScoPacketCount)) {
105     return transport_->InitializeScoDataChannel(buffer_info);
106   }
107 
108   // Sets a callback which will be invoked when we receive packets from the test
109   // controller. |callback| will be posted on the test loop, thus no locking is
110   // necessary within the callback.
111   //
112   // InitializeACLDataChannel() must be called once and its data rx handler must
113   // not be overridden by tests for |callback| to work.
set_data_received_callback(hci::ACLPacketHandler callback)114   void set_data_received_callback(hci::ACLPacketHandler callback) {
115     data_received_callback_ = std::move(callback);
116   }
117 
transport()118   hci::Transport* transport() const { return transport_.get(); }
cmd_channel()119   hci::CommandChannel* cmd_channel() const {
120     return transport_->command_channel();
121   }
acl_data_channel()122   hci::AclDataChannel* acl_data_channel() const {
123     return transport_->acl_data_channel();
124   }
sco_data_channel()125   hci::ScoDataChannel* sco_data_channel() const {
126     return transport_->sco_data_channel();
127   }
128 
129   // Deletes |test_device_| and resets the pointer.
DeleteTestDevice()130   void DeleteTestDevice() { test_device_ = nullptr; }
DeleteTransport()131   void DeleteTransport() { transport_ = nullptr; }
132 
133   // Getters for internal fields frequently used by tests.
test_device()134   const typename ControllerTestDoubleType::WeakPtr& test_device() const {
135     return test_device_;
136   }
137 
138  private:
SetUpTestController()139   std::unique_ptr<pw::bluetooth::Controller> SetUpTestController() {
140     std::unique_ptr<ControllerTestDoubleType> controller =
141         std::make_unique<ControllerTestDoubleType>(dispatcher_);
142     test_device_ = controller->GetWeakPtr();
143     return controller;
144   }
145 
OnAclDataReceived(hci::ACLDataPacketPtr data_packet)146   void OnAclDataReceived(hci::ACLDataPacketPtr data_packet) {
147     // Accessing |data_received_callback_| is racy but unlikely to cause issues
148     // in unit tests. NOTE(armansito): Famous last words?
149     if (!data_received_callback_)
150       return;
151 
152     (void)heap_dispatcher_.Post(
153         [this, packet = std::move(data_packet)](pw::async::Context /*ctx*/,
154                                                 pw::Status status) mutable {
155           if (status.ok()) {
156             data_received_callback_(std::move(packet));
157           }
158         });
159   }
160 
161   pw::async::Dispatcher& dispatcher_;
162   pw::async::HeapDispatcher heap_dispatcher_{dispatcher_};
163   typename ControllerTestDoubleType::WeakPtr test_device_;
164   std::unique_ptr<hci::Transport> transport_;
165   hci::ACLPacketHandler data_received_callback_;
166 
167   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ControllerTest);
168   static_assert(
169       std::is_base_of<ControllerTestDoubleBase,
170                       ControllerTestDoubleType>::value,
171       "TestBase must be used with a derivative of ControllerTestDoubleBase");
172 };
173 
174 // FakeDispatcherControllerTest is a convenience test fixture that initializes
175 // ControllerTest with a pw_async FakeDispatcherFixture backend. Only if a
176 // different underlying dispatcher is desired (e.g. Zircon TestLoopFixture)
177 // should ControllerTest be referenced directly and passed the desired
178 // dispatcher, which must implement the pw_async Dispatcher interface.
179 //
180 // To properly "TearDown" ControllerTest, the Dispatcher must be driven, then
181 // DeleteTransport() called.
182 template <typename ControllerTestDoubleType>
183 class FakeDispatcherControllerTest
184     : public pw::async::test::FakeDispatcherFixture,
185       public ControllerTest<ControllerTestDoubleType> {
186  protected:
FakeDispatcherControllerTest()187   FakeDispatcherControllerTest()
188       : ControllerTest<ControllerTestDoubleType>(dispatcher()) {}
189 
SetUp()190   void SetUp() override {
191     SetUp(pw::bluetooth::Controller::FeaturesBits::kHciSco);
192   }
193 
194   void SetUp(pw::bluetooth::Controller::FeaturesBits features,
195              bool initialize_transport = true) {
196     ControllerTest<ControllerTestDoubleType>::Initialize(features,
197                                                          initialize_transport);
198     RunUntilIdle();
199   }
200 
TearDown()201   void TearDown() override {
202     RunUntilIdle();
203     ControllerTest<ControllerTestDoubleType>::DeleteTransport();
204   }
205 };
206 
207 }  // namespace bt::testing
208