1 // Copyright 2014 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/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "device/bluetooth/bluetooth_adapter_factory.h"
11 #include "device/bluetooth/bluetooth_uuid.h"
12 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
13 #include "device/bluetooth/test/mock_bluetooth_device.h"
14 #include "device/bluetooth/test/mock_bluetooth_socket.h"
15 #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h"
16 #include "extensions/common/test_util.h"
17 #include "extensions/shell/test/shell_apitest.h"
18 #include "extensions/test/extension_test_message_listener.h"
19 #include "extensions/test/result_catcher.h"
20 #include "testing/gmock/include/gmock/gmock.h"
22 using device::BluetoothAdapter
;
23 using device::BluetoothAdapterFactory
;
24 using device::BluetoothDevice
;
25 using device::BluetoothSocket
;
26 using device::BluetoothUUID
;
27 using device::MockBluetoothAdapter
;
28 using device::MockBluetoothDevice
;
29 using device::MockBluetoothSocket
;
30 using extensions::Extension
;
31 using extensions::ResultCatcher
;
33 namespace api
= extensions::api
;
37 class BluetoothSocketApiTest
: public extensions::ShellApiTest
{
39 BluetoothSocketApiTest() {}
41 void SetUpOnMainThread() override
{
42 ShellApiTest::SetUpOnMainThread();
43 empty_extension_
= extensions::test_util::CreateEmptyExtension();
47 void SetUpMockAdapter() {
48 // The browser will clean this up when it is torn down.
49 mock_adapter_
= new testing::StrictMock
<MockBluetoothAdapter
>();
50 BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_
);
53 new testing::NiceMock
<MockBluetoothDevice
>(mock_adapter_
.get(),
58 false /* connected */));
60 new testing::NiceMock
<MockBluetoothDevice
>(mock_adapter_
.get(),
65 false /* connected */));
69 scoped_refptr
<testing::StrictMock
<MockBluetoothAdapter
> > mock_adapter_
;
70 scoped_ptr
<testing::NiceMock
<MockBluetoothDevice
> > mock_device1_
;
71 scoped_ptr
<testing::NiceMock
<MockBluetoothDevice
> > mock_device2_
;
74 scoped_refptr
<Extension
> empty_extension_
;
77 // testing::InvokeArgument<N> does not work with base::Callback, fortunately
78 // gmock makes it simple to create action templates that do for the various
79 // possible numbers of arguments.
80 ACTION_TEMPLATE(InvokeCallbackArgument
,
81 HAS_1_TEMPLATE_PARAMS(int, k
),
82 AND_0_VALUE_PARAMS()) {
83 ::std::tr1::get
<k
>(args
).Run();
86 ACTION_TEMPLATE(InvokeCallbackArgument
,
87 HAS_1_TEMPLATE_PARAMS(int, k
),
88 AND_1_VALUE_PARAMS(p0
)) {
89 ::std::tr1::get
<k
>(args
).Run(p0
);
92 ACTION_TEMPLATE(InvokeCallbackArgument
,
93 HAS_1_TEMPLATE_PARAMS(int, k
),
94 AND_2_VALUE_PARAMS(p0
, p1
)) {
95 ::std::tr1::get
<k
>(args
).Run(p0
, p1
);
100 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest
, Connect
) {
101 ResultCatcher catcher
;
102 catcher
.RestrictToBrowserContext(browser_context());
104 // Return the right mock device object for the address used by the test,
105 // return NULL for the "Device not found" test.
106 EXPECT_CALL(*mock_adapter_
.get(), GetDevice(mock_device1_
->GetAddress()))
107 .WillRepeatedly(testing::Return(mock_device1_
.get()));
108 EXPECT_CALL(*mock_adapter_
.get(), GetDevice(std::string("aa:aa:aa:aa:aa:aa")))
109 .WillOnce(testing::Return(static_cast<BluetoothDevice
*>(NULL
)));
111 // Return a mock socket object as a successful result to the connect() call.
112 BluetoothUUID
service_uuid("8e3ad063-db38-4289-aa8f-b30e4223cf40");
113 scoped_refptr
<testing::StrictMock
<MockBluetoothSocket
> > mock_socket
114 = new testing::StrictMock
<MockBluetoothSocket
>();
115 EXPECT_CALL(*mock_device1_
,
116 ConnectToService(service_uuid
, testing::_
, testing::_
))
117 .WillOnce(InvokeCallbackArgument
<1>(mock_socket
));
119 // Since the socket is unpaused, expect a call to Receive() from the socket
120 // dispatcher. Since there is no data, this will not call its callback.
121 EXPECT_CALL(*mock_socket
.get(), Receive(testing::_
, testing::_
, testing::_
));
123 // The test also cleans up by calling Disconnect and Close.
124 EXPECT_CALL(*mock_socket
.get(), Disconnect(testing::_
))
125 .WillOnce(InvokeCallbackArgument
<0>());
126 EXPECT_CALL(*mock_socket
.get(), Close());
129 ExtensionTestMessageListener
listener("ready", true);
130 scoped_refptr
<const Extension
> extension(
131 LoadApp("api_test/bluetooth_socket/connect"));
132 ASSERT_TRUE(extension
.get());
133 EXPECT_TRUE(listener
.WaitUntilSatisfied());
135 listener
.Reply("go");
136 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
139 #if defined(_LIBCPP_VERSION)
140 // This test fails in libc++ builds, see http://crbug.com/392205.
141 #define MAYBE_Listen DISABLED_Listen
143 #define MAYBE_Listen Listen
145 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest
, MAYBE_Listen
) {
146 ResultCatcher catcher
;
147 catcher
.RestrictToBrowserContext(browser_context());
149 // Return a mock socket object as a successful result to the create service
151 BluetoothUUID
service_uuid("2de497f9-ab28-49db-b6d2-066ea69f1737");
152 scoped_refptr
<testing::StrictMock
<MockBluetoothSocket
> > mock_server_socket
153 = new testing::StrictMock
<MockBluetoothSocket
>();
154 BluetoothAdapter::ServiceOptions service_options
;
155 service_options
.name
.reset(new std::string("MyServiceName"));
157 *mock_adapter_
.get(),
160 testing::Field(&BluetoothAdapter::ServiceOptions::name
,
161 testing::Pointee(testing::Eq("MyServiceName"))),
163 testing::_
)).WillOnce(InvokeCallbackArgument
<2>(mock_server_socket
));
165 // Since the socket is unpaused, expect a call to Accept() from the socket
166 // dispatcher. We'll immediately send back another mock socket to represent
167 // the client API. Further calls will return no data and behave as if
169 scoped_refptr
<testing::StrictMock
<MockBluetoothSocket
> > mock_client_socket
170 = new testing::StrictMock
<MockBluetoothSocket
>();
171 EXPECT_CALL(*mock_server_socket
.get(), Accept(testing::_
, testing::_
))
174 InvokeCallbackArgument
<0>(mock_device1_
.get(), mock_client_socket
))
175 .WillOnce(testing::Return());
177 // Run the test, it sends a ready signal once it's ready for us to dispatch
178 // a client connection to it.
179 ExtensionTestMessageListener
socket_listening("ready", true);
180 scoped_refptr
<const Extension
> extension(
181 LoadApp("api_test/bluetooth_socket/listen"));
182 ASSERT_TRUE(extension
.get());
183 EXPECT_TRUE(socket_listening
.WaitUntilSatisfied());
185 // Connection events are dispatched using a couple of PostTask to the UI
186 // thread. Waiting until idle ensures the event is dispatched to the
188 base::RunLoop().RunUntilIdle();
189 ExtensionTestMessageListener
listener("ready", true);
190 socket_listening
.Reply("go");
192 // Second stage of tests checks for error conditions, and will clean up
193 // the existing server and client sockets.
194 EXPECT_CALL(*mock_server_socket
.get(), Disconnect(testing::_
))
195 .WillOnce(InvokeCallbackArgument
<0>());
196 EXPECT_CALL(*mock_server_socket
.get(), Close());
198 EXPECT_CALL(*mock_client_socket
.get(), Disconnect(testing::_
))
199 .WillOnce(InvokeCallbackArgument
<0>());
200 EXPECT_CALL(*mock_client_socket
.get(), Close());
202 EXPECT_TRUE(listener
.WaitUntilSatisfied());
203 listener
.Reply("go");
204 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
207 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest
, PermissionDenied
) {
208 ResultCatcher catcher
;
209 catcher
.RestrictToBrowserContext(browser_context());
212 scoped_refptr
<const Extension
> extension(
213 LoadApp("api_test/bluetooth_socket/permission_denied"));
214 ASSERT_TRUE(extension
.get());
216 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();