| // 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" |
| #include "src/connectivity/bluetooth/core/bt-host/l2cap/types.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()); } |
| |
| // Returns true if and only if a link identified by |handle| has been added and connected. |
| [[nodiscard]] bool IsLinkConnected(hci::ConnectionHandle handle) const; |
| |
| // 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, l2cap::ChannelParameters params); |
| |
| // Triggers the creation of an inbound dynamic channel on the given link. The |
| // channels created will be provided to handlers passed to RegisterService. |
| // Returns false if unable to create the channel. |
| bool TriggerInboundL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, l2cap::ChannelId id, |
| l2cap::ChannelId remote_id, uint16_t tx_mtu = l2cap::kDefaultMTU); |
| |
| // Triggers a link error callback on the given link. |
| void TriggerLinkError(hci::ConnectionHandle handle); |
| |
| // Domain overrides: |
| void AddACLConnection(hci::ConnectionHandle handle, hci::Connection::Role role, |
| l2cap::LinkErrorCallback link_error_callback, |
| l2cap::SecurityUpgradeCallback security_callback) 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) override; |
| void RemoveConnection(hci::ConnectionHandle handle) override; |
| void AssignLinkSecurityProperties(hci::ConnectionHandle handle, |
| sm::SecurityProperties security) override; |
| |
| // Immediately posts accept on |dispatcher|. |
| void RequestConnectionParameterUpdate(hci::ConnectionHandle handle, |
| hci::LEPreferredConnectionParameters params, |
| l2cap::ConnectionParameterUpdateRequestCallback request_cb, |
| async_dispatcher_t* dispatcher) override; |
| void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| l2cap::ChannelParameters params, l2cap::ChannelCallback cb, |
| async_dispatcher_t* dispatcher) override; |
| void OpenL2capChannel(hci::ConnectionHandle handle, l2cap::PSM psm, |
| l2cap::ChannelParameters params, SocketCallback socket_callback, |
| async_dispatcher_t* dispatcher) override; |
| void RegisterService(l2cap::PSM psm, l2cap::ChannelParameters params, |
| l2cap::ChannelCallback channel_callback, |
| async_dispatcher_t* dispatcher) override; |
| void RegisterService(l2cap::PSM psm, l2cap::ChannelParameters params, |
| 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); } |
| void set_simulate_open_channel_failure(bool simulate_failure) { |
| simulate_open_channel_failure_ = simulate_failure; |
| } |
| |
| // Called when RequestConnectionParameterUpdate is called. |request_cb| will be called with return |
| // value. Defaults to returning true if not set. |
| using ConnectionParameterUpdateRequestResponder = |
| fit::function<bool(hci::ConnectionHandle, hci::LEPreferredConnectionParameters)>; |
| void set_connection_parameter_update_request_responder( |
| ConnectionParameterUpdateRequestResponder responder) { |
| connection_parameter_update_request_responder_ = std::move(responder); |
| } |
| |
| private: |
| friend class fbl::RefPtr<FakeDomain>; |
| |
| // TODO(armansito): Consider moving the following logic into an internal fake |
| // that is L2CAP-specific. |
| struct ChannelData { |
| l2cap::ChannelId local_id; |
| l2cap::ChannelId remote_id; |
| l2cap::ChannelParameters params; |
| }; |
| 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<ChannelData>> 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); |
| |
| fbl::RefPtr<l2cap::testing::FakeChannel> OpenFakeChannel( |
| LinkData* link, l2cap::ChannelId id, l2cap::ChannelId remote_id, |
| l2cap::ChannelInfo info = l2cap::ChannelInfo::MakeBasicMode(l2cap::kDefaultMTU, |
| l2cap::kDefaultMTU)); |
| 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); |
| |
| std::unordered_map<hci::ConnectionHandle, LinkData> links_; |
| FakeChannelCallback chan_cb_; |
| bool simulate_open_channel_failure_ = false; |
| |
| ConnectionParameterUpdateRequestResponder connection_parameter_update_request_responder_; |
| |
| using ServiceInfo = l2cap::ServiceInfo<l2cap::ChannelCallback>; |
| std::unordered_map<l2cap::PSM, ServiceInfo> registered_services_; |
| |
| // 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_ |