blob: 559acfab444acb951373d3e41d3cdc5b8aee9a5b [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_DATA_FAKE_DOMAIN_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_DATA_FAKE_DOMAIN_H_
#include "src/connectivity/bluetooth/core/bt-host/data/domain.h"
#include "src/connectivity/bluetooth/core/bt-host/data/socket_factory.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/channel.h"
namespace bt {
namespace l2cap {
namespace testing {
class FakeChannel;
} // namespace testing
} // namespace l2cap
namespace data {
namespace testing {
// This is a fake version of the Domain class that can be injected into other
// layers for unit testing.
class FakeDomain final : public Domain {
public:
inline static fbl::RefPtr<FakeDomain> Create() {
return fbl::AdoptRef(new FakeDomain());
}
// Triggers a LE connection parameter update callback on the given link.
void TriggerLEConnectionParameterUpdate(
hci::ConnectionHandle handle,
const hci::LEPreferredConnectionParameters& params);
// Sets up the expectation that an outbound dynamic channel will be opened
// on the given link. Each call will expect one dyanmic channel to be
// created. If a call to OpenL2capChannel is made without expectation, it
// will assert.
// Multiple expectations for the same PSM should be queued in FIFO order.
void ExpectOutboundL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
l2cap::ChannelId id,
l2cap::ChannelId remote_id);
// Triggers the creation of an inbound dynamic channel on the given link. The
// channels created will be provided to handlers passed to RegisterService.
void TriggerInboundL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
l2cap::ChannelId id,
l2cap::ChannelId remote_id);
// Triggers a link error callback on the given link.
void TriggerLinkError(hci::ConnectionHandle handle);
// Domain overrides:
void Initialize() override;
void ShutDown() override;
void AddACLConnection(hci::ConnectionHandle handle,
hci::Connection::Role role,
l2cap::LinkErrorCallback link_error_callback,
l2cap::SecurityUpgradeCallback security_callback,
async_dispatcher_t* dispatcher) override;
void AddLEConnection(
hci::ConnectionHandle handle, hci::Connection::Role role,
l2cap::LinkErrorCallback link_error_callback,
l2cap::LEConnectionParameterUpdateCallback conn_param_callback,
l2cap::LEFixedChannelsCallback channel_callback,
l2cap::SecurityUpgradeCallback security_callback,
async_dispatcher_t* dispatcher) override;
void RemoveConnection(hci::ConnectionHandle handle) override;
void AssignLinkSecurityProperties(hci::ConnectionHandle handle,
sm::SecurityProperties security) override;
void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
l2cap::ChannelCallback cb,
async_dispatcher_t* dispatcher) override;
void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm,
SocketCallback socket_callback,
async_dispatcher_t* dispatcher) override;
void RegisterService(l2cap::PSM psm, l2cap::ChannelCallback channel_callback,
async_dispatcher_t* dispatcher) override;
void RegisterService(l2cap::PSM psm, SocketCallback socket_callback,
async_dispatcher_t* dispatcher) override;
void UnregisterService(l2cap::PSM psm) override;
// Called when a new channel gets opened. Tests can use this to obtain a
// reference to all channels.
using FakeChannelCallback =
fit::function<void(fbl::RefPtr<l2cap::testing::FakeChannel>)>;
void set_channel_callback(FakeChannelCallback callback) {
chan_cb_ = std::move(callback);
}
private:
friend class fbl::RefPtr<FakeDomain>;
// TODO(armansito): Consider moving the following logic into an internal fake
// that is L2CAP-specific.
// Each one of these pairs is a local id and remote id of the channel that
// will be returned.
using ChannelIdPair = std::pair<l2cap::ChannelId, l2cap::ChannelId>;
struct LinkData {
// Expectations on links can be created before they are connected.
bool connected;
hci::ConnectionHandle handle;
hci::Connection::Role role;
hci::Connection::LinkType type;
async_dispatcher_t* dispatcher;
// Dual-mode callbacks
l2cap::LinkErrorCallback link_error_cb;
std::unordered_map<l2cap::PSM, std::queue<ChannelIdPair>>
expected_outbound_conns;
// LE-only callbacks
l2cap::LEConnectionParameterUpdateCallback le_conn_param_cb;
};
FakeDomain() = default;
~FakeDomain() override;
LinkData* RegisterInternal(hci::ConnectionHandle handle,
hci::Connection::Role role,
hci::Connection::LinkType link_type,
l2cap::LinkErrorCallback link_error_callback,
async_dispatcher_t* dispatcher);
fbl::RefPtr<l2cap::testing::FakeChannel> OpenFakeChannel(
LinkData* link, l2cap::ChannelId id, l2cap::ChannelId remote_id);
fbl::RefPtr<l2cap::testing::FakeChannel> OpenFakeFixedChannel(
LinkData* link, l2cap::ChannelId id);
// Gets the link data for |handle|, creating it if necessary.
LinkData& GetLinkData(hci::ConnectionHandle handle);
// Gets the link data for |handle|. Asserts if the link is not connected
// yet.
LinkData& ConnectedLinkData(hci::ConnectionHandle handle);
bool initialized_ = false;
std::unordered_map<hci::ConnectionHandle, LinkData> links_;
FakeChannelCallback chan_cb_;
using ChannelDelivery =
std::pair<l2cap::ChannelCallback, async_dispatcher_t*>;
std::unordered_map<l2cap::PSM, ChannelDelivery> inbound_conn_cbs_;
// Makes sockets for RegisterService
internal::SocketFactory<l2cap::Channel> socket_factory_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeDomain);
};
} // namespace testing
} // namespace data
} // namespace bt
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_DATA_FAKE_DOMAIN_H_