Home | History | Annotate | Download | only in bluetooth
      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