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.
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"
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
;
36 namespace utils
= extension_function_test_utils
;
37 namespace api
= extensions::core_api
;
41 static const char* kAdapterAddress
= "A1:A2:A3:A4:A5:A6";
42 static const char* kName
= "whatsinaname";
44 class BluetoothApiTest
: public ExtensionApiTest
{
48 void SetUpOnMainThread() override
{
49 ExtensionApiTest::SetUpOnMainThread();
50 empty_extension_
= extensions::test_util::CreateEmptyExtension();
54 void TearDownOnMainThread() override
{
55 EXPECT_CALL(*mock_adapter_
, RemoveObserver(testing::_
));
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_
);
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 */));
74 void DiscoverySessionCallback(
75 const BluetoothAdapter::DiscoverySessionCallback
& callback
,
76 const BluetoothAdapter::ErrorCallback
& error_callback
) {
77 if (mock_session_
.get()) {
79 scoped_ptr
<BluetoothDiscoverySession
>(mock_session_
.release()));
86 T
* setupFunction(T
* function
) {
87 function
->set_extension(empty_extension_
.get());
88 function
->set_has_callback(true);
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_
;
99 extensions::BluetoothEventRouter
* event_router() {
100 return bluetooth_api()->event_router();
103 extensions::BluetoothAPI
* bluetooth_api() {
104 return extensions::BluetoothAPI::Get(browser()->profile());
108 scoped_refptr
<Extension
> empty_extension_
;
111 static void StopDiscoverySessionCallback(const base::Closure
& callback
,
112 const base::Closure
& error_callback
) {
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));
130 scoped_refptr
<api::BluetoothGetAdapterStateFunction
> get_adapter_state
;
131 get_adapter_state
= setupFunction(new api::BluetoothGetAdapterStateFunction
);
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
));
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
);
146 IN_PROC_BROWSER_TEST_F(BluetoothApiTest
, DeviceEvents
) {
147 ResultCatcher catcher
;
148 catcher
.RestrictToBrowserContext(browser()->profile());
150 ASSERT_TRUE(LoadExtension(
151 test_data_dir_
.AppendASCII("bluetooth/device_events")));
153 ExtensionTestMessageListener
events_received("ready", true);
154 event_router()->DeviceAdded(mock_adapter_
, device1_
.get());
155 event_router()->DeviceAdded(mock_adapter_
, device2_
.get());
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());
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");
168 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
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::_
))
176 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback
));
178 // StartDiscovery failure will not reference the adapter.
179 scoped_refptr
<api::BluetoothStartDiscoveryFunction
> start_function
;
180 start_function
= setupFunction(new api::BluetoothStartDiscoveryFunction
);
182 utils::RunFunctionAndReturnError(start_function
.get(), "[]", browser()));
183 ASSERT_FALSE(error
.empty());
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());
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::_
))
196 testing::Invoke(this, &BluetoothApiTest::DiscoverySessionCallback
));
197 start_function
= setupFunction(new api::BluetoothStartDiscoveryFunction
);
199 utils::RunFunctionAndReturnError(start_function
.get(), "[]", browser());
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
));
207 // StopDiscovery success will remove the session object, unreferencing the
209 scoped_refptr
<api::BluetoothStopDiscoveryFunction
> stop_function
;
210 stop_function
= setupFunction(new api::BluetoothStopDiscoveryFunction
);
211 (void) utils::RunFunctionAndReturnSingleResult(
212 stop_function
.get(), "[]", browser());
214 // Reset the adapter. Simulate failure for stop discovery. The event router
215 // still owns the session. Make it appear inactive.
217 EXPECT_CALL(*session
, IsActive()).WillOnce(testing::Return(false));
218 stop_function
= setupFunction(new api::BluetoothStopDiscoveryFunction
);
220 utils::RunFunctionAndReturnError(stop_function
.get(), "[]", browser());
221 ASSERT_FALSE(error
.empty());
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::_
))
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
));
235 ResultCatcher catcher
;
236 catcher
.RestrictToBrowserContext(browser()->profile());
238 ExtensionTestMessageListener
discovery_started("ready", true);
239 ASSERT_TRUE(LoadExtension(
240 test_data_dir_
.AppendASCII("bluetooth/discovery_callback")));
241 EXPECT_TRUE(discovery_started
.WaitUntilSatisfied());
243 event_router()->DeviceAdded(mock_adapter_
, device1_
.get());
245 discovery_started
.Reply("go");
246 ExtensionTestMessageListener
discovery_stopped("ready", true);
247 EXPECT_CALL(*mock_adapter_
, RemoveObserver(testing::_
));
248 EXPECT_TRUE(discovery_stopped
.WaitUntilSatisfied());
251 event_router()->DeviceAdded(mock_adapter_
, device2_
.get());
252 discovery_stopped
.Reply("go");
254 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
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));
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);
272 // Cache a device before the extension starts discovering
273 event_router()->DeviceAdded(mock_adapter_
, device1_
.get());
275 ResultCatcher catcher
;
276 catcher
.RestrictToBrowserContext(browser()->profile());
278 mock_session_
.reset(new testing::NiceMock
<MockBluetoothDiscoverySession
>());
279 MockBluetoothDiscoverySession
* session
= mock_session_
.get();
280 EXPECT_CALL(*mock_adapter_
, StartDiscoverySession(testing::_
, testing::_
))
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
));
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());
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());
296 discovery_started
.Reply("go");
297 ExtensionTestMessageListener
discovery_stopped("ready", true);
298 EXPECT_CALL(*mock_adapter_
, RemoveObserver(testing::_
));
299 EXPECT_TRUE(discovery_stopped
.WaitUntilSatisfied());
302 // This should never be received.
303 event_router()->DeviceAdded(mock_adapter_
, device2_
.get());
304 discovery_stopped
.Reply("go");
306 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
309 IN_PROC_BROWSER_TEST_F(BluetoothApiTest
, OnAdapterStateChanged
) {
310 ResultCatcher catcher
;
311 catcher
.RestrictToBrowserContext(browser()->profile());
313 // Load and wait for setup
314 ExtensionTestMessageListener
listener("ready", true);
317 test_data_dir_
.AppendASCII("bluetooth/on_adapter_state_changed")));
318 EXPECT_TRUE(listener
.WaitUntilSatisfied());
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);
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);
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);
356 listener
.Reply("go");
358 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
361 IN_PROC_BROWSER_TEST_F(BluetoothApiTest
, GetDevices
) {
362 ResultCatcher catcher
;
363 catcher
.RestrictToBrowserContext(browser()->profile());
365 BluetoothAdapter::ConstDeviceList devices
;
366 devices
.push_back(device1_
.get());
367 devices
.push_back(device2_
.get());
369 EXPECT_CALL(*mock_adapter_
, GetDevices())
371 .WillRepeatedly(testing::Return(devices
));
373 // Load and wait for setup
374 ExtensionTestMessageListener
listener("ready", true);
376 LoadExtension(test_data_dir_
.AppendASCII("bluetooth/get_devices")));
377 EXPECT_TRUE(listener
.WaitUntilSatisfied());
379 listener
.Reply("go");
381 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
384 IN_PROC_BROWSER_TEST_F(BluetoothApiTest
, GetDevice
) {
385 ResultCatcher catcher
;
386 catcher
.RestrictToBrowserContext(browser()->profile());
388 EXPECT_CALL(*mock_adapter_
, GetDevice(device1_
->GetAddress()))
389 .WillOnce(testing::Return(device1_
.get()));
390 EXPECT_CALL(*mock_adapter_
, GetDevice(device2_
->GetAddress()))
392 .WillRepeatedly(testing::Return(static_cast<BluetoothDevice
*>(NULL
)));
394 // Load and wait for setup
395 ExtensionTestMessageListener
listener("ready", true);
397 LoadExtension(test_data_dir_
.AppendASCII("bluetooth/get_device")));
398 EXPECT_TRUE(listener
.WaitUntilSatisfied());
400 listener
.Reply("go");
402 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
405 IN_PROC_BROWSER_TEST_F(BluetoothApiTest
, DeviceInfo
) {
406 ResultCatcher catcher
;
407 catcher
.RestrictToBrowserContext(browser()->profile());
409 // Set up the first device object to reflect a real-world device.
410 BluetoothAdapter::ConstDeviceList devices
;
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));
431 BluetoothDevice::UUIDList uuids
;
432 uuids
.push_back(BluetoothUUID("1105"));
433 uuids
.push_back(BluetoothUUID("1106"));
435 EXPECT_CALL(*device1_
.get(), GetUUIDs())
436 .WillOnce(testing::Return(uuids
));
438 devices
.push_back(device1_
.get());
440 // Leave the second largely empty so we can check a device without
441 // available information.
442 devices
.push_back(device2_
.get());
444 EXPECT_CALL(*mock_adapter_
, GetDevices())
446 .WillRepeatedly(testing::Return(devices
));
448 // Load and wait for setup
449 ExtensionTestMessageListener
listener("ready", true);
451 LoadExtension(test_data_dir_
.AppendASCII("bluetooth/device_info")));
452 EXPECT_TRUE(listener
.WaitUntilSatisfied());
454 listener
.Reply("go");
456 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();