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/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