Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / extensions / browser / api / usb / usb_apitest.cc
blobad36408d0bc32dc9771517a7033f9c2c3268d139
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"
17 using testing::_;
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 {
32 namespace {
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 class TestDevicePermissionsPrompt
43 : public DevicePermissionsPrompt,
44 public DevicePermissionsPrompt::Prompt::Observer {
45 public:
46 TestDevicePermissionsPrompt(content::WebContents* web_contents)
47 : DevicePermissionsPrompt(web_contents) {}
49 void ShowDialog() override { prompt()->SetObserver(this); }
51 void OnDevicesChanged() override {
52 std::vector<scoped_refptr<UsbDevice>> devices;
53 for (size_t i = 0; i < prompt()->GetDeviceCount(); ++i) {
54 prompt()->GrantDevicePermission(i);
55 devices.push_back(prompt()->GetDevice(i));
56 if (!prompt()->multiple()) {
57 break;
60 delegate()->OnUsbDevicesChosen(devices);
64 class TestExtensionsAPIClient : public ShellExtensionsAPIClient {
65 public:
66 TestExtensionsAPIClient() : ShellExtensionsAPIClient() {}
68 scoped_ptr<DevicePermissionsPrompt> CreateDevicePermissionsPrompt(
69 content::WebContents* web_contents) const override {
70 return make_scoped_ptr(new TestDevicePermissionsPrompt(web_contents));
74 class MockUsbDeviceHandle : public UsbDeviceHandle {
75 public:
76 MockUsbDeviceHandle() : UsbDeviceHandle() {}
78 MOCK_METHOD0(Close, void());
80 MOCK_METHOD10(ControlTransfer,
81 void(UsbEndpointDirection direction,
82 TransferRequestType request_type,
83 TransferRecipient recipient,
84 uint8 request,
85 uint16 value,
86 uint16 index,
87 net::IOBuffer* buffer,
88 size_t length,
89 unsigned int timeout,
90 const UsbTransferCallback& callback));
92 MOCK_METHOD6(BulkTransfer,
93 void(UsbEndpointDirection direction,
94 uint8 endpoint,
95 net::IOBuffer* buffer,
96 size_t length,
97 unsigned int timeout,
98 const UsbTransferCallback& callback));
100 MOCK_METHOD6(InterruptTransfer,
101 void(UsbEndpointDirection direction,
102 uint8 endpoint,
103 net::IOBuffer* buffer,
104 size_t length,
105 unsigned int timeout,
106 const UsbTransferCallback& callback));
108 MOCK_METHOD8(IsochronousTransfer,
109 void(UsbEndpointDirection direction,
110 uint8 endpoint,
111 net::IOBuffer* buffer,
112 size_t length,
113 unsigned int packets,
114 unsigned int packet_length,
115 unsigned int timeout,
116 const UsbTransferCallback& callback));
118 MOCK_METHOD0(ResetDevice, bool());
119 MOCK_METHOD2(GetStringDescriptor, bool(uint8_t, base::string16*));
120 MOCK_METHOD1(SetConfiguration, bool(int));
121 MOCK_METHOD1(ClaimInterface, bool(int interface_number));
122 MOCK_METHOD1(ReleaseInterface, bool(int interface_number));
123 MOCK_METHOD2(SetInterfaceAlternateSetting,
124 bool(int interface_number, int alternate_setting));
126 virtual scoped_refptr<UsbDevice> GetDevice() const override {
127 return device_;
130 void set_device(UsbDevice* device) { device_ = device; }
132 protected:
133 UsbDevice* device_;
135 virtual ~MockUsbDeviceHandle() {}
138 class MockUsbDevice : public UsbDevice {
139 public:
140 MockUsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
141 : UsbDevice(vendor_id, product_id, unique_id) {}
143 MOCK_METHOD0(Open, scoped_refptr<UsbDeviceHandle>());
144 MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>));
145 MOCK_METHOD0(GetConfiguration, const device::UsbConfigDescriptor*());
146 MOCK_METHOD1(GetManufacturer, bool(base::string16*));
147 MOCK_METHOD1(GetProduct, bool(base::string16*));
148 MOCK_METHOD1(GetSerialNumber, bool(base::string16*));
150 private:
151 virtual ~MockUsbDevice() {}
154 class MockUsbService : public UsbService {
155 public:
156 explicit MockUsbService(scoped_refptr<UsbDevice> device) : device_(device) {}
158 // Public wrapper around the protected base class method.
159 void NotifyDeviceAdded(scoped_refptr<UsbDevice> device) {
160 UsbService::NotifyDeviceAdded(device);
163 // Public wrapper around the protected base class method.
164 void NotifyDeviceRemoved(scoped_refptr<UsbDevice> device) {
165 UsbService::NotifyDeviceRemoved(device);
168 protected:
169 scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
170 EXPECT_EQ(unique_id, 0U);
171 return device_;
174 void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
175 STLClearObject(devices);
176 devices->push_back(device_);
179 scoped_refptr<UsbDevice> device_;
182 class UsbApiTest : public ShellApiTest {
183 public:
184 void SetUpOnMainThread() override {
185 ShellApiTest::SetUpOnMainThread();
187 mock_device_ = new MockUsbDevice(0, 0, 0);
188 EXPECT_CALL(*mock_device_.get(), GetManufacturer(_))
189 .WillRepeatedly(Return(false));
190 EXPECT_CALL(*mock_device_.get(), GetProduct(_))
191 .WillRepeatedly(Return(false));
192 EXPECT_CALL(*mock_device_.get(), GetSerialNumber(_))
193 .WillRepeatedly(Return(false));
195 mock_device_handle_ = new MockUsbDeviceHandle();
196 mock_device_handle_->set_device(mock_device_.get());
197 EXPECT_CALL(*mock_device_.get(), Open())
198 .WillRepeatedly(Return(mock_device_handle_));
200 base::RunLoop run_loop;
201 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
202 base::Bind(&UsbApiTest::SetUpService, this),
203 run_loop.QuitClosure());
204 run_loop.Run();
207 void SetUpService() {
208 mock_service_ = new MockUsbService(mock_device_);
209 UsbService::SetInstanceForTest(mock_service_);
212 void AddTestDevices() {
213 scoped_refptr<MockUsbDevice> device(new MockUsbDevice(0x18D1, 0x58F0, 1));
214 EXPECT_CALL(*device.get(), GetSerialNumber(_))
215 .WillRepeatedly(Return(false));
216 mock_service_->NotifyDeviceAdded(device);
218 device = new MockUsbDevice(0x18D1, 0x58F1, 2);
219 EXPECT_CALL(*device.get(), GetSerialNumber(_))
220 .WillRepeatedly(Return(false));
221 mock_service_->NotifyDeviceAdded(device);
224 protected:
225 scoped_refptr<MockUsbDeviceHandle> mock_device_handle_;
226 scoped_refptr<MockUsbDevice> mock_device_;
227 MockUsbService* mock_service_;
230 } // namespace
232 IN_PROC_BROWSER_TEST_F(UsbApiTest, DeviceHandling) {
233 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(2);
234 ASSERT_TRUE(RunAppTest("api_test/usb/device_handling"));
237 IN_PROC_BROWSER_TEST_F(UsbApiTest, ResetDevice) {
238 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(2);
239 EXPECT_CALL(*mock_device_handle_.get(), ResetDevice())
240 .WillOnce(Return(true))
241 .WillOnce(Return(false));
242 EXPECT_CALL(*mock_device_handle_.get(),
243 InterruptTransfer(device::USB_DIRECTION_OUTBOUND, 2, _, 1, _, _))
244 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED));
245 ASSERT_TRUE(RunAppTest("api_test/usb/reset_device"));
248 IN_PROC_BROWSER_TEST_F(UsbApiTest, SetConfiguration) {
249 UsbConfigDescriptor config_descriptor;
250 EXPECT_CALL(*mock_device_handle_.get(), SetConfiguration(1))
251 .WillOnce(Return(true));
252 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(1);
253 EXPECT_CALL(*mock_device_.get(), GetConfiguration())
254 .WillOnce(Return(nullptr))
255 .WillOnce(Return(&config_descriptor));
256 ASSERT_TRUE(RunAppTest("api_test/usb/set_configuration"));
259 IN_PROC_BROWSER_TEST_F(UsbApiTest, ListInterfaces) {
260 UsbConfigDescriptor config_descriptor;
261 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(1);
262 EXPECT_CALL(*mock_device_.get(), GetConfiguration())
263 .WillOnce(Return(&config_descriptor));
264 ASSERT_TRUE(RunAppTest("api_test/usb/list_interfaces"));
267 IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferEvent) {
268 EXPECT_CALL(*mock_device_handle_.get(),
269 ControlTransfer(device::USB_DIRECTION_OUTBOUND,
270 UsbDeviceHandle::STANDARD,
271 UsbDeviceHandle::DEVICE,
279 .WillOnce(InvokeUsbTransferCallback<9>(device::USB_TRANSFER_COMPLETED));
280 EXPECT_CALL(*mock_device_handle_.get(),
281 BulkTransfer(device::USB_DIRECTION_OUTBOUND, 1, _, 1, _, _))
282 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED));
283 EXPECT_CALL(*mock_device_handle_.get(),
284 InterruptTransfer(device::USB_DIRECTION_OUTBOUND, 2, _, 1, _, _))
285 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED));
286 EXPECT_CALL(
287 *mock_device_handle_.get(),
288 IsochronousTransfer(device::USB_DIRECTION_OUTBOUND, 3, _, 1, 1, 1, _, _))
289 .WillOnce(InvokeUsbTransferCallback<7>(device::USB_TRANSFER_COMPLETED));
290 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber());
291 ASSERT_TRUE(RunAppTest("api_test/usb/transfer_event"));
294 IN_PROC_BROWSER_TEST_F(UsbApiTest, ZeroLengthTransfer) {
295 EXPECT_CALL(*mock_device_handle_.get(), BulkTransfer(_, _, _, 0, _, _))
296 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED));
297 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber());
298 ASSERT_TRUE(RunAppTest("api_test/usb/zero_length_transfer"));
301 IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferFailure) {
302 EXPECT_CALL(*mock_device_handle_.get(), BulkTransfer(_, _, _, _, _, _))
303 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED))
304 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_ERROR))
305 .WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_TIMEOUT));
306 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber());
307 ASSERT_TRUE(RunAppTest("api_test/usb/transfer_failure"));
310 IN_PROC_BROWSER_TEST_F(UsbApiTest, InvalidLengthTransfer) {
311 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber());
312 ASSERT_TRUE(RunAppTest("api_test/usb/invalid_length_transfer"));
315 IN_PROC_BROWSER_TEST_F(UsbApiTest, InvalidTimeout) {
316 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber());
317 ASSERT_TRUE(RunAppTest("api_test/usb/invalid_timeout"));
320 IN_PROC_BROWSER_TEST_F(UsbApiTest, OnDeviceAdded) {
321 ExtensionTestMessageListener load_listener("loaded", false);
322 ExtensionTestMessageListener result_listener("success", false);
323 result_listener.set_failure_message("failure");
325 ASSERT_TRUE(LoadApp("api_test/usb/add_event"));
326 ASSERT_TRUE(load_listener.WaitUntilSatisfied());
328 base::RunLoop run_loop;
329 BrowserThread::PostTaskAndReply(
330 BrowserThread::FILE, FROM_HERE,
331 base::Bind(&UsbApiTest::AddTestDevices, base::Unretained(this)),
332 run_loop.QuitClosure());
333 run_loop.Run();
335 ASSERT_TRUE(result_listener.WaitUntilSatisfied());
338 IN_PROC_BROWSER_TEST_F(UsbApiTest, OnDeviceRemoved) {
339 ExtensionTestMessageListener load_listener("loaded", false);
340 ExtensionTestMessageListener result_listener("success", false);
341 result_listener.set_failure_message("failure");
343 ASSERT_TRUE(LoadApp("api_test/usb/remove_event"));
344 ASSERT_TRUE(load_listener.WaitUntilSatisfied());
346 base::RunLoop run_loop;
347 BrowserThread::PostTaskAndReply(
348 BrowserThread::FILE, FROM_HERE,
349 base::Bind(&MockUsbService::NotifyDeviceRemoved,
350 base::Unretained(mock_service_), mock_device_),
351 run_loop.QuitClosure());
352 run_loop.Run();
354 ASSERT_TRUE(result_listener.WaitUntilSatisfied());
357 IN_PROC_BROWSER_TEST_F(UsbApiTest, GetUserSelectedDevices) {
358 ExtensionTestMessageListener ready_listener("opened_device", false);
359 ExtensionTestMessageListener result_listener("success", false);
360 result_listener.set_failure_message("failure");
362 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(1);
364 TestExtensionsAPIClient test_api_client;
365 ASSERT_TRUE(LoadApp("api_test/usb/get_user_selected_devices"));
366 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
368 base::RunLoop run_loop;
369 BrowserThread::PostTaskAndReply(
370 BrowserThread::FILE, FROM_HERE,
371 base::Bind(&MockUsbService::NotifyDeviceRemoved,
372 base::Unretained(mock_service_), mock_device_),
373 run_loop.QuitClosure());
374 run_loop.Run();
376 ASSERT_TRUE(result_listener.WaitUntilSatisfied());
379 } // namespace extensions