1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 7 #include "base/memory/ref_counted.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h" 10 #include "chrome/browser/extensions/extension_apitest.h" 11 #include "chrome/browser/extensions/extension_function_test_utils.h" 12 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_test_message_listener.h" 14 #include "chrome/browser/ui/browser.h" 15 #include "chrome/test/base/ui_test_utils.h" 16 #include "device/bluetooth/bluetooth_adapter_factory.h" 17 #include "device/bluetooth/bluetooth_uuid.h" 18 #include "device/bluetooth/test/mock_bluetooth_adapter.h" 19 #include "device/bluetooth/test/mock_bluetooth_device.h" 20 #include "device/bluetooth/test/mock_bluetooth_socket.h" 21 #include "testing/gmock/include/gmock/gmock.h" 22 23 using device::BluetoothAdapter; 24 using device::BluetoothAdapterFactory; 25 using device::BluetoothDevice; 26 using device::BluetoothSocket; 27 using device::BluetoothUUID; 28 using device::MockBluetoothAdapter; 29 using device::MockBluetoothDevice; 30 using device::MockBluetoothSocket; 31 using extensions::Extension; 32 33 namespace utils = extension_function_test_utils; 34 namespace api = extensions::api; 35 36 namespace { 37 38 class BluetoothSocketApiTest : public ExtensionApiTest { 39 public: 40 BluetoothSocketApiTest() {} 41 42 virtual void SetUpOnMainThread() OVERRIDE { 43 ExtensionApiTest::SetUpOnMainThread(); 44 empty_extension_ = utils::CreateEmptyExtension(); 45 SetUpMockAdapter(); 46 } 47 48 virtual void CleanUpOnMainThread() OVERRIDE { 49 ExtensionApiTest::CleanUpOnMainThread(); 50 } 51 52 void SetUpMockAdapter() { 53 // The browser will clean this up when it is torn down. 54 mock_adapter_ = new testing::StrictMock<MockBluetoothAdapter>(); 55 BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_); 56 57 mock_device1_.reset(new testing::NiceMock<MockBluetoothDevice>( 58 mock_adapter_, 0, "d1", "11:12:13:14:15:16", 59 true /* paired */, false /* connected */)); 60 mock_device2_.reset(new testing::NiceMock<MockBluetoothDevice>( 61 mock_adapter_, 0, "d2", "21:22:23:24:25:26", 62 true /* paired */, false /* connected */)); 63 } 64 65 protected: 66 scoped_refptr<testing::StrictMock<MockBluetoothAdapter> > mock_adapter_; 67 scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device1_; 68 scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device2_; 69 70 private: 71 scoped_refptr<Extension> empty_extension_; 72 }; 73 74 // testing::InvokeArgument<N> does not work with base::Callback, fortunately 75 // gmock makes it simple to create action templates that do for the various 76 // possible numbers of arguments. 77 ACTION_TEMPLATE(InvokeCallbackArgument, 78 HAS_1_TEMPLATE_PARAMS(int, k), 79 AND_0_VALUE_PARAMS()) { 80 ::std::tr1::get<k>(args).Run(); 81 } 82 83 ACTION_TEMPLATE(InvokeCallbackArgument, 84 HAS_1_TEMPLATE_PARAMS(int, k), 85 AND_1_VALUE_PARAMS(p0)) { 86 ::std::tr1::get<k>(args).Run(p0); 87 } 88 89 ACTION_TEMPLATE(InvokeCallbackArgument, 90 HAS_1_TEMPLATE_PARAMS(int, k), 91 AND_2_VALUE_PARAMS(p0, p1)) { 92 ::std::tr1::get<k>(args).Run(p0, p1); 93 } 94 95 } // namespace 96 97 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Connect) { 98 ResultCatcher catcher; 99 catcher.RestrictToProfile(browser()->profile()); 100 101 // Return the right mock device object for the address used by the test, 102 // return NULL for the "Device not found" test. 103 EXPECT_CALL(*mock_adapter_, GetDevice(mock_device1_->GetAddress())) 104 .WillRepeatedly(testing::Return(mock_device1_.get())); 105 EXPECT_CALL(*mock_adapter_, GetDevice(std::string("aa:aa:aa:aa:aa:aa"))) 106 .WillOnce(testing::Return(static_cast<BluetoothDevice*>(NULL))); 107 108 // Return a mock socket object as a successful result to the connect() call. 109 BluetoothUUID service_uuid("8e3ad063-db38-4289-aa8f-b30e4223cf40"); 110 scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_socket 111 = new testing::StrictMock<MockBluetoothSocket>(); 112 EXPECT_CALL(*mock_device1_, 113 ConnectToService(service_uuid, testing::_, testing::_)) 114 .WillOnce(InvokeCallbackArgument<1>(mock_socket)); 115 116 // Since the socket is unpaused, expect a call to Receive() from the socket 117 // dispatcher. Since there is no data, this will not call its callback. 118 EXPECT_CALL(*mock_socket, Receive(testing::_, testing::_, testing::_)); 119 120 // The test also cleans up by calling Disconnect and Close. 121 EXPECT_CALL(*mock_socket, Disconnect(testing::_)) 122 .WillOnce(InvokeCallbackArgument<0>()); 123 EXPECT_CALL(*mock_socket, Close()); 124 125 // Run the test. 126 ExtensionTestMessageListener listener("ready", true); 127 scoped_refptr<const Extension> extension( 128 LoadExtension(test_data_dir_.AppendASCII("bluetooth_socket/connect"))); 129 ASSERT_TRUE(extension.get()); 130 EXPECT_TRUE(listener.WaitUntilSatisfied()); 131 132 listener.Reply("go"); 133 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 134 } 135 136 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Listen) { 137 ResultCatcher catcher; 138 catcher.RestrictToProfile(browser()->profile()); 139 140 // Return a mock socket object as a successful result to the create service 141 // call. 142 BluetoothUUID service_uuid("2de497f9-ab28-49db-b6d2-066ea69f1737"); 143 scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_server_socket 144 = new testing::StrictMock<MockBluetoothSocket>(); 145 EXPECT_CALL(*mock_adapter_, 146 CreateRfcommService(service_uuid, 147 BluetoothAdapter::kChannelAuto, 148 testing::_, testing::_)) 149 .WillOnce(InvokeCallbackArgument<2>(mock_server_socket)); 150 151 // Since the socket is unpaused, expect a call to Accept() from the socket 152 // dispatcher. We'll immediately send back another mock socket to represent 153 // the client API. Further calls will return no data and behave as if 154 // pending. 155 scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_client_socket 156 = new testing::StrictMock<MockBluetoothSocket>(); 157 EXPECT_CALL(*mock_server_socket, Accept(testing::_, testing::_)) 158 .Times(2) 159 .WillOnce(InvokeCallbackArgument<0>(mock_device1_.get(), 160 mock_client_socket)) 161 .WillOnce(testing::Return()); 162 163 // Run the test, it sends a ready signal once it's ready for us to dispatch 164 // a client connection to it. 165 ExtensionTestMessageListener socket_listening("ready", true); 166 scoped_refptr<const Extension> extension( 167 LoadExtension(test_data_dir_.AppendASCII("bluetooth_socket/listen"))); 168 ASSERT_TRUE(extension.get()); 169 EXPECT_TRUE(socket_listening.WaitUntilSatisfied()); 170 171 // Connection events are dispatched using a couple of PostTask to the UI 172 // thread. Waiting until idle ensures the event is dispatched to the 173 // receiver(s). 174 base::RunLoop().RunUntilIdle(); 175 ExtensionTestMessageListener listener("ready", true); 176 socket_listening.Reply("go"); 177 178 // Second stage of tests checks for error conditions, and will clean up 179 // the existing server and client sockets. 180 EXPECT_CALL(*mock_server_socket, Disconnect(testing::_)) 181 .WillOnce(InvokeCallbackArgument<0>()); 182 EXPECT_CALL(*mock_server_socket, Close()); 183 184 EXPECT_CALL(*mock_client_socket, Disconnect(testing::_)) 185 .WillOnce(InvokeCallbackArgument<0>()); 186 EXPECT_CALL(*mock_client_socket, Close()); 187 188 EXPECT_TRUE(listener.WaitUntilSatisfied()); 189 listener.Reply("go"); 190 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 191 } 192 193 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, PermissionDenied) { 194 ResultCatcher catcher; 195 catcher.RestrictToProfile(browser()->profile()); 196 197 // Run the test. 198 scoped_refptr<const Extension> extension( 199 LoadExtension(test_data_dir_.AppendASCII( 200 "bluetooth_socket/permission_denied"))); 201 ASSERT_TRUE(extension.get()); 202 203 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 204 } 205