| // 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 "socket_factory.h" |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| |
| #include <memory> |
| #include <type_traits> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/l2cap/channel.h" |
| #include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel.h" |
| #include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap_defs.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sco/sco_connection.h" |
| |
| namespace bt::socket { |
| namespace { |
| |
| // We'll test the template just for L2CAP channels. |
| using FactoryT = SocketFactory<l2cap::Channel>; |
| |
| constexpr l2cap::ChannelId kDynamicChannelIdMin = 0x0040; |
| constexpr l2cap::ChannelId kRemoteChannelId = 0x0050; |
| constexpr hci_spec::ConnectionHandle kDefaultConnectionHandle = 0x0001; |
| constexpr hci_spec::ConnectionHandle kAnotherConnectionHandle = 0x0002; |
| |
| class SocketFactoryTest : public ::testing::Test { |
| public: |
| SocketFactoryTest() : loop_(&kAsyncLoopConfigAttachToCurrentThread) { |
| EXPECT_EQ(ASYNC_LOOP_RUNNABLE, loop_.GetState()); |
| channel_ = fbl::MakeRefCounted<l2cap::testing::FakeChannel>( |
| kDynamicChannelIdMin, kRemoteChannelId, kDefaultConnectionHandle, bt::LinkType::kACL); |
| EXPECT_TRUE(channel_); |
| } |
| |
| void TearDown() { |
| // Process any pending events, to tickle any use-after-free bugs. |
| RunLoopUntilIdle(); |
| } |
| |
| protected: |
| fbl::RefPtr<l2cap::testing::FakeChannel> channel() { return channel_; } |
| async_dispatcher_t* dispatcher() { return loop_.dispatcher(); } |
| void RunLoopUntilIdle() { loop_.RunUntilIdle(); } |
| |
| private: |
| async::Loop loop_; |
| fbl::RefPtr<l2cap::testing::FakeChannel> channel_; |
| }; |
| |
| TEST_F(SocketFactoryTest, TemplatesCompile) { |
| socket::SocketFactory<l2cap::Channel> l2cap_factory; |
| socket::SocketFactory<sco::ScoConnection> sco_factory; |
| } |
| |
| TEST_F(SocketFactoryTest, CanCreateSocket) { |
| FactoryT socket_factory; |
| EXPECT_TRUE(socket_factory.MakeSocketForChannel(channel())); |
| } |
| |
| TEST_F(SocketFactoryTest, SocketCreationFailsIfChannelIsNullptr) { |
| FactoryT socket_factory; |
| EXPECT_FALSE(socket_factory.MakeSocketForChannel(nullptr)); |
| } |
| |
| TEST_F(SocketFactoryTest, SocketCreationFailsIfChannelAlreadyHasASocket) { |
| FactoryT socket_factory; |
| zx::socket socket = socket_factory.MakeSocketForChannel(channel()); |
| ASSERT_TRUE(socket); |
| |
| EXPECT_FALSE(socket_factory.MakeSocketForChannel(channel())); |
| } |
| |
| TEST_F(SocketFactoryTest, SocketCreationFailsIfChannelActivationFails) { |
| channel()->set_activate_fails(true); |
| EXPECT_FALSE(FactoryT().MakeSocketForChannel(channel())); |
| } |
| |
| TEST_F(SocketFactoryTest, CanCreateSocketForNewChannelWithRecycledId) { |
| FactoryT socket_factory; |
| auto original_channel = fbl::MakeRefCounted<l2cap::testing::FakeChannel>( |
| kDynamicChannelIdMin + 1, kRemoteChannelId, kDefaultConnectionHandle, bt::LinkType::kACL); |
| zx::socket socket = socket_factory.MakeSocketForChannel(original_channel); |
| ASSERT_TRUE(socket); |
| original_channel->Close(); |
| RunLoopUntilIdle(); // Process any events related to channel closure. |
| |
| auto new_channel = fbl::MakeRefCounted<l2cap::testing::FakeChannel>( |
| kDynamicChannelIdMin + 1, kRemoteChannelId, kDefaultConnectionHandle, bt::LinkType::kACL); |
| EXPECT_TRUE(socket_factory.MakeSocketForChannel(new_channel)); |
| } |
| |
| TEST_F(SocketFactoryTest, DestructionWithActiveRelayDoesNotCrash) { |
| FactoryT socket_factory; |
| zx::socket socket = socket_factory.MakeSocketForChannel(channel()); |
| ASSERT_TRUE(socket); |
| // |socket_factory| is destroyed implicitly. |
| } |
| |
| TEST_F(SocketFactoryTest, DestructionAfterDeactivatingRelayDoesNotCrash) { |
| FactoryT socket_factory; |
| zx::socket socket = socket_factory.MakeSocketForChannel(channel()); |
| ASSERT_TRUE(socket); |
| channel()->Close(); |
| RunLoopUntilIdle(); // Process any events related to channel closure. |
| // |socket_factory| is destroyed implicitly. |
| } |
| |
| TEST_F(SocketFactoryTest, SameChannelIdDifferentHandles) { |
| FactoryT socket_factory; |
| EXPECT_TRUE(socket_factory.MakeSocketForChannel(channel())); |
| auto another_channel = fbl::MakeRefCounted<l2cap::testing::FakeChannel>( |
| kDynamicChannelIdMin, kRemoteChannelId, kAnotherConnectionHandle, bt::LinkType::kACL); |
| EXPECT_TRUE(socket_factory.MakeSocketForChannel(another_channel)); |
| } |
| |
| } // namespace |
| } // namespace bt::socket |