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 <unordered_map> 19 #include <vector> 20 21 #include "pw_bluetooth_sapphire/internal/host/l2cap/signaling_channel.h" 22 23 // Helper for FakeSignalingChannel::AddOutbound to add file and line numbers of 24 // the test call site that expected the command, and to reduce one level of 25 // braces in the responses. |fake_sig| should be a FakeSignalingChannel lvalue. 26 #define EXPECT_OUTBOUND_REQ(fake_sig, req_code, req_payload, ...) \ 27 (fake_sig).AddOutbound( \ 28 __FILE__, __LINE__, req_code, req_payload, {__VA_ARGS__}) 29 30 namespace bt::l2cap::internal::testing { 31 32 // Can be injected into internal L2CAP tests to drive fake interactions over the 33 // signaling channels with remote peers (in both directions). Expectations for 34 // inbound and outbound expected transactions are not synchronized. 35 class FakeSignalingChannel : public SignalingChannelInterface { 36 public: 37 using TransactionId = size_t; 38 39 // Simulated response's command code and payload. 40 using Response = std::pair<Status, BufferView>; 41 42 // |dispatcher| is the test message loop's dispatcher 43 explicit FakeSignalingChannel(pw::async::Dispatcher& pw_dispatcher); 44 ~FakeSignalingChannel() override; 45 46 // SignalingChannelInterface overrides 47 bool SendRequest(CommandCode req_code, 48 const ByteBuffer& payload, 49 ResponseHandler cb) override; 50 void ServeRequest(CommandCode req_code, RequestDelegate cb) override; 51 52 // Add an expected outbound request, which FakeSignalingChannel will respond 53 // to with the contents of |responses|. The request's contents will be 54 // expected to match |req_code| and |req_payload|. The request's response 55 // handler will be expected to handle all responses provided here. 56 // Returns a handle that can be used to provide additional responses with 57 // |ReceiveResponses|. |file| and |line| will be used to trace test failures. 58 TransactionId AddOutbound(const char* file, 59 int line, 60 CommandCode req_code, 61 BufferView req_payload, 62 std::vector<Response> responses); 63 64 // Receive additional responses to an already received request. 65 void ReceiveResponses(TransactionId id, 66 const std::vector<Response>& responses); 67 68 // Simulate reception of an inbound request with |req_code| and |req_payload|, 69 // then expect a corresponding outbound response with payload |rsp_payload|. 70 void ReceiveExpect(CommandCode req_code, 71 const ByteBuffer& req_payload, 72 const ByteBuffer& rsp_payload); 73 74 // Simulate reception of an inbound request with |req_code| and |req_payload|, 75 // then expect a matching rejection with the Not Understood reason. 76 void ReceiveExpectRejectNotUnderstood(CommandCode req_code, 77 const ByteBuffer& req_payload); 78 79 // Simulate reception of an inbound request with |req_code| and |req_payload|, 80 // then expect a matching rejection with the Invalid Channel ID reason and the 81 // rejected IDs |local_cid| and |remote_cid|. 82 void ReceiveExpectRejectInvalidChannelId(CommandCode req_code, 83 const ByteBuffer& req_payload, 84 ChannelId local_cid, 85 ChannelId remote_cid); 86 87 private: 88 // Expected outbound request and response(s) that this fake sends back 89 struct Transaction { 90 const char* const file; 91 const int line; 92 const CommandCode request_code; 93 const BufferView req_payload; 94 const std::vector<std::pair<Status, BufferView>> responses; 95 96 // Assigned when the request is actually sent 97 SignalingChannel::ResponseHandler response_callback = nullptr; 98 99 // Does not include responses handled in |ReceiveResponses|. 100 size_t responses_handled = 0UL; 101 }; 102 103 // Simulate reception of |responses|, calling |transaction.response_callback| 104 // on each response until it returns false. Returns the number of invocations. 105 size_t TriggerResponses(const Transaction& transaction, 106 const std::vector<Response>& responses); 107 108 // Test a previously-registered request handler by simulating an inbound 109 // request of |req_code| and |req_payload|. The test will assert-fail if no 110 // handler had been registered with |ServeRequest|. |fake_responder| will be 111 // generated internally based on the kind of reply that the handler is 112 // expected to send and is passed to the handler-under-test. The test will 113 // fail if no reply at all is sent. 114 void ReceiveExpectInternal(CommandCode req_code, 115 const ByteBuffer& req_payload, 116 Responder* fake_responder); 117 118 // Expected outbound transactions 119 std::vector<Transaction> transactions_; 120 121 // Index of current outbound transaction expected through SendRequest 122 size_t expected_transaction_index_ = 0UL; 123 124 // Registered inbound request delegates 125 std::unordered_map<CommandCode, RequestDelegate> request_handlers_; 126 127 // Test message loop dispatcher 128 pw::async::HeapDispatcher heap_dispatcher_; 129 }; 130 131 } // namespace bt::l2cap::internal::testing 132