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 <lib/fit/function.h> 17 18 #include <queue> 19 #include <vector> 20 21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 23 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h" 24 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 25 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test_double_base.h" 26 27 namespace bt::testing { 28 29 struct ExpectationMetadata { ExpectationMetadataExpectationMetadata30 ExpectationMetadata(const char* file, int line, const char* expectation) 31 : file(file), line(line), expectation(expectation) {} 32 const char* file; 33 int line; 34 // String inside of the expectation expression: 35 // EXPECT_ACL_PACKET_OUT(expectation, ...). 36 const char* expectation; 37 }; 38 39 struct PacketExpectation { 40 DynamicByteBuffer data; 41 ExpectationMetadata meta; 42 }; 43 44 class Transaction { 45 public: 46 // The |expected| buffer and the buffers in |replies| will be copied, so their 47 // lifetime does not need to extend past Transaction construction. 48 Transaction(const ByteBuffer& expected, 49 const std::vector<const ByteBuffer*>& replies, 50 ExpectationMetadata meta); 51 virtual ~Transaction() = default; 52 Transaction(Transaction&& other) = default; 53 Transaction& operator=(Transaction&& other) = default; 54 55 // Returns true if the transaction matches the given HCI packet. 56 virtual bool Match(const ByteBuffer& packet); 57 expected()58 const PacketExpectation& expected() { return expected_; } set_expected(const PacketExpectation & expected)59 void set_expected(const PacketExpectation& expected) { 60 expected_ = PacketExpectation{.data = DynamicByteBuffer(expected.data), 61 .meta = expected.meta}; 62 } 63 replies()64 std::queue<DynamicByteBuffer>& replies() { return replies_; } 65 66 private: 67 PacketExpectation expected_; 68 std::queue<DynamicByteBuffer> replies_; 69 70 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Transaction); 71 }; 72 73 // A CommandTransaction is used to set up an expectation for a command channel 74 // packet and the events that should be sent back in response to it. 75 class CommandTransaction final : public Transaction { 76 public: CommandTransaction(const ByteBuffer & expected,const std::vector<const ByteBuffer * > & replies,ExpectationMetadata meta)77 CommandTransaction(const ByteBuffer& expected, 78 const std::vector<const ByteBuffer*>& replies, 79 ExpectationMetadata meta) 80 : Transaction(expected, replies, meta), prefix_(false) {} 81 82 // Match by opcode only. 83 CommandTransaction(hci_spec::OpCode expected_opcode, 84 const std::vector<const ByteBuffer*>& replies, 85 ExpectationMetadata meta); 86 87 // Move constructor and assignment operator. 88 CommandTransaction(CommandTransaction&& other) = default; 89 CommandTransaction& operator=(CommandTransaction&& other) = default; 90 91 // Returns true if the transaction matches the given HCI command packet. 92 bool Match(const ByteBuffer& cmd) override; 93 94 private: 95 bool prefix_ = false; 96 }; 97 98 // A DataTransaction is used to set up an expectation for an acl data channel 99 class DataTransaction final : public Transaction { 100 public: DataTransaction(const ByteBuffer & expected,const std::vector<const ByteBuffer * > & replies,ExpectationMetadata meta)101 DataTransaction(const ByteBuffer& expected, 102 const std::vector<const ByteBuffer*>& replies, 103 ExpectationMetadata meta) 104 : Transaction(expected, replies, meta) {} 105 DataTransaction(DataTransaction&& other) = default; 106 DataTransaction& operator=(DataTransaction&& other) = default; 107 }; 108 109 // A ScoTransaction is used to set up an expectation for a SCO data channel 110 // SCO packets don't have a concept of "replies". 111 class ScoTransaction final : public Transaction { 112 public: ScoTransaction(const ByteBuffer & expected,ExpectationMetadata meta)113 ScoTransaction(const ByteBuffer& expected, ExpectationMetadata meta) 114 : Transaction(expected, /*replies=*/{}, meta) {} 115 ScoTransaction(ScoTransaction&& other) = default; 116 ScoTransaction& operator=(ScoTransaction&& other) = default; 117 }; 118 119 // An IsoTransaction is used to set up an expectation for an ISO data channel. 120 // ISO packets don't have a concept of "replies". 121 class IsoTransaction final : public Transaction { 122 public: IsoTransaction(const ByteBuffer & expected,ExpectationMetadata meta)123 IsoTransaction(const ByteBuffer& expected, ExpectationMetadata meta) 124 : Transaction(expected, /*replies=*/{}, meta) {} 125 IsoTransaction(IsoTransaction&& other) = default; 126 IsoTransaction& operator=(IsoTransaction&& other) = default; 127 }; 128 129 // Helper macro for expecting a data packet and specifying a variable number of 130 // responses that the MockController should send in response to the expected 131 // packet. 132 #define EXPECT_ACL_PACKET_OUT(device, expected, ...) \ 133 (device)->QueueDataTransaction( \ 134 (expected), \ 135 {__VA_ARGS__}, \ 136 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 137 138 // Helper macro for expecting a SCO packet. 139 #define EXPECT_SCO_PACKET_OUT(device, expected) \ 140 (device)->QueueScoTransaction( \ 141 (expected), \ 142 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 143 144 // Helper macro for expecting a command packet and receiving a variable number 145 // of responses. 146 #define EXPECT_CMD_PACKET_OUT(device, expected, ...) \ 147 (device)->QueueCommandTransaction( \ 148 (expected), \ 149 {__VA_ARGS__}, \ 150 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 151 152 // Helper macro for expecting an ISO packet. 153 #define EXPECT_ISO_PACKET_OUT(device, expected) \ 154 (device)->QueueIsoTransaction( \ 155 (expected), \ 156 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 157 158 // MockController allows unit tests to set up an expected sequence of HCI 159 // command packets and ACL data packets and any packets that should be sent back 160 // in response. The code internally verifies each received packet using gtest 161 // ASSERT_* macros. 162 class MockController final : public ControllerTestDoubleBase, 163 public WeakSelf<MockController> { 164 public: 165 explicit MockController(pw::async::Dispatcher& pw_dispatcher); 166 ~MockController() override; 167 168 // Queues a transaction into the MockController's expected command queue. Each 169 // packet received through the command channel endpoint will be verified 170 // against the next expected transaction in the queue. A mismatch will cause a 171 // fatal assertion. On a match, MockController will send back the replies 172 // provided in the transaction. 173 void QueueCommandTransaction(CommandTransaction transaction); 174 void QueueCommandTransaction(const ByteBuffer& expected, 175 const std::vector<const ByteBuffer*>& replies, 176 ExpectationMetadata); 177 void QueueCommandTransaction(hci_spec::OpCode expected_opcode, 178 const std::vector<const ByteBuffer*>& replies, 179 ExpectationMetadata meta); 180 181 // Queues a transaction into the MockController's expected ACL data queue. 182 // Each packet received through the ACL data channel endpoint will be verified 183 // against the next expected transaction in the queue. A mismatch will cause a 184 // fatal assertion. On a match, MockController will send back the replies 185 // provided in the transaction. 186 void QueueDataTransaction(DataTransaction transaction); 187 void QueueDataTransaction(const ByteBuffer& expected, 188 const std::vector<const ByteBuffer*>& replies, 189 ExpectationMetadata meta); 190 191 // Queues a transaction into the MockController's expected SCO packet queue. 192 // Each packet received through the SCO data channel endpoint will be verified 193 // against the next expected transaction in the queue. A mismatch will cause a 194 // fatal assertion. 195 void QueueScoTransaction(const ByteBuffer& expected, 196 ExpectationMetadata meta); 197 198 // Queues a transaction into the MockController's expected ISO packet queue. 199 // Each packet received through the ISO data channel endpoint will be verified 200 // against the next expected transaction in the queue. A mismatch will cause a 201 // fatal assertion. 202 void QueueIsoTransaction(const ByteBuffer& expected, 203 ExpectationMetadata meta); 204 205 // Returns true iff all transactions queued with QueueScoTransaction() have 206 // been received. 207 bool AllExpectedScoPacketsSent() const; 208 209 // Returns true iff all transactions queued with QueueDataTransaction() have 210 // been received. 211 bool AllExpectedDataPacketsSent() const; 212 213 // Returns true iff all transactions queued with QueueCommandTransaction() 214 // have been received. 215 bool AllExpectedCommandPacketsSent() const; 216 217 // Returns true iff all transactions queued with QueueIsoTransaction() have 218 // been received. 219 bool AllExpectedIsoPacketsSent() const; 220 221 // Callback to invoke when a packet is received over the data channel. Care 222 // should be taken to ensure that a callback with a reference to test case 223 // variables is not invoked when tearing down. 224 using DataCallback = fit::function<void(const ByteBuffer& packet)>; 225 void SetDataCallback(DataCallback callback); 226 void ClearDataCallback(); 227 228 // Callback invoked when a transaction completes. Care should be taken to 229 // ensure that a callback with a reference to test case variables is not 230 // invoked when tearing down. 231 using TransactionCallback = fit::function<void(const ByteBuffer& rx)>; 232 void SetTransactionCallback(TransactionCallback callback); 233 void SetTransactionCallback(fit::closure callback); 234 void ClearTransactionCallback(); 235 236 private: 237 void OnCommandReceived(const ByteBuffer& data); 238 void OnACLDataPacketReceived(const ByteBuffer& acl_data_packet); 239 void OnScoDataPacketReceived(const ByteBuffer& sco_data_packet); 240 void OnIsoDataPacketReceived(const ByteBuffer& iso_data_packet); 241 242 // Controller overrides: 243 void SendCommand(pw::span<const std::byte> data) override; 244 void SendAclData(pw::span<const std::byte> data) override; 245 void SendScoData(pw::span<const std::byte> data) override; 246 void SendIsoData(pw::span<const std::byte> data) override; 247 248 std::queue<CommandTransaction> cmd_transactions_; 249 std::queue<DataTransaction> data_transactions_; 250 std::queue<ScoTransaction> sco_transactions_; 251 std::queue<IsoTransaction> iso_transactions_; 252 DataCallback data_callback_; 253 TransactionCallback transaction_callback_; 254 255 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(MockController); 256 }; 257 258 } // namespace bt::testing 259