1 // Copyright (c) 2012 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.h> 6 7 #include "base/strings/stringprintf.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/extensions/extension_apitest.h" 10 #include "chrome/browser/extensions/extension_function_test_utils.h" 11 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/test/base/ui_test_utils.h" 14 #include "device/bluetooth/bluetooth_adapter.h" 15 #include "device/bluetooth/bluetooth_uuid.h" 16 #include "device/bluetooth/test/mock_bluetooth_adapter.h" 17 #include "device/bluetooth/test/mock_bluetooth_device.h" 18 #include "device/bluetooth/test/mock_bluetooth_discovery_session.h" 19 #include "extensions/browser/api/bluetooth/bluetooth_api.h" 20 #include "extensions/browser/api/bluetooth/bluetooth_event_router.h" 21 #include "extensions/common/test_util.h" 22 #include "extensions/test/extension_test_message_listener.h" 23 #include "extensions/test/result_catcher.h" 24 #include "testing/gmock/include/gmock/gmock.h" 25 26 using device::BluetoothAdapter; 27 using device::BluetoothDevice; 28 using device::BluetoothDiscoverySession; 29 using device::BluetoothUUID; 30 using device::MockBluetoothAdapter; 31 using device::MockBluetoothDevice; 32 using device::MockBluetoothDiscoverySession; 33 using extensions::Extension; 34 using extensions::ResultCatcher; 35 36 namespace utils = extension_function_test_utils; 37 namespace api = extensions::core_api; 38 39 namespace { 40 41 static const char* kAdapterAddress = "A1:A2:A3:A4:A5:A6"; 42 static const char* kName = "whatsinaname"; 43 44 class BluetoothApiTest : public ExtensionApiTest { 45 public: 46 BluetoothApiTest() {} 47 48 virtual void SetUpOnMainThread() OVERRIDE { 49 ExtensionApiTest::SetUpOnMainThread(); 50 empty_extension_ = extensions::test_util::CreateEmptyExtension(); 51 SetUpMockAdapter(); 52 } 53 54 virtual void TearDownOnMainThread() OVERRIDE { 55 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); 56 } 57 58 void SetUpMockAdapter() { 59 // The browser will clean this up when it is torn down 60 mock_adapter_ = new testing::StrictMock<MockBluetoothAdapter>(); 61 event_router()->SetAdapterForTest(mock_adapter_); 62 63 device1_.reset(new testing::NiceMock<MockBluetoothDevice>( 64 mock_adapter_, 0, "d1", "11:12:13:14:15:16", 65 true /* paired */, true /* connected */)); 66 device2_.reset(new testing::NiceMock<MockBluetoothDevice>( 67 mock_adapter_, 0, "d2", "21:22:23:24:25:26", 68 false /* paired */, false /* connected */)); 69 device3_.reset(new testing::NiceMock<MockBluetoothDevice>( 70 mock_adapter_, 0, "d3", "31:32:33:34:35:36", 71 false /* paired */, false /* connected */)); 72 } 73 74 void DiscoverySessionCallback( 75 const BluetoothAdapter::DiscoverySessionCallback& callback, 76 const BluetoothAdapter::ErrorCallback& error_callback) { 77 if (mock_session_.get()) { 78 callback.Run( 79 scoped_ptr<BluetoothDiscoverySession>(mock_session_.release())); 80 return; 81 } 82 error_callback.Run(); 83 } 84 85 template <class T> 86 T* setupFunction(T* function) { 87 function->set_extension(empty_extension_.get()); 88 function->set_has_callback(true); 89 return function; 90 } 91 92 protected: 93 testing::StrictMock<MockBluetoothAdapter>* mock_adapter_; 94 scoped_ptr<testing::NiceMock<MockBluetoothDiscoverySession> > mock_session_; 95 scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device1_; 96 scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device2_; 97 scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device3_; 98 99 extensions::BluetoothEventRouter* event_router() { 100 return bluetooth_api()->event_router(); 101 } 102 103 extensions::BluetoothAPI* bluetooth_api() { 104 return extensions::BluetoothAPI::Get(browser()->profile()); 105 } 106 107 private: 108 scoped_refptr<Extension> empty_extension_; 109 }; 110 111 static void StopDiscoverySessionCallback(const base::Closure& callback, 112 const base::Closure& error_callback) { 113 callback.Run(); 114 } 115 116 } // namespace 117 118 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetAdapterState) { 119 EXPECT_CALL(*mock_adapter_, GetAddress()) 120 .WillOnce(testing::Return(kAdapterAddress)); 121 EXPECT_CALL(*mock_adapter_, GetName()) 122 .WillOnce(testing::Return(kName)); 123 EXPECT_CALL(*mock_adapter_, IsPresent()) 124 .WillOnce(testing::Return(false)); 125 EXPECT_CALL(*mock_adapter_, IsPowered()) 126 .WillOnce(testing::Return(true)); 127 EXPECT_CALL(*mock_adapter_, IsDiscovering()) 128 .WillOnce(testing::Return(false)); 129 130 scoped_refptr<api::BluetoothGetAdapterStateFunction> get_adapter_state; 131 get_adapter_state = setupFunction(new api::BluetoothGetAdapterStateFunction); 132 133 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult( 134 get_adapter_state.get(), "[]", browser())); 135 ASSERT_TRUE(result.get() != NULL); 136 api::bluetooth::AdapterState state; 137 ASSERT_TRUE(api::bluetooth::AdapterState::Populate(*result, &state)); 138 139 EXPECT_FALSE(state.available); 140 EXPECT_TRUE(state.powered); 141 EXPECT_FALSE(state.discovering); 142 EXPECT_EQ(kName, state.name); 143 EXPECT_EQ(kAdapterAddress, state.address); 144 } 145 146 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DeviceEvents) { 147 ResultCatcher catcher; 148 catcher.RestrictToBrowserContext(browser()->profile()); 149 150 ASSERT_TRUE(LoadExtension( 151 test_data_dir_.AppendASCII("bluetooth/device_events"))); 152 153 ExtensionTestMessageListener events_received("ready", true); 154 event_router()->DeviceAdded(mock_adapter_, device1_.get()); 155 event_router()->DeviceAdded(mock_adapter_, device2_.get()); 156 157 EXPECT_CALL(*device2_.get(), GetDeviceName()) 158 .WillRepeatedly(testing::Return("the real d2")); 159 EXPECT_CALL(*device2_.get(), GetName()) 160 .WillRepeatedly(testing::Return(base::UTF8ToUTF16("the real d2"))); 161 event_router()->DeviceChanged(mock_adapter_, device2_.get()); 162 163 event_router()->DeviceAdded(mock_adapter_, device3_.get()); 164 event_router()->DeviceRemoved(mock_adapter_, device1_.get()); 165 EXPECT_TRUE(events_received.WaitUntilSatisfied()); 166 events_received.Reply("go"); 167 168 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 169 } 170 171 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { 172 // Try with a failure to start. This will return an error as we haven't 173 // initialied a session object. 174 EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_)) 175 .WillOnce( 176 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback)); 177 178 // StartDiscovery failure will not reference the adapter. 179 scoped_refptr<api::BluetoothStartDiscoveryFunction> start_function; 180 start_function = setupFunction(new api::BluetoothStartDiscoveryFunction); 181 std::string error( 182 utils::RunFunctionAndReturnError(start_function.get(), "[]", browser())); 183 ASSERT_FALSE(error.empty()); 184 185 // Reset the adapter and initiate a discovery session. The ownership of the 186 // mock session will be passed to the event router. 187 ASSERT_FALSE(mock_session_.get()); 188 SetUpMockAdapter(); 189 190 // Create a mock session to be returned as a result. Get a handle to it as 191 // its ownership will be passed and |mock_session_| will be reset. 192 mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>()); 193 MockBluetoothDiscoverySession* session = mock_session_.get(); 194 EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_)) 195 .WillOnce( 196 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback)); 197 start_function = setupFunction(new api::BluetoothStartDiscoveryFunction); 198 (void) 199 utils::RunFunctionAndReturnError(start_function.get(), "[]", browser()); 200 201 // End the discovery session. The StopDiscovery function should succeed. 202 testing::Mock::VerifyAndClearExpectations(mock_adapter_); 203 EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true)); 204 EXPECT_CALL(*session, Stop(testing::_, testing::_)) 205 .WillOnce(testing::Invoke(StopDiscoverySessionCallback)); 206 207 // StopDiscovery success will remove the session object, unreferencing the 208 // adapter. 209 scoped_refptr<api::BluetoothStopDiscoveryFunction> stop_function; 210 stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); 211 (void) utils::RunFunctionAndReturnSingleResult( 212 stop_function.get(), "[]", browser()); 213 214 // Reset the adapter. Simulate failure for stop discovery. The event router 215 // still owns the session. Make it appear inactive. 216 SetUpMockAdapter(); 217 EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(false)); 218 stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); 219 error = 220 utils::RunFunctionAndReturnError(stop_function.get(), "[]", browser()); 221 ASSERT_FALSE(error.empty()); 222 SetUpMockAdapter(); 223 } 224 225 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) { 226 mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>()); 227 MockBluetoothDiscoverySession* session = mock_session_.get(); 228 EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_)) 229 .WillOnce( 230 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback)); 231 EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true)); 232 EXPECT_CALL(*session, Stop(testing::_, testing::_)) 233 .WillOnce(testing::Invoke(StopDiscoverySessionCallback)); 234 235 ResultCatcher catcher; 236 catcher.RestrictToBrowserContext(browser()->profile()); 237 238 ExtensionTestMessageListener discovery_started("ready", true); 239 ASSERT_TRUE(LoadExtension( 240 test_data_dir_.AppendASCII("bluetooth/discovery_callback"))); 241 EXPECT_TRUE(discovery_started.WaitUntilSatisfied()); 242 243 event_router()->DeviceAdded(mock_adapter_, device1_.get()); 244 245 discovery_started.Reply("go"); 246 ExtensionTestMessageListener discovery_stopped("ready", true); 247 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); 248 EXPECT_TRUE(discovery_stopped.WaitUntilSatisfied()); 249 250 SetUpMockAdapter(); 251 event_router()->DeviceAdded(mock_adapter_, device2_.get()); 252 discovery_stopped.Reply("go"); 253 254 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 255 } 256 257 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) { 258 EXPECT_CALL(*mock_adapter_, GetAddress()) 259 .WillOnce(testing::Return(kAdapterAddress)); 260 EXPECT_CALL(*mock_adapter_, GetName()) 261 .WillOnce(testing::Return(kName)); 262 EXPECT_CALL(*mock_adapter_, IsPresent()) 263 .WillOnce(testing::Return(true)); 264 EXPECT_CALL(*mock_adapter_, IsPowered()) 265 .WillOnce(testing::Return(true)); 266 267 // Fake that the adapter is discovering 268 EXPECT_CALL(*mock_adapter_, IsDiscovering()) 269 .WillOnce(testing::Return(true)); 270 event_router()->AdapterDiscoveringChanged(mock_adapter_, true); 271 272 // Cache a device before the extension starts discovering 273 event_router()->DeviceAdded(mock_adapter_, device1_.get()); 274 275 ResultCatcher catcher; 276 catcher.RestrictToBrowserContext(browser()->profile()); 277 278 mock_session_.reset(new testing::NiceMock<MockBluetoothDiscoverySession>()); 279 MockBluetoothDiscoverySession* session = mock_session_.get(); 280 EXPECT_CALL(*mock_adapter_, StartDiscoverySession(testing::_, testing::_)) 281 .WillOnce( 282 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback)); 283 EXPECT_CALL(*session, IsActive()).WillOnce(testing::Return(true)); 284 EXPECT_CALL(*session, Stop(testing::_, testing::_)) 285 .WillOnce(testing::Invoke(StopDiscoverySessionCallback)); 286 287 ExtensionTestMessageListener discovery_started("ready", true); 288 ASSERT_TRUE(LoadExtension( 289 test_data_dir_.AppendASCII("bluetooth/discovery_in_progress"))); 290 EXPECT_TRUE(discovery_started.WaitUntilSatisfied()); 291 292 // Only this should be received. No additional notification should be sent for 293 // devices discovered before the discovery session started. 294 event_router()->DeviceAdded(mock_adapter_, device2_.get()); 295 296 discovery_started.Reply("go"); 297 ExtensionTestMessageListener discovery_stopped("ready", true); 298 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); 299 EXPECT_TRUE(discovery_stopped.WaitUntilSatisfied()); 300 301 SetUpMockAdapter(); 302 // This should never be received. 303 event_router()->DeviceAdded(mock_adapter_, device2_.get()); 304 discovery_stopped.Reply("go"); 305 306 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 307 } 308 309 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, OnAdapterStateChanged) { 310 ResultCatcher catcher; 311 catcher.RestrictToBrowserContext(browser()->profile()); 312 313 // Load and wait for setup 314 ExtensionTestMessageListener listener("ready", true); 315 ASSERT_TRUE( 316 LoadExtension( 317 test_data_dir_.AppendASCII("bluetooth/on_adapter_state_changed"))); 318 EXPECT_TRUE(listener.WaitUntilSatisfied()); 319 320 EXPECT_CALL(*mock_adapter_, GetAddress()) 321 .WillOnce(testing::Return(kAdapterAddress)); 322 EXPECT_CALL(*mock_adapter_, GetName()) 323 .WillOnce(testing::Return(kName)); 324 EXPECT_CALL(*mock_adapter_, IsPresent()) 325 .WillOnce(testing::Return(false)); 326 EXPECT_CALL(*mock_adapter_, IsPowered()) 327 .WillOnce(testing::Return(false)); 328 EXPECT_CALL(*mock_adapter_, IsDiscovering()) 329 .WillOnce(testing::Return(false)); 330 event_router()->AdapterPoweredChanged(mock_adapter_, false); 331 332 EXPECT_CALL(*mock_adapter_, GetAddress()) 333 .WillOnce(testing::Return(kAdapterAddress)); 334 EXPECT_CALL(*mock_adapter_, GetName()) 335 .WillOnce(testing::Return(kName)); 336 EXPECT_CALL(*mock_adapter_, IsPresent()) 337 .WillOnce(testing::Return(true)); 338 EXPECT_CALL(*mock_adapter_, IsPowered()) 339 .WillOnce(testing::Return(true)); 340 EXPECT_CALL(*mock_adapter_, IsDiscovering()) 341 .WillOnce(testing::Return(true)); 342 event_router()->AdapterPresentChanged(mock_adapter_, true); 343 344 EXPECT_CALL(*mock_adapter_, GetAddress()) 345 .WillOnce(testing::Return(kAdapterAddress)); 346 EXPECT_CALL(*mock_adapter_, GetName()) 347 .WillOnce(testing::Return(kName)); 348 EXPECT_CALL(*mock_adapter_, IsPresent()) 349 .WillOnce(testing::Return(true)); 350 EXPECT_CALL(*mock_adapter_, IsPowered()) 351 .WillOnce(testing::Return(true)); 352 EXPECT_CALL(*mock_adapter_, IsDiscovering()) 353 .WillOnce(testing::Return(true)); 354 event_router()->AdapterDiscoveringChanged(mock_adapter_, true); 355 356 listener.Reply("go"); 357 358 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 359 } 360 361 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevices) { 362 ResultCatcher catcher; 363 catcher.RestrictToBrowserContext(browser()->profile()); 364 365 BluetoothAdapter::ConstDeviceList devices; 366 devices.push_back(device1_.get()); 367 devices.push_back(device2_.get()); 368 369 EXPECT_CALL(*mock_adapter_, GetDevices()) 370 .Times(1) 371 .WillRepeatedly(testing::Return(devices)); 372 373 // Load and wait for setup 374 ExtensionTestMessageListener listener("ready", true); 375 ASSERT_TRUE( 376 LoadExtension(test_data_dir_.AppendASCII("bluetooth/get_devices"))); 377 EXPECT_TRUE(listener.WaitUntilSatisfied()); 378 379 listener.Reply("go"); 380 381 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 382 } 383 384 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevice) { 385 ResultCatcher catcher; 386 catcher.RestrictToBrowserContext(browser()->profile()); 387 388 EXPECT_CALL(*mock_adapter_, GetDevice(device1_->GetAddress())) 389 .WillOnce(testing::Return(device1_.get())); 390 EXPECT_CALL(*mock_adapter_, GetDevice(device2_->GetAddress())) 391 .Times(1) 392 .WillRepeatedly(testing::Return(static_cast<BluetoothDevice*>(NULL))); 393 394 // Load and wait for setup 395 ExtensionTestMessageListener listener("ready", true); 396 ASSERT_TRUE( 397 LoadExtension(test_data_dir_.AppendASCII("bluetooth/get_device"))); 398 EXPECT_TRUE(listener.WaitUntilSatisfied()); 399 400 listener.Reply("go"); 401 402 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 403 } 404 405 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DeviceInfo) { 406 ResultCatcher catcher; 407 catcher.RestrictToBrowserContext(browser()->profile()); 408 409 // Set up the first device object to reflect a real-world device. 410 BluetoothAdapter::ConstDeviceList devices; 411 412 EXPECT_CALL(*device1_.get(), GetAddress()) 413 .WillRepeatedly(testing::Return("A4:17:31:00:00:00")); 414 EXPECT_CALL(*device1_.get(), GetDeviceName()) 415 .WillRepeatedly(testing::Return("Chromebook Pixel")); 416 EXPECT_CALL(*device1_.get(), GetName()) 417 .WillRepeatedly(testing::Return(base::UTF8ToUTF16("Chromebook Pixel"))); 418 EXPECT_CALL(*device1_.get(), GetBluetoothClass()) 419 .WillRepeatedly(testing::Return(0x080104)); 420 EXPECT_CALL(*device1_.get(), GetDeviceType()) 421 .WillRepeatedly(testing::Return(BluetoothDevice::DEVICE_COMPUTER)); 422 EXPECT_CALL(*device1_.get(), GetVendorIDSource()) 423 .WillRepeatedly(testing::Return(BluetoothDevice::VENDOR_ID_BLUETOOTH)); 424 EXPECT_CALL(*device1_.get(), GetVendorID()) 425 .WillRepeatedly(testing::Return(0x00E0)); 426 EXPECT_CALL(*device1_.get(), GetProductID()) 427 .WillRepeatedly(testing::Return(0x240A)); 428 EXPECT_CALL(*device1_.get(), GetDeviceID()) 429 .WillRepeatedly(testing::Return(0x0400)); 430 EXPECT_CALL(*device1_, GetRSSI()).WillRepeatedly(testing::Return(-42)); 431 EXPECT_CALL(*device1_, GetCurrentHostTransmitPower()) 432 .WillRepeatedly(testing::Return(-16)); 433 EXPECT_CALL(*device1_, GetMaximumHostTransmitPower()) 434 .WillRepeatedly(testing::Return(10)); 435 436 BluetoothDevice::UUIDList uuids; 437 uuids.push_back(BluetoothUUID("1105")); 438 uuids.push_back(BluetoothUUID("1106")); 439 440 EXPECT_CALL(*device1_.get(), GetUUIDs()) 441 .WillOnce(testing::Return(uuids)); 442 443 devices.push_back(device1_.get()); 444 445 // Leave the second largely empty so we can check a device without 446 // available information. 447 devices.push_back(device2_.get()); 448 449 EXPECT_CALL(*mock_adapter_, GetDevices()) 450 .Times(1) 451 .WillRepeatedly(testing::Return(devices)); 452 453 // Load and wait for setup 454 ExtensionTestMessageListener listener("ready", true); 455 ASSERT_TRUE( 456 LoadExtension(test_data_dir_.AppendASCII("bluetooth/device_info"))); 457 EXPECT_TRUE(listener.WaitUntilSatisfied()); 458 459 listener.Reply("go"); 460 461 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 462 } 463