| // Copyright 2016 The Chromium 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 "content/browser/bluetooth/frame_connected_bluetooth_devices.h" |
| |
| #include "base/memory/ref_counted.h" |
| #include "content/browser/bluetooth/web_bluetooth_service_impl.h" |
| #include "content/test/test_render_view_host.h" |
| #include "content/test/test_web_contents.h" |
| #include "device/bluetooth/bluetooth_gatt_connection.h" |
| #include "device/bluetooth/test/mock_bluetooth_adapter.h" |
| #include "device/bluetooth/test/mock_bluetooth_device.h" |
| #include "device/bluetooth/test/mock_bluetooth_gatt_connection.h" |
| #include "mojo/public/cpp/bindings/associated_interface_ptr.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| typedef testing::NiceMock<device::MockBluetoothAdapter> |
| NiceMockBluetoothAdapter; |
| typedef testing::NiceMock<device::MockBluetoothDevice> NiceMockBluetoothDevice; |
| typedef testing::NiceMock<device::MockBluetoothGattConnection> |
| NiceMockBluetoothGattConnection; |
| |
| using testing::Return; |
| using testing::StrEq; |
| using testing::_; |
| |
| namespace { |
| |
| const WebBluetoothDeviceId kDeviceId0("000000000000000000000A=="); |
| constexpr char kDeviceAddress0[] = "0"; |
| constexpr char kDeviceName0[] = "Device0"; |
| |
| const WebBluetoothDeviceId kDeviceId1("111111111111111111111A=="); |
| constexpr char kDeviceAddress1[] = "1"; |
| constexpr char kDeviceName1[] = "Device1"; |
| |
| blink::mojom::WebBluetoothServerClientAssociatedPtr CreateServerClient() { |
| blink::mojom::WebBluetoothServerClientAssociatedPtr client; |
| mojo::MakeRequestAssociatedWithDedicatedPipe(&client); |
| return client; |
| } |
| |
| } // namespace |
| |
| class FrameConnectedBluetoothDevicesTest |
| : public RenderViewHostImplTestHarness { |
| public: |
| FrameConnectedBluetoothDevicesTest() |
| : adapter_(new NiceMockBluetoothAdapter()), |
| device0_(adapter_.get(), |
| 0 /* class */, |
| kDeviceName0, |
| kDeviceAddress0, |
| false /* paired */, |
| false /* connected */), |
| device1_(adapter_.get(), |
| 0 /* class */, |
| kDeviceName1, |
| kDeviceAddress1, |
| false /* paired */, |
| false /* connected */) { |
| ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(nullptr)); |
| ON_CALL(*adapter_, GetDevice(StrEq(kDeviceAddress0))) |
| .WillByDefault(Return(&device0_)); |
| ON_CALL(*adapter_, GetDevice(StrEq(kDeviceAddress1))) |
| .WillByDefault(Return(&device1_)); |
| } |
| |
| ~FrameConnectedBluetoothDevicesTest() override {} |
| |
| void SetUp() override { |
| RenderViewHostImplTestHarness::SetUp(); |
| |
| // Create subframe to simulate two maps on the same WebContents. |
| contents()->GetMainFrame()->InitializeRenderFrameIfNeeded(); |
| TestRenderFrameHost* subframe = |
| contents()->GetMainFrame()->AppendChild("bluetooth_frame"); |
| subframe->InitializeRenderFrameIfNeeded(); |
| |
| // Simulate two frames each connected to a bluetooth service. |
| service0_ = |
| contents()->GetMainFrame()->CreateWebBluetoothServiceForTesting(); |
| map0_ = service0_->connected_devices_.get(); |
| |
| service1_ = subframe->CreateWebBluetoothServiceForTesting(); |
| map1_ = service1_->connected_devices_.get(); |
| } |
| |
| void TearDown() override { |
| map1_ = nullptr; |
| service1_ = nullptr; |
| map0_ = nullptr; |
| service0_ = nullptr; |
| RenderViewHostImplTestHarness::TearDown(); |
| } |
| |
| std::unique_ptr<NiceMockBluetoothGattConnection> GetConnection( |
| const std::string& address) { |
| return std::make_unique<NiceMockBluetoothGattConnection>(adapter_.get(), |
| address); |
| } |
| |
| void ResetService0() { |
| service0_->ClearState(); |
| map0_ = nullptr; |
| } |
| |
| void ResetService1() { |
| service1_->ClearState(); |
| map1_ = nullptr; |
| } |
| |
| protected: |
| FrameConnectedBluetoothDevices* map0_; |
| WebBluetoothServiceImpl* service0_; |
| |
| FrameConnectedBluetoothDevices* map1_; |
| WebBluetoothServiceImpl* service1_; |
| |
| private: |
| scoped_refptr<NiceMockBluetoothAdapter> adapter_; |
| NiceMockBluetoothDevice device0_; |
| NiceMockBluetoothDevice device1_; |
| }; |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Insert_Once) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Insert_Twice) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Insert_TwoDevices) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Insert_TwoMaps) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map1_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionId_OneDevice_AddOnce_RemoveOnce) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionId_OneDevice_AddOnce_RemoveTwice) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionId_OneDevice_AddTwice_RemoveOnce) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionId_OneDevice_AddTwice_RemoveTwice) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, CloseConnectionId_TwoDevices) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId1); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, CloseConnectionId_TwoMaps) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map1_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| map0_->CloseConnectionToDeviceWithId(kDeviceId0); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| map1_->CloseConnectionToDeviceWithId(kDeviceId1); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionAddress_OneDevice_AddOnce_RemoveOnce) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionAddress_OneDevice_AddOnce_RemoveTwice) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| EXPECT_FALSE(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0)); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionAddress_OneDevice_AddTwice_RemoveOnce) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| CloseConnectionAddress_OneDevice_AddTwice_RemoveTwice) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| EXPECT_FALSE(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0)); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, CloseConnectionAddress_TwoDevices) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress1).value(), |
| kDeviceId1); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, CloseConnectionAddress_TwoMaps) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map1_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(), |
| kDeviceId0); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0)); |
| EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| |
| EXPECT_EQ(map1_->CloseConnectionToDeviceWithAddress(kDeviceAddress1).value(), |
| kDeviceId1); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| EXPECT_FALSE(map1_->IsConnectedToDeviceWithId(kDeviceId1)); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Destruction_MultipleDevices) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| |
| ResetService0(); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, Destruction_MultipleMaps) { |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map0_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| map1_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| map1_->Insert(kDeviceId1, GetConnection(kDeviceAddress1), |
| CreateServerClient()); |
| |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| |
| ResetService0(); |
| |
| // WebContents should still be connected because of map1_. |
| EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice()); |
| |
| ResetService1(); |
| |
| EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice()); |
| } |
| |
| TEST_F(FrameConnectedBluetoothDevicesTest, |
| DestroyedByWebContentsImplDestruction) { |
| // Tests that we don't crash when FrameConnectedBluetoothDevices contains |
| // at least one device, and it is destroyed while WebContentsImpl is being |
| // destroyed. |
| map0_->Insert(kDeviceId0, GetConnection(kDeviceAddress0), |
| CreateServerClient()); |
| DeleteContents(); |
| } |
| |
| } // namespace content |