| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "device/bluetooth/floss/floss_socket_manager.h" |
| |
| #include <utility> |
| |
| #include "base/run_loop.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "dbus/bus.h" |
| #include "dbus/message.h" |
| #include "dbus/mock_bus.h" |
| #include "dbus/mock_exported_object.h" |
| #include "dbus/mock_object_proxy.h" |
| #include "dbus/object_path.h" |
| #include "device/bluetooth/floss/floss_dbus_client.h" |
| #include "device/bluetooth/floss/floss_manager_client.h" |
| #include "device/bluetooth/floss/test_helpers.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| using testing::_; |
| |
| } // namespace |
| |
| namespace floss { |
| |
| using Security = FlossSocketManager::Security; |
| using BtifStatus = FlossDBusClient::BtifStatus; |
| |
| class FlossSocketManagerTest : public testing::Test { |
| public: |
| FlossSocketManagerTest() = default; |
| |
| base::Version GetCurrVersion() { |
| return floss::version::GetMaximalSupportedVersion(); |
| } |
| |
| void SetUpMocks() { |
| adapter_path_ = FlossDBusClient::GenerateAdapterPath(adapter_index_); |
| sockmgr_proxy_ = base::MakeRefCounted<::dbus::MockObjectProxy>( |
| bus_.get(), kSocketManagerInterface, adapter_path_); |
| exported_callbacks_ = base::MakeRefCounted<::dbus::MockExportedObject>( |
| bus_.get(), |
| ::dbus::ObjectPath(FlossSocketManager::kExportedCallbacksPath)); |
| |
| EXPECT_CALL(*bus_.get(), |
| GetObjectProxy(kSocketManagerInterface, adapter_path_)) |
| .WillRepeatedly(::testing::Return(sockmgr_proxy_.get())); |
| EXPECT_CALL(*bus_.get(), GetExportedObject) |
| .WillRepeatedly(::testing::Return(exported_callbacks_.get())); |
| |
| // Make sure we export all callbacks. This will need to be updated once new |
| // callbacks are added. |
| EXPECT_CALL(*exported_callbacks_.get(), ExportMethod).Times(4); |
| |
| // Handle method calls on the object proxy. |
| ON_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse( |
| HasMemberOf(socket_manager::kRegisterCallback), _, _)) |
| .WillByDefault( |
| Invoke(this, &FlossSocketManagerTest::HandleRegisterCallback)); |
| } |
| |
| void SetUp() override { |
| ::dbus::Bus::Options options; |
| options.bus_type = ::dbus::Bus::BusType::SYSTEM; |
| bus_ = base::MakeRefCounted<::dbus::MockBus>(std::move(options)); |
| sockmgr_ = FlossSocketManager::Create(); |
| |
| SetUpMocks(); |
| } |
| |
| void TearDown() override { |
| // Expected call to UnregisterCallback when client is destroyed |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse( |
| HasMemberOf(socket_manager::kUnregisterCallback), _, _)) |
| .WillOnce([this](::dbus::MethodCall* method_call, int timeout_ms, |
| ::dbus::ObjectProxy::ResponseOrErrorCallback cb) { |
| dbus::MessageReader msg(method_call); |
| // D-Bus method call should have 1 parameter. |
| uint32_t param1; |
| ASSERT_TRUE(FlossDBusClient::ReadAllDBusParams(&msg, ¶m1)); |
| EXPECT_EQ(this->callback_id_ctr_ - 1, param1); |
| EXPECT_FALSE(msg.HasMoreData()); |
| }); |
| |
| // Clean up the socket manager first to get rid of all references to various |
| // buses, object proxies, etc. |
| sockmgr_.reset(); |
| } |
| |
| void Init() { |
| sockmgr_->Init(bus_.get(), kSocketManagerInterface, adapter_index_, |
| GetCurrVersion(), base::DoNothing()); |
| } |
| |
| void SetupListeningSocket() { |
| // First listen on something. This will push the socket callbacks into a |
| // map. |
| EXPECT_CALL( |
| *sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse( |
| HasMemberOf(socket_manager::kListenUsingRfcommWithServiceRecord), _, |
| _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| sockmgr_->ListenUsingRfcomm( |
| "Foo", device::BluetoothUUID("F00D"), Security::kSecure, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionStateChanged, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionAccepted, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // We should call accept here but that state is tracked on the daemon side. |
| // Opting not to simply because we have it mocked away... |
| } |
| |
| void HandleRegisterCallback(::dbus::MethodCall* method_call, |
| int timeout_ms, |
| ::dbus::ObjectProxy::ResponseOrErrorCallback cb) { |
| auto response = ::dbus::Response::CreateEmpty(); |
| ::dbus::MessageWriter msg(response.get()); |
| FlossDBusClient::WriteAllDBusParams(&msg, callback_id_ctr_); |
| |
| // Increment callback counter for next call. |
| callback_id_ctr_++; |
| |
| std::move(cb).Run(response.get(), nullptr); |
| } |
| |
| void HandleReturnSocketResult( |
| ::dbus::MethodCall* method_call, |
| int timeout_ms, |
| ::dbus::ObjectProxy::ResponseOrErrorCallback cb) { |
| auto response = ::dbus::Response::CreateEmpty(); |
| ::dbus::MessageWriter msg(response.get()); |
| FlossSocketManager::SocketResult result = { |
| .status = BtifStatus::kSuccess, |
| .id = socket_id_ctr_, |
| }; |
| FlossDBusClient::WriteAllDBusParams(&msg, result); |
| |
| socket_id_ctr_++; |
| |
| std::move(cb).Run(response.get(), nullptr); |
| } |
| |
| void HandleReturnSuccess(::dbus::MethodCall* method_call, |
| int timeout_ms, |
| ::dbus::ObjectProxy::ResponseOrErrorCallback cb) { |
| auto response = ::dbus::Response::CreateEmpty(); |
| ::dbus::MessageWriter msg(response.get()); |
| |
| BtifStatus status = BtifStatus::kSuccess; |
| FlossDBusClient::WriteAllDBusParams(&msg, status); |
| |
| std::move(cb).Run(response.get(), nullptr); |
| } |
| |
| void SendOutgoingConnectionResult( |
| FlossSocketManager::SocketId id, |
| BtifStatus status, |
| const std::optional<FlossSocketManager::FlossSocket>& socket, |
| dbus::ExportedObject::ResponseSender response) { |
| dbus::MethodCall method_call(socket_manager::kCallbackInterface, |
| socket_manager::kOnOutgoingConnectionResult); |
| method_call.SetSerial(serial_++); |
| dbus::MessageWriter writer(&method_call); |
| FlossDBusClient::WriteAllDBusParams(&writer, id, status, socket); |
| |
| sockmgr_->OnOutgoingConnectionResult(&method_call, std::move(response)); |
| } |
| |
| void SendIncomingSocketReady( |
| const FlossSocketManager::FlossListeningSocket& server_socket, |
| BtifStatus status, |
| dbus::ExportedObject::ResponseSender response) { |
| dbus::MethodCall method_call(socket_manager::kCallbackInterface, |
| socket_manager::kOnIncomingSocketReady); |
| method_call.SetSerial(serial_++); |
| dbus::MessageWriter writer(&method_call); |
| FlossDBusClient::WriteAllDBusParams(&writer, server_socket, status); |
| |
| sockmgr_->OnIncomingSocketReady(&method_call, std::move(response)); |
| } |
| |
| void SendIncomingSocketClosed(FlossSocketManager::SocketId id, |
| BtifStatus status, |
| dbus::ExportedObject::ResponseSender response) { |
| dbus::MethodCall method_call(socket_manager::kCallbackInterface, |
| socket_manager::kOnIncomingSocketReady); |
| method_call.SetSerial(serial_++); |
| dbus::MessageWriter writer(&method_call); |
| FlossDBusClient::WriteAllDBusParams(&writer, id, status); |
| |
| sockmgr_->OnIncomingSocketClosed(&method_call, std::move(response)); |
| } |
| |
| void SendIncomingConnection(FlossSocketManager::SocketId id, |
| const FlossSocketManager::FlossSocket& socket, |
| dbus::ExportedObject::ResponseSender response) { |
| dbus::MethodCall method_call(socket_manager::kCallbackInterface, |
| socket_manager::kOnIncomingSocketReady); |
| method_call.SetSerial(serial_++); |
| dbus::MessageWriter writer(&method_call); |
| FlossDBusClient::WriteAllDBusParams(&writer, id, socket); |
| |
| sockmgr_->OnHandleIncomingConnection(&method_call, std::move(response)); |
| } |
| |
| void SockStatusCb(DBusResult<BtifStatus> result) { |
| if (!result.has_value()) { |
| last_status_ = BtifStatus::kFail; |
| } else { |
| last_status_ = *result; |
| } |
| } |
| |
| void SockConnectionStateChanged( |
| FlossSocketManager::ServerSocketState state, |
| FlossSocketManager::FlossListeningSocket socket, |
| BtifStatus status) { |
| last_state_ = state; |
| last_server_socket_ = socket; |
| last_status_ = status; |
| } |
| |
| void SockConnectionAccepted(FlossSocketManager::FlossSocket&& socket) { |
| last_incoming_socket_ = std::move(socket); |
| } |
| |
| void ExpectNormalResponse(std::unique_ptr<dbus::Response> response) { |
| EXPECT_NE(response->GetMessageType(), |
| dbus::Message::MessageType::MESSAGE_ERROR); |
| } |
| |
| int adapter_index_ = 2; |
| int serial_ = 1; |
| dbus::ObjectPath adapter_path_; |
| |
| FlossSocketManager::ServerSocketState last_state_; |
| FlossSocketManager::FlossListeningSocket last_server_socket_; |
| BtifStatus last_status_; |
| FlossSocketManager::FlossSocket last_incoming_socket_; |
| |
| uint32_t callback_id_ctr_ = 1; |
| uint64_t socket_id_ctr_ = 1; |
| |
| scoped_refptr<::dbus::MockBus> bus_; |
| scoped_refptr<::dbus::MockExportedObject> exported_callbacks_; |
| scoped_refptr<::dbus::MockObjectProxy> sockmgr_proxy_; |
| std::unique_ptr<FlossSocketManager> sockmgr_; |
| |
| base::test::TaskEnvironment task_environment_; |
| base::WeakPtrFactory<FlossSocketManagerTest> weak_ptr_factory_{this}; |
| }; |
| |
| // Tests for good path |
| |
| TEST_F(FlossSocketManagerTest, ListenOnSockets) { |
| Init(); |
| |
| std::map<std::string, Security> l2cap_apis = { |
| {socket_manager::kListenUsingInsecureL2capChannel, Security::kInsecure}, |
| {socket_manager::kListenUsingL2capChannel, Security::kSecure}, |
| }; |
| std::map<std::string, Security> l2cap_le_apis = { |
| {socket_manager::kListenUsingInsecureL2capLeChannel, Security::kInsecure}, |
| {socket_manager::kListenUsingL2capLeChannel, Security::kSecure}, |
| }; |
| std::map<std::string, Security> rfcomm_apis = { |
| {socket_manager::kListenUsingInsecureRfcommWithServiceRecord, |
| Security::kInsecure}, |
| {socket_manager::kListenUsingRfcommWithServiceRecord, Security::kSecure}, |
| }; |
| |
| // Exercise all security paths. |
| for (auto kv : l2cap_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| last_status_ = BtifStatus::kNotReady; |
| sockmgr_->ListenUsingL2cap( |
| kv.second, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionStateChanged, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionAccepted, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| } |
| for (auto kv : l2cap_le_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| last_status_ = BtifStatus::kNotReady; |
| sockmgr_->ListenUsingL2capLe( |
| kv.second, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionStateChanged, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionAccepted, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| } |
| |
| for (auto kv : rfcomm_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| last_status_ = BtifStatus::kNotReady; |
| sockmgr_->ListenUsingRfcomm( |
| "Foo", device::BluetoothUUID(), kv.second, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionStateChanged, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&FlossSocketManagerTest::SockConnectionAccepted, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| } |
| } |
| |
| TEST_F(FlossSocketManagerTest, ConnectToSockets) { |
| Init(); |
| |
| std::map<std::string, Security> l2cap_apis = { |
| {socket_manager::kCreateInsecureL2capChannel, Security::kInsecure}, |
| {socket_manager::kCreateL2capChannel, Security::kSecure}, |
| }; |
| |
| std::map<std::string, Security> l2cap_le_apis = { |
| {socket_manager::kCreateInsecureL2capLeChannel, Security::kInsecure}, |
| {socket_manager::kCreateL2capLeChannel, Security::kSecure}, |
| }; |
| |
| std::map<std::string, Security> rfcomm_apis = { |
| {socket_manager::kCreateInsecureRfcommSocketToServiceRecord, |
| Security::kInsecure}, |
| {socket_manager::kCreateRfcommSocketToServiceRecord, Security::kSecure}, |
| }; |
| |
| FlossDeviceId remote_device = { |
| .address = "00:11:22:33:44:55", |
| .name = "Remote device", |
| }; |
| |
| int psm = 42; |
| |
| device::BluetoothUUID uuid("f0de"); |
| |
| for (auto kv : l2cap_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| bool callback_completed = false; |
| BtifStatus callback_status = BtifStatus::kNotReady; |
| int found_psm = -1; |
| |
| sockmgr_->ConnectUsingL2cap( |
| remote_device, psm, kv.second, |
| base::BindOnce( |
| [](bool* complete, BtifStatus* cb_status, int* fpsm, |
| BtifStatus status, |
| std::optional<FlossSocketManager::FlossSocket>&& socket) { |
| *complete = true; |
| *cb_status = status; |
| if (socket) { |
| *fpsm = socket->port; |
| } |
| }, |
| &callback_completed, &callback_status, &found_psm)); |
| |
| // Status shouldn't be updated yet since we get callback update AFTER we |
| // send outgoing result. |
| EXPECT_FALSE(callback_completed); |
| EXPECT_EQ(BtifStatus::kNotReady, callback_status); |
| |
| std::optional<FlossSocketManager::FlossSocket> sock = |
| FlossSocketManager::FlossSocket(); |
| sock->id = socket_id_ctr_ - 1; |
| sock->port = psm; |
| |
| // Trigger the callback completion. We don't care about socket itself. |
| SendOutgoingConnectionResult( |
| socket_id_ctr_ - 1, BtifStatus::kSuccess, std::move(sock), |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_TRUE(callback_completed); |
| EXPECT_EQ(BtifStatus::kSuccess, callback_status); |
| EXPECT_EQ(psm, found_psm); |
| } |
| |
| for (auto kv : l2cap_le_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| bool callback_completed = false; |
| BtifStatus callback_status = BtifStatus::kNotReady; |
| int found_psm = -1; |
| |
| sockmgr_->ConnectUsingL2capLe( |
| remote_device, psm, kv.second, |
| base::BindOnce( |
| [](bool* complete, BtifStatus* cb_status, int* fpsm, |
| BtifStatus status, |
| std::optional<FlossSocketManager::FlossSocket>&& socket) { |
| *complete = true; |
| *cb_status = status; |
| if (socket) { |
| *fpsm = socket->port; |
| } |
| }, |
| &callback_completed, &callback_status, &found_psm)); |
| |
| // Status shouldn't be updated yet since we get callback update AFTER we |
| // send outgoing result. |
| EXPECT_FALSE(callback_completed); |
| EXPECT_EQ(BtifStatus::kNotReady, callback_status); |
| |
| std::optional<FlossSocketManager::FlossSocket> sock = |
| FlossSocketManager::FlossSocket(); |
| sock->id = socket_id_ctr_ - 1; |
| sock->port = psm; |
| |
| // Trigger the callback completion. We don't care about socket itself. |
| SendOutgoingConnectionResult( |
| socket_id_ctr_ - 1, BtifStatus::kSuccess, std::move(sock), |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_TRUE(callback_completed); |
| EXPECT_EQ(BtifStatus::kSuccess, callback_status); |
| EXPECT_EQ(psm, found_psm); |
| } |
| |
| for (auto kv : rfcomm_apis) { |
| EXPECT_CALL(*sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) |
| .WillOnce( |
| Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); |
| |
| bool callback_completed = false; |
| BtifStatus callback_status = BtifStatus::kNotReady; |
| device::BluetoothUUID found_uuid; |
| |
| sockmgr_->ConnectUsingRfcomm( |
| remote_device, uuid, kv.second, |
| base::BindOnce( |
| [](bool* complete, BtifStatus* cb_status, device::BluetoothUUID* uu, |
| BtifStatus status, |
| std::optional<FlossSocketManager::FlossSocket>&& socket) { |
| *complete = true; |
| *cb_status = status; |
| if (socket && socket->uuid) { |
| *uu = *socket->uuid; |
| } |
| }, |
| &callback_completed, &callback_status, &found_uuid)); |
| |
| // Status shouldn't be updated yet since we get callback update AFTER we |
| // send outgoing result. |
| EXPECT_FALSE(callback_completed); |
| EXPECT_EQ(BtifStatus::kNotReady, callback_status); |
| |
| std::optional<FlossSocketManager::FlossSocket> sock = |
| FlossSocketManager::FlossSocket(); |
| sock->id = socket_id_ctr_ - 1; |
| sock->uuid = uuid; |
| |
| // Trigger the callback completion. We don't care about socket itself. |
| SendOutgoingConnectionResult( |
| socket_id_ctr_ - 1, BtifStatus::kSuccess, std::move(sock), |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| EXPECT_TRUE(callback_completed); |
| EXPECT_EQ(BtifStatus::kSuccess, callback_status); |
| EXPECT_EQ(uuid, found_uuid); |
| } |
| } |
| |
| // Really basic calls to accept and close |
| TEST_F(FlossSocketManagerTest, AcceptAndCloseConnection) { |
| Init(); |
| |
| EXPECT_CALL( |
| *sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(socket_manager::kAccept), _, _)) |
| .WillOnce(Invoke(this, &FlossSocketManagerTest::HandleReturnSuccess)); |
| |
| last_status_ = BtifStatus::kNotReady; |
| sockmgr_->Accept(socket_id_ctr_, 42, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| |
| EXPECT_CALL( |
| *sockmgr_proxy_.get(), |
| CallMethodWithErrorResponse(HasMemberOf(socket_manager::kClose), _, _)) |
| .WillOnce(Invoke(this, &FlossSocketManagerTest::HandleReturnSuccess)); |
| |
| last_status_ = BtifStatus::kNotReady; |
| sockmgr_->Close(socket_id_ctr_, |
| base::BindOnce(&FlossSocketManagerTest::SockStatusCb, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| } |
| |
| // Handle state changes from calling accept and close. |
| TEST_F(FlossSocketManagerTest, IncomingStateChanges) { |
| Init(); |
| SetupListeningSocket(); |
| |
| // With a bad id, callbacks will never be dispatched. |
| FlossSocketManager::FlossListeningSocket bad_socket; |
| bad_socket.id = 123456789; |
| |
| // Good id is the last socket ctr we used. |
| FlossSocketManager::FlossListeningSocket good_socket; |
| good_socket.id = socket_id_ctr_ - 1; |
| good_socket.name = "Foo"; |
| good_socket.uuid = device::BluetoothUUID("F00D"); |
| |
| // Empty out the last seen status and socket. |
| last_status_ = BtifStatus::kNotReady; |
| last_server_socket_ = FlossSocketManager::FlossListeningSocket(); |
| last_state_ = FlossSocketManager::ServerSocketState::kClosed; |
| |
| EXPECT_FALSE(last_server_socket_.is_valid()); |
| // Send an invalid update. Should result in no callbacks being called. |
| SendIncomingSocketReady( |
| bad_socket, BtifStatus::kSuccess, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kNotReady, last_status_); |
| EXPECT_FALSE(last_server_socket_.is_valid()); |
| |
| // Send a successful ready to a valid socket. |
| SendIncomingSocketReady( |
| good_socket, BtifStatus::kSuccess, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| EXPECT_EQ(last_state_, FlossSocketManager::ServerSocketState::kReady); |
| EXPECT_TRUE(last_server_socket_.is_valid()); |
| |
| // Empty out the last seen status and socket. |
| last_status_ = BtifStatus::kNotReady; |
| last_server_socket_ = FlossSocketManager::FlossListeningSocket(); |
| |
| // Send an invalid update. Should result in no callbacks being called. |
| SendIncomingSocketClosed( |
| bad_socket.id, BtifStatus::kSuccess, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kNotReady, last_status_); |
| EXPECT_FALSE(last_server_socket_.is_valid()); |
| |
| // Send a successful close to a valid socket. |
| SendIncomingSocketClosed( |
| good_socket.id, BtifStatus::kSuccess, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kSuccess, last_status_); |
| EXPECT_EQ(last_server_socket_.id, good_socket.id); |
| EXPECT_EQ(last_state_, FlossSocketManager::ServerSocketState::kClosed); |
| |
| // Try sending a ready to the same socket and nothing should happen. |
| last_status_ = BtifStatus::kNotReady; |
| SendIncomingSocketReady( |
| good_socket, BtifStatus::kSuccess, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_EQ(BtifStatus::kNotReady, last_status_); |
| } |
| |
| // Handle incoming socket connections. |
| TEST_F(FlossSocketManagerTest, IncomingConnections) { |
| Init(); |
| SetupListeningSocket(); |
| |
| // With a bad id, callbacks will never be dispatched. |
| FlossSocketManager::FlossSocket bad_socket; |
| bad_socket.id = 123456789; |
| |
| // Good id is the last socket ctr we used. |
| FlossSocketManager::FlossSocket good_socket; |
| good_socket.id = socket_id_ctr_ - 1; |
| |
| last_incoming_socket_ = FlossSocketManager::FlossSocket(); |
| EXPECT_FALSE(last_incoming_socket_.is_valid()); |
| |
| SendIncomingConnection( |
| bad_socket.id, bad_socket, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_FALSE(last_incoming_socket_.is_valid()); |
| |
| SendIncomingConnection( |
| good_socket.id, good_socket, |
| base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| EXPECT_TRUE(last_incoming_socket_.is_valid()); |
| EXPECT_EQ(last_incoming_socket_.id, good_socket.id); |
| } |
| |
| } // namespace floss |