• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
BluetoothApiTest()43   BluetoothApiTest() {}
44 
SetUpOnMainThread()45   virtual void SetUpOnMainThread() OVERRIDE {
46     ExtensionApiTest::SetUpOnMainThread();
47     empty_extension_ = utils::CreateEmptyExtension();
48     SetUpMockAdapter();
49   }
50 
CleanUpOnMainThread()51   virtual void CleanUpOnMainThread() OVERRIDE {
52     EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_));
53   }
54 
SetUpMockAdapter()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 
DiscoverySessionCallback(const BluetoothAdapter::DiscoverySessionCallback & callback,const BluetoothAdapter::ErrorCallback & error_callback)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>
setupFunction(T * function)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 
event_router()96   extensions::BluetoothEventRouter* event_router() {
97     return bluetooth_api()->event_router();
98   }
99 
bluetooth_api()100   extensions::BluetoothAPI* bluetooth_api() {
101     return extensions::BluetoothAPI::Get(browser()->profile());
102   }
103 
104  private:
105   scoped_refptr<Extension> empty_extension_;
106 };
107 
StopDiscoverySessionCallback(const base::Closure & callback,const base::Closure & error_callback)108 static void StopDiscoverySessionCallback(const base::Closure& callback,
109                                          const base::Closure& error_callback) {
110   callback.Run();
111 }
112 
113 }  // namespace
114 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,GetAdapterState)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,DeviceEvents)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,Discovery)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,DiscoveryCallback)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,DiscoveryInProgress)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,OnAdapterStateChanged)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,GetDevices)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,GetDevice)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 
IN_PROC_BROWSER_TEST_F(BluetoothApiTest,DeviceInfo)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