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.
5 #include "chrome/browser/extensions/extension_apitest.h"
6 #include "content/public/browser/browser_thread.h"
7 #include "content/public/test/test_utils.h"
8 #include "device/usb/usb_service.h"
9 #include "extensions/browser/api/device_permissions_prompt.h"
10 #include "extensions/browser/api/usb/usb_api.h"
11 #include "extensions/shell/browser/shell_extensions_api_client.h"
12 #include "extensions/shell/test/shell_apitest.h"
13 #include "extensions/test/extension_test_message_listener.h"
14 #include "net/base/io_buffer.h"
15 #include "testing/gmock/include/gmock/gmock.h"
18 using testing::AnyNumber
;
19 using testing::Invoke
;
20 using testing::Return
;
21 using content::BrowserThread
;
22 using device::UsbConfigDescriptor
;
23 using device::UsbDevice
;
24 using device::UsbDeviceHandle
;
25 using device::UsbEndpointDirection
;
26 using device::UsbInterfaceDescriptor
;
27 using device::UsbService
;
28 using device::UsbTransferCallback
;
30 namespace extensions
{
34 ACTION_TEMPLATE(InvokeUsbTransferCallback
,
35 HAS_1_TEMPLATE_PARAMS(int, k
),
36 AND_1_VALUE_PARAMS(p1
)) {
37 net::IOBuffer
* io_buffer
= new net::IOBuffer(1);
38 memset(io_buffer
->data(), 0, 1); // Avoid uninitialized reads.
39 ::std::tr1::get
<k
>(args
).Run(p1
, io_buffer
, 1);
42 void RequestUsbAccess(int interface_id
,
43 const base::Callback
<void(bool success
)>& callback
) {
44 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
, true));
47 class TestDevicePermissionsPrompt
48 : public DevicePermissionsPrompt
,
49 public DevicePermissionsPrompt::Prompt::Observer
{
51 TestDevicePermissionsPrompt(content::WebContents
* web_contents
)
52 : DevicePermissionsPrompt(web_contents
) {}
54 void ShowDialog() override
{ prompt()->SetObserver(this); }
56 void OnDevicesChanged() override
{
57 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
58 for (size_t i
= 0; i
< prompt()->GetDeviceCount(); ++i
) {
59 prompt()->GrantDevicePermission(i
);
60 devices
.push_back(prompt()->GetDevice(i
));
61 if (!prompt()->multiple()) {
65 delegate()->OnUsbDevicesChosen(devices
);
69 class TestExtensionsAPIClient
: public ShellExtensionsAPIClient
{
71 TestExtensionsAPIClient() : ShellExtensionsAPIClient() {}
73 scoped_ptr
<DevicePermissionsPrompt
> CreateDevicePermissionsPrompt(
74 content::WebContents
* web_contents
) const override
{
75 return make_scoped_ptr(new TestDevicePermissionsPrompt(web_contents
));
79 class MockUsbDeviceHandle
: public UsbDeviceHandle
{
81 MockUsbDeviceHandle() : UsbDeviceHandle() {}
83 MOCK_METHOD0(Close
, void());
85 MOCK_METHOD10(ControlTransfer
,
86 void(UsbEndpointDirection direction
,
87 TransferRequestType request_type
,
88 TransferRecipient recipient
,
92 net::IOBuffer
* buffer
,
95 const UsbTransferCallback
& callback
));
97 MOCK_METHOD6(BulkTransfer
,
98 void(UsbEndpointDirection direction
,
100 net::IOBuffer
* buffer
,
102 unsigned int timeout
,
103 const UsbTransferCallback
& callback
));
105 MOCK_METHOD6(InterruptTransfer
,
106 void(UsbEndpointDirection direction
,
108 net::IOBuffer
* buffer
,
110 unsigned int timeout
,
111 const UsbTransferCallback
& callback
));
113 MOCK_METHOD8(IsochronousTransfer
,
114 void(UsbEndpointDirection direction
,
116 net::IOBuffer
* buffer
,
118 unsigned int packets
,
119 unsigned int packet_length
,
120 unsigned int timeout
,
121 const UsbTransferCallback
& callback
));
123 MOCK_METHOD0(ResetDevice
, bool());
124 MOCK_METHOD2(GetStringDescriptor
, bool(uint8_t, base::string16
*));
125 MOCK_METHOD1(SetConfiguration
, bool(int));
126 MOCK_METHOD1(ClaimInterface
, bool(int interface_number
));
127 MOCK_METHOD1(ReleaseInterface
, bool(int interface_number
));
128 MOCK_METHOD2(SetInterfaceAlternateSetting
,
129 bool(int interface_number
, int alternate_setting
));
131 virtual scoped_refptr
<UsbDevice
> GetDevice() const override
{
135 void set_device(UsbDevice
* device
) { device_
= device
; }
140 virtual ~MockUsbDeviceHandle() {}
143 class MockUsbDevice
: public UsbDevice
{
145 MockUsbDevice(uint16 vendor_id
, uint16 product_id
, uint32 unique_id
)
146 : UsbDevice(vendor_id
, product_id
, unique_id
) {}
148 MOCK_METHOD2(RequestUsbAccess
, void(int, const base::Callback
<void(bool)>&));
149 MOCK_METHOD0(Open
, scoped_refptr
<UsbDeviceHandle
>());
150 MOCK_METHOD1(Close
, bool(scoped_refptr
<UsbDeviceHandle
>));
151 MOCK_METHOD0(GetConfiguration
, const device::UsbConfigDescriptor
*());
152 MOCK_METHOD1(GetManufacturer
, bool(base::string16
*));
153 MOCK_METHOD1(GetProduct
, bool(base::string16
*));
154 MOCK_METHOD1(GetSerialNumber
, bool(base::string16
*));
157 virtual ~MockUsbDevice() {}
160 class MockUsbService
: public UsbService
{
162 explicit MockUsbService(scoped_refptr
<UsbDevice
> device
) : device_(device
) {}
164 // Public wrapper around the protected base class method.
165 void NotifyDeviceAdded(scoped_refptr
<UsbDevice
> device
) {
166 UsbService::NotifyDeviceAdded(device
);
169 // Public wrapper around the protected base class method.
170 void NotifyDeviceRemoved(scoped_refptr
<UsbDevice
> device
) {
171 UsbService::NotifyDeviceRemoved(device
);
175 scoped_refptr
<UsbDevice
> GetDeviceById(uint32 unique_id
) override
{
176 EXPECT_EQ(unique_id
, 0U);
180 void GetDevices(std::vector
<scoped_refptr
<UsbDevice
>>* devices
) override
{
181 STLClearObject(devices
);
182 devices
->push_back(device_
);
185 scoped_refptr
<UsbDevice
> device_
;
188 class UsbApiTest
: public ShellApiTest
{
190 void SetUpOnMainThread() override
{
191 ShellApiTest::SetUpOnMainThread();
193 mock_device_
= new MockUsbDevice(0, 0, 0);
194 EXPECT_CALL(*mock_device_
.get(), GetManufacturer(_
))
195 .WillRepeatedly(Return(false));
196 EXPECT_CALL(*mock_device_
.get(), GetProduct(_
))
197 .WillRepeatedly(Return(false));
198 EXPECT_CALL(*mock_device_
.get(), GetSerialNumber(_
))
199 .WillRepeatedly(Return(false));
201 mock_device_handle_
= new MockUsbDeviceHandle();
202 mock_device_handle_
->set_device(mock_device_
.get());
203 EXPECT_CALL(*mock_device_
.get(), RequestUsbAccess(_
, _
))
204 .WillRepeatedly(Invoke(RequestUsbAccess
));
205 EXPECT_CALL(*mock_device_
.get(), Open())
206 .WillRepeatedly(Return(mock_device_handle_
));
208 base::RunLoop run_loop
;
209 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE
,
210 base::Bind(&UsbApiTest::SetUpService
, this),
211 run_loop
.QuitClosure());
215 void SetUpService() {
216 mock_service_
= new MockUsbService(mock_device_
);
217 UsbService::SetInstanceForTest(mock_service_
);
220 void AddTestDevices() {
221 scoped_refptr
<MockUsbDevice
> device(new MockUsbDevice(0x18D1, 0x58F0, 1));
222 EXPECT_CALL(*device
.get(), GetSerialNumber(_
))
223 .WillRepeatedly(Return(false));
224 mock_service_
->NotifyDeviceAdded(device
);
226 device
= new MockUsbDevice(0x18D1, 0x58F1, 2);
227 EXPECT_CALL(*device
.get(), GetSerialNumber(_
))
228 .WillRepeatedly(Return(false));
229 mock_service_
->NotifyDeviceAdded(device
);
233 scoped_refptr
<MockUsbDeviceHandle
> mock_device_handle_
;
234 scoped_refptr
<MockUsbDevice
> mock_device_
;
235 MockUsbService
* mock_service_
;
240 IN_PROC_BROWSER_TEST_F(UsbApiTest
, DeviceHandling
) {
241 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(2);
242 ASSERT_TRUE(RunAppTest("api_test/usb/device_handling"));
245 IN_PROC_BROWSER_TEST_F(UsbApiTest
, ResetDevice
) {
246 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(2);
247 EXPECT_CALL(*mock_device_handle_
.get(), ResetDevice())
248 .WillOnce(Return(true))
249 .WillOnce(Return(false));
250 EXPECT_CALL(*mock_device_handle_
.get(),
251 InterruptTransfer(device::USB_DIRECTION_OUTBOUND
, 2, _
, 1, _
, _
))
252 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_COMPLETED
));
253 ASSERT_TRUE(RunAppTest("api_test/usb/reset_device"));
256 IN_PROC_BROWSER_TEST_F(UsbApiTest
, SetConfiguration
) {
257 UsbConfigDescriptor config_descriptor
;
258 EXPECT_CALL(*mock_device_handle_
.get(), SetConfiguration(1))
259 .WillOnce(Return(true));
260 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(1);
261 EXPECT_CALL(*mock_device_
.get(), GetConfiguration())
262 .WillOnce(Return(nullptr))
263 .WillOnce(Return(&config_descriptor
));
264 ASSERT_TRUE(RunAppTest("api_test/usb/set_configuration"));
267 IN_PROC_BROWSER_TEST_F(UsbApiTest
, ListInterfaces
) {
268 UsbConfigDescriptor config_descriptor
;
269 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(1);
270 EXPECT_CALL(*mock_device_
.get(), GetConfiguration())
271 .WillOnce(Return(&config_descriptor
));
272 ASSERT_TRUE(RunAppTest("api_test/usb/list_interfaces"));
275 IN_PROC_BROWSER_TEST_F(UsbApiTest
, TransferEvent
) {
276 EXPECT_CALL(*mock_device_handle_
.get(),
277 ControlTransfer(device::USB_DIRECTION_OUTBOUND
,
278 UsbDeviceHandle::STANDARD
,
279 UsbDeviceHandle::DEVICE
,
287 .WillOnce(InvokeUsbTransferCallback
<9>(device::USB_TRANSFER_COMPLETED
));
288 EXPECT_CALL(*mock_device_handle_
.get(),
289 BulkTransfer(device::USB_DIRECTION_OUTBOUND
, 1, _
, 1, _
, _
))
290 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_COMPLETED
));
291 EXPECT_CALL(*mock_device_handle_
.get(),
292 InterruptTransfer(device::USB_DIRECTION_OUTBOUND
, 2, _
, 1, _
, _
))
293 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_COMPLETED
));
295 *mock_device_handle_
.get(),
296 IsochronousTransfer(device::USB_DIRECTION_OUTBOUND
, 3, _
, 1, 1, 1, _
, _
))
297 .WillOnce(InvokeUsbTransferCallback
<7>(device::USB_TRANSFER_COMPLETED
));
298 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(AnyNumber());
299 ASSERT_TRUE(RunAppTest("api_test/usb/transfer_event"));
302 IN_PROC_BROWSER_TEST_F(UsbApiTest
, ZeroLengthTransfer
) {
303 EXPECT_CALL(*mock_device_handle_
.get(), BulkTransfer(_
, _
, _
, 0, _
, _
))
304 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_COMPLETED
));
305 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(AnyNumber());
306 ASSERT_TRUE(RunAppTest("api_test/usb/zero_length_transfer"));
309 IN_PROC_BROWSER_TEST_F(UsbApiTest
, TransferFailure
) {
310 EXPECT_CALL(*mock_device_handle_
.get(), BulkTransfer(_
, _
, _
, _
, _
, _
))
311 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_COMPLETED
))
312 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_ERROR
))
313 .WillOnce(InvokeUsbTransferCallback
<5>(device::USB_TRANSFER_TIMEOUT
));
314 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(AnyNumber());
315 ASSERT_TRUE(RunAppTest("api_test/usb/transfer_failure"));
318 IN_PROC_BROWSER_TEST_F(UsbApiTest
, InvalidLengthTransfer
) {
319 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(AnyNumber());
320 ASSERT_TRUE(RunAppTest("api_test/usb/invalid_length_transfer"));
323 IN_PROC_BROWSER_TEST_F(UsbApiTest
, OnDeviceAdded
) {
324 ExtensionTestMessageListener
load_listener("loaded", false);
325 ExtensionTestMessageListener
result_listener("success", false);
326 result_listener
.set_failure_message("failure");
328 ASSERT_TRUE(LoadApp("api_test/usb/add_event"));
329 ASSERT_TRUE(load_listener
.WaitUntilSatisfied());
331 base::RunLoop run_loop
;
332 BrowserThread::PostTaskAndReply(
333 BrowserThread::FILE, FROM_HERE
,
334 base::Bind(&UsbApiTest::AddTestDevices
, base::Unretained(this)),
335 run_loop
.QuitClosure());
338 ASSERT_TRUE(result_listener
.WaitUntilSatisfied());
341 IN_PROC_BROWSER_TEST_F(UsbApiTest
, OnDeviceRemoved
) {
342 ExtensionTestMessageListener
load_listener("loaded", false);
343 ExtensionTestMessageListener
result_listener("success", false);
344 result_listener
.set_failure_message("failure");
346 ASSERT_TRUE(LoadApp("api_test/usb/remove_event"));
347 ASSERT_TRUE(load_listener
.WaitUntilSatisfied());
349 base::RunLoop run_loop
;
350 BrowserThread::PostTaskAndReply(
351 BrowserThread::FILE, FROM_HERE
,
352 base::Bind(&MockUsbService::NotifyDeviceRemoved
,
353 base::Unretained(mock_service_
), mock_device_
),
354 run_loop
.QuitClosure());
357 ASSERT_TRUE(result_listener
.WaitUntilSatisfied());
360 IN_PROC_BROWSER_TEST_F(UsbApiTest
, GetUserSelectedDevices
) {
361 ExtensionTestMessageListener
ready_listener("opened_device", false);
362 ExtensionTestMessageListener
result_listener("success", false);
363 result_listener
.set_failure_message("failure");
365 EXPECT_CALL(*mock_device_handle_
.get(), Close()).Times(1);
367 TestExtensionsAPIClient test_api_client
;
368 ASSERT_TRUE(LoadApp("api_test/usb/get_user_selected_devices"));
369 ASSERT_TRUE(ready_listener
.WaitUntilSatisfied());
371 base::RunLoop run_loop
;
372 BrowserThread::PostTaskAndReply(
373 BrowserThread::FILE, FROM_HERE
,
374 base::Bind(&MockUsbService::NotifyDeviceRemoved
,
375 base::Unretained(mock_service_
), mock_device_
),
376 run_loop
.QuitClosure());
379 ASSERT_TRUE(result_listener
.WaitUntilSatisfied());
382 } // namespace extensions