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 // Helper macro for expecting a data packet and specifying a variable number of 120 // responses that the MockController should send in response to the expected 121 // packet. 122 #define EXPECT_ACL_PACKET_OUT(device, expected, ...) \ 123 (device)->QueueDataTransaction( \ 124 (expected), \ 125 {__VA_ARGS__}, \ 126 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 127 128 // Helper macro for expecting a SCO packet. 129 #define EXPECT_SCO_PACKET_OUT(device, expected) \ 130 (device)->QueueScoTransaction( \ 131 (expected), \ 132 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 133 134 // Helper macro for expecting a command packet and receiving a variable number 135 // of responses. 136 #define EXPECT_CMD_PACKET_OUT(device, expected, ...) \ 137 (device)->QueueCommandTransaction( \ 138 (expected), \ 139 {__VA_ARGS__}, \ 140 bt::testing::ExpectationMetadata(__FILE__, __LINE__, #expected)) 141 142 // MockController allows unit tests to set up an expected sequence of HCI 143 // command packets and ACL data packets and any packets that should be sent back 144 // in response. The code internally verifies each received packet using gtest 145 // ASSERT_* macros. 146 class MockController final : public ControllerTestDoubleBase, 147 public WeakSelf<MockController> { 148 public: 149 explicit MockController(pw::async::Dispatcher& pw_dispatcher); 150 ~MockController() override; 151 152 // Queues a transaction into the MockController's expected command queue. Each 153 // packet received through the command channel endpoint will be verified 154 // against the next expected transaction in the queue. A mismatch will cause a 155 // fatal assertion. On a match, MockController will send back the replies 156 // provided in the transaction. 157 void QueueCommandTransaction(CommandTransaction transaction); 158 void QueueCommandTransaction(const ByteBuffer& expected, 159 const std::vector<const ByteBuffer*>& replies, 160 ExpectationMetadata); 161 void QueueCommandTransaction(hci_spec::OpCode expected_opcode, 162 const std::vector<const ByteBuffer*>& replies, 163 ExpectationMetadata meta); 164 165 // Queues a transaction into the MockController's expected ACL data queue. 166 // Each packet received through the ACL data channel endpoint will be verified 167 // against the next expected transaction in the queue. A mismatch will cause a 168 // fatal assertion. On a match, MockController will send back the replies 169 // provided in the transaction. 170 void QueueDataTransaction(DataTransaction transaction); 171 void QueueDataTransaction(const ByteBuffer& expected, 172 const std::vector<const ByteBuffer*>& replies, 173 ExpectationMetadata meta); 174 175 // Queues a transaction into the MockController's expected SCO packet queue. 176 // Each packet received through the SCO data channel endpoint will be verified 177 // against the next expected transaction in the queue. A mismatch will cause a 178 // fatal assertion. 179 void QueueScoTransaction(const ByteBuffer& expected, 180 ExpectationMetadata meta); 181 182 // Returns true iff all transactions queued with QueueScoTransaction() have 183 // been received. 184 bool AllExpectedScoPacketsSent() const; 185 186 // Returns true iff all transactions queued with QueueDataTransaction() have 187 // been received. 188 bool AllExpectedDataPacketsSent() const; 189 190 // Returns true iff all transactions queued with QueueCommandTransaction() 191 // have been received. 192 bool AllExpectedCommandPacketsSent() const; 193 194 // Callback to invoke when a packet is received over the data channel. Care 195 // should be taken to ensure that a callback with a reference to test case 196 // variables is not invoked when tearing down. 197 using DataCallback = fit::function<void(const ByteBuffer& packet)>; 198 void SetDataCallback(DataCallback callback); 199 void ClearDataCallback(); 200 201 // Callback invoked when a transaction completes. Care should be taken to 202 // ensure that a callback with a reference to test case variables is not 203 // invoked when tearing down. 204 using TransactionCallback = fit::function<void(const ByteBuffer& rx)>; 205 void SetTransactionCallback(TransactionCallback callback); 206 void SetTransactionCallback(fit::closure callback); 207 void ClearTransactionCallback(); 208 209 private: 210 void OnCommandReceived(const ByteBuffer& data); 211 void OnACLDataPacketReceived(const ByteBuffer& acl_data_packet); 212 void OnScoDataPacketReceived(const ByteBuffer& sco_data_packet); 213 214 // Controller overrides: 215 void SendCommand(pw::span<const std::byte> data) override; 216 void SendAclData(pw::span<const std::byte> data) override; 217 void SendScoData(pw::span<const std::byte> data) override; 218 219 std::queue<CommandTransaction> cmd_transactions_; 220 std::queue<DataTransaction> data_transactions_; 221 std::queue<ScoTransaction> sco_transactions_; 222 DataCallback data_callback_; 223 TransactionCallback transaction_callback_; 224 225 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(MockController); 226 }; 227 228 } // namespace bt::testing 229