blob: f979cb2a6b92b38ec816504a7a8d1b6eb03337c8 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_FAKE_SIGNALING_CHANNEL_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_FAKE_SIGNALING_CHANNEL_H_
#include <lib/async/cpp/task.h>
#include <unordered_map>
#include <vector>
#include "src/connectivity/bluetooth/core/bt-host/l2cap/signaling_channel.h"
// Helper for FakeSignalingChannel::AddOutbound to add file and line numbers of
// the test call site that expected the command, and to reduce one level of
// braces in the responses. |fake_sig| should be a FakeSignalingChannel lvalue.
#define EXPECT_OUTBOUND_REQ(fake_sig, req_code, req_payload, ...) \
(fake_sig).AddOutbound(__FILE__, __LINE__, req_code, req_payload, \
{__VA_ARGS__})
namespace bt {
namespace l2cap {
namespace internal {
namespace testing {
// Can be injected into internal L2CAP tests to drive fake interactions over the
// signaling channels with remote peers (in both directions). Expectations for
// inbound and outbound expected transactions are not synchronized.
class FakeSignalingChannel : public SignalingChannelInterface {
public:
using TransactionId = size_t;
// Simulated response's command code and payload.
using Response = std::pair<Status, BufferView>;
// |dispatcher| is the test message loop's dispatcher
explicit FakeSignalingChannel(async_dispatcher_t* dispatcher);
~FakeSignalingChannel() override;
// SignalingChannelInterface overrides
bool SendRequest(CommandCode req_code, const ByteBuffer& payload,
ResponseHandler cb) override;
void ServeRequest(CommandCode req_code, RequestDelegate cb) override;
// Add an expected outbound request, which FakeSignalingChannel will respond
// to with the contents of |responses|. The request's contents will be
// expected to match |req_code| and |req_payload|. The request's response
// handler will be expected to handle all responses provided here.
// Returns a handle that can be used to provide additional responses with
// |ReceiveResponses|. |file| and |line| will be used to trace test failures.
TransactionId AddOutbound(const char* file, int line, CommandCode req_code,
BufferView req_payload,
std::vector<Response> responses);
// Receive additional responses to an already received request.
void ReceiveResponses(TransactionId id,
const std::vector<Response>& responses);
// Simulate reception of an inbound request with |req_code| and |req_payload|,
// then expect a corresponding outbound response with payload |rsp_payload|.
void ReceiveExpect(CommandCode req_code, const ByteBuffer& req_payload,
const ByteBuffer& rsp_payload);
// Simulate reception of an inbound request with |req_code| and |req_payload|,
// then expect a matching rejection with the Not Understood reason.
void ReceiveExpectRejectNotUnderstood(CommandCode req_code,
const ByteBuffer& req_payload);
// Simulate reception of an inbound request with |req_code| and |req_payload|,
// then expect a matching rejection with the Invalid Channel ID reason and the
// rejected IDs |local_cid| and |remote_cid|.
void ReceiveExpectRejectInvalidChannelId(CommandCode req_code,
const ByteBuffer& req_payload,
ChannelId local_cid,
ChannelId remote_cid);
private:
// Expected outbound request and response(s) that this fake sends back
struct Transaction {
const char* const file;
const int line;
const CommandCode request_code;
const BufferView req_payload;
const std::vector<std::pair<Status, BufferView>> responses;
// Assigned when the request is actually sent
SignalingChannel::ResponseHandler response_callback = nullptr;
// Does not include responses handled in |ReceiveResponses|.
size_t responses_handled = 0UL;
};
// Simulate reception of |responses|, calling |transaction.response_callback|
// on each response until it returns false. Returns the number of invocations.
size_t TriggerResponses(const Transaction& transaction,
const std::vector<Response>& responses);
// Test a previously-registered request handler by simulating an inbound
// request of |req_code| and |req_payload|. The test will assert-fail if no
// handler had been registered with |ServeRequest|. |fake_responder| will be
// generated internally based on the kind of reply that the handler is
// expected to send and is passed to the handler-under-test. The test will
// fail if no reply at all is sent.
void ReceiveExpectInternal(CommandCode req_code,
const ByteBuffer& req_payload,
Responder* fake_responder);
// Test message loop dispatcher
async_dispatcher_t* const dispatcher_;
// Expected outbound transactions
std::vector<Transaction> transactions_;
// Index of current outbound transaction expected through SendRequest
size_t expected_transaction_index_ = 0UL;
// Registered inbound request delegates
std::unordered_map<CommandCode, RequestDelegate> request_handlers_;
};
} // namespace testing
} // namespace internal
} // namespace l2cap
} // namespace bt
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_FAKE_SIGNALING_CHANNEL_H_