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