blob: 5b51880cc5bd54b5f0cf21adebff0a89313a680b [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.
#include "garnet/drivers/bluetooth/lib/l2cap/fake_signaling_channel.h"
#include "garnet/drivers/bluetooth/lib/common/test_helpers.h"
#include "lib/gtest/test_loop_fixture.h"
namespace btlib {
namespace l2cap {
namespace internal {
namespace testing {
namespace {
// These classes bind the response that the request handlers are expected to
// send back. These also serve as the actual Responder implementation that the
// request handler under test will see. These roles may need to be decoupled if
// request handlers have to be tested for multiple responses to each request.
class Expecter : public SignalingChannel::Responder {
public:
void Send(const common::ByteBuffer& rsp_payload) override {
FAIL() << "Unexpected local response " << rsp_payload.AsString();
}
void RejectNotUnderstood() override {
FAIL() << "Unexpected local rejection, \"Not Understood\"";
}
void RejectInvalidChannelId(ChannelId local_cid,
ChannelId remote_cid) override {
FAIL() << fxl::StringPrintf(
"Unexpected local rejection, \"Invalid Channel ID\" local: %#.4x "
"remote: %#.4x",
local_cid, remote_cid);
}
bool called() const { return called_; }
protected:
void set_called(bool called) { called_ = called; }
private:
bool called_ = false;
};
class ResponseExpecter : public Expecter {
public:
explicit ResponseExpecter(const common::ByteBuffer& expected_rsp)
: expected_rsp_(expected_rsp) {}
void Send(const common::ByteBuffer& rsp_payload) override {
set_called(true);
EXPECT_TRUE(common::ContainersEqual(expected_rsp_, rsp_payload));
}
private:
const common::ByteBuffer& expected_rsp_;
};
class RejectNotUnderstoodExpecter : public Expecter {
public:
void RejectNotUnderstood() override { set_called(true); }
};
class RejectInvalidChannelIdExpecter : public Expecter {
public:
RejectInvalidChannelIdExpecter(ChannelId local_cid, ChannelId remote_cid)
: local_cid_(local_cid), remote_cid_(remote_cid) {}
void RejectInvalidChannelId(ChannelId local_cid,
ChannelId remote_cid) override {
set_called(true);
EXPECT_EQ(local_cid_, local_cid);
EXPECT_EQ(remote_cid_, remote_cid);
}
private:
const ChannelId local_cid_;
const ChannelId remote_cid_;
};
} // namespace
FakeSignalingChannel::FakeSignalingChannel(async_dispatcher_t* dispatcher)
: dispatcher_(dispatcher) {
ZX_DEBUG_ASSERT(dispatcher_);
}
bool FakeSignalingChannel::SendRequest(CommandCode req_code,
const common::ByteBuffer& payload,
SignalingChannel::ResponseHandler cb) {
if (expected_transaction_index_ >= transactions_.size()) {
return false;
}
const Transaction& transaction = transactions_[expected_transaction_index_];
EXPECT_EQ(transaction.request_code, req_code);
EXPECT_TRUE(common::ContainersEqual(transaction.req_payload, payload));
// Simulate the remote's response(s)
async::PostTask(dispatcher_, [this, cb = std::move(cb),
index = expected_transaction_index_]() {
size_t responses_handled = 0;
const Transaction& transaction = transactions_[index];
for (auto& response : transaction.responses) {
responses_handled++;
if (!cb(response.first, response.second)) {
break;
}
}
ASSERT_EQ(transaction.responses.size(), responses_handled);
});
expected_transaction_index_++;
return (transaction.request_code == req_code);
}
void FakeSignalingChannel::ServeRequest(CommandCode req_code,
SignalingChannel::RequestDelegate cb) {
request_handlers_[req_code] = std::move(cb);
}
void FakeSignalingChannel::ReceiveExpect(
CommandCode req_code, const common::ByteBuffer& req_payload,
const common::ByteBuffer& rsp_payload) {
ResponseExpecter expecter(rsp_payload);
ReceiveExpectInternal(req_code, req_payload, &expecter);
}
void FakeSignalingChannel::ReceiveExpectRejectNotUnderstood(
CommandCode req_code, const common::ByteBuffer& req_payload) {
RejectNotUnderstoodExpecter expecter;
ReceiveExpectInternal(req_code, req_payload, &expecter);
}
void FakeSignalingChannel::ReceiveExpectRejectInvalidChannelId(
CommandCode req_code, const common::ByteBuffer& req_payload,
ChannelId local_cid, ChannelId remote_cid) {
RejectInvalidChannelIdExpecter expecter(local_cid, remote_cid);
ReceiveExpectInternal(req_code, req_payload, &expecter);
}
// Test evaluator for inbound requests with type-erased, bound expected requests
void FakeSignalingChannel::ReceiveExpectInternal(
CommandCode req_code, const common::ByteBuffer& req_payload,
Responder* fake_responder) {
auto iter = request_handlers_.find(req_code);
ASSERT_NE(request_handlers_.end(), iter);
// Invoke delegate assigned for this request type
iter->second(req_payload, fake_responder);
EXPECT_TRUE(static_cast<Expecter*>(fake_responder)->called());
}
} // namespace testing
} // namespace internal
} // namespace l2cap
} // namespace btlib