1 // Copyright 2015 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.
10 #include "base/bind.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "device/devices_app/usb/device_impl.h"
16 #include "device/usb/mock_usb_device.h"
17 #include "device/usb/mock_usb_device_handle.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
21 using ::testing::Invoke
;
31 ConfigBuilder(uint8_t value
) { config_
.configuration_value
= value
; }
33 ConfigBuilder
& AddInterface(uint8_t interface_number
,
34 uint8_t alternate_setting
,
36 uint8_t subclass_code
,
37 uint8_t protocol_code
) {
38 UsbInterfaceDescriptor interface
;
39 interface
.interface_number
= interface_number
;
40 interface
.alternate_setting
= alternate_setting
;
41 interface
.interface_class
= class_code
;
42 interface
.interface_subclass
= subclass_code
;
43 interface
.interface_protocol
= protocol_code
;
44 config_
.interfaces
.push_back(interface
);
48 const UsbConfigDescriptor
& config() const { return config_
; }
51 UsbConfigDescriptor config_
;
54 void ExpectDeviceInfoAndThen(const std::string
& guid
,
57 const std::string
& manufacturer_name
,
58 const std::string
& product_name
,
59 const std::string
& serial_number
,
60 const base::Closure
& continuation
,
61 DeviceInfoPtr device_info
) {
62 EXPECT_EQ(guid
, device_info
->guid
);
63 EXPECT_EQ(vendor_id
, device_info
->vendor_id
);
64 EXPECT_EQ(product_id
, device_info
->product_id
);
65 EXPECT_EQ(manufacturer_name
, device_info
->manufacturer_name
);
66 EXPECT_EQ(product_name
, device_info
->product_name
);
67 EXPECT_EQ(serial_number
, device_info
->serial_number
);
71 void ExpectResultAndThen(bool expected_result
,
72 const base::Closure
& continuation
,
74 EXPECT_EQ(expected_result
, actual_result
);
78 void ExpectTransferInAndThen(TransferStatus expected_status
,
79 const std::vector
<uint8_t>& expected_bytes
,
80 const base::Closure
& continuation
,
81 TransferStatus actual_status
,
82 mojo::Array
<uint8_t> actual_bytes
) {
83 EXPECT_EQ(expected_status
, actual_status
);
84 ASSERT_EQ(expected_bytes
.size(), actual_bytes
.size());
85 for (size_t i
= 0; i
< actual_bytes
.size(); ++i
) {
86 EXPECT_EQ(expected_bytes
[i
], actual_bytes
[i
])
87 << "Contents differ at index: " << i
;
92 void ExpectPacketsAndThen(
93 TransferStatus expected_status
,
94 const std::vector
<std::vector
<uint8_t>>& expected_packets
,
95 const base::Closure
& continuation
,
96 TransferStatus actual_status
,
97 mojo::Array
<mojo::Array
<uint8_t>> actual_packets
) {
98 EXPECT_EQ(expected_status
, actual_status
);
99 ASSERT_EQ(expected_packets
.size(), actual_packets
.size());
100 for (size_t i
= 0; i
< expected_packets
.size(); ++i
) {
101 EXPECT_EQ(expected_packets
[i
].size(), actual_packets
[i
].size())
102 << "Packet sizes differ at index: " << i
;
103 for (size_t j
= 0; j
< expected_packets
[i
].size(); ++j
) {
104 EXPECT_EQ(expected_packets
[i
][j
], actual_packets
[i
][j
])
105 << "Contents of packet " << i
<< " differ at index " << j
;
111 void ExpectTransferStatusAndThen(TransferStatus expected_status
,
112 const base::Closure
& continuation
,
113 TransferStatus actual_status
) {
114 EXPECT_EQ(expected_status
, actual_status
);
118 class USBDeviceImplTest
: public testing::Test
{
121 : message_loop_(new base::MessageLoop
),
122 is_device_open_(false),
124 current_config_(0) {}
126 ~USBDeviceImplTest() override
{}
129 MockUsbDevice
& mock_device() { return *mock_device_
.get(); }
130 bool is_device_open() const { return is_device_open_
; }
131 MockUsbDeviceHandle
& mock_handle() { return *mock_handle_
.get(); }
133 void set_allow_reset(bool allow_reset
) { allow_reset_
= allow_reset
; }
135 // Creates a mock device and binds a Device proxy to a Device service impl
136 // wrapping the mock device.
137 DevicePtr
GetMockDeviceProxy(uint16_t vendor_id
,
139 const std::string
& manufacturer
,
140 const std::string
& product
,
141 const std::string
& serial
) {
142 is_device_open_
= true;
145 new MockUsbDevice(vendor_id
, product_id
, manufacturer
, product
, serial
);
146 mock_handle_
= new MockUsbDeviceHandle(mock_device_
.get());
149 new DeviceImpl(mock_handle_
, mojo::GetProxy(&proxy
));
151 // Set up mock handle calls to respond based on mock device configs
152 // established by the test.
153 ON_CALL(mock_handle(), Close())
154 .WillByDefault(Invoke(this, &USBDeviceImplTest::CloseMockHandle
));
155 ON_CALL(mock_handle(), SetConfiguration(_
, _
))
156 .WillByDefault(Invoke(this, &USBDeviceImplTest::SetConfiguration
));
157 ON_CALL(mock_handle(), ClaimInterface(_
, _
))
158 .WillByDefault(Invoke(this, &USBDeviceImplTest::ClaimInterface
));
159 ON_CALL(mock_handle(), ReleaseInterface(_
))
160 .WillByDefault(Invoke(this, &USBDeviceImplTest::ReleaseInterface
));
161 ON_CALL(mock_handle(), SetInterfaceAlternateSetting(_
, _
, _
))
163 Invoke(this, &USBDeviceImplTest::SetInterfaceAlternateSetting
));
164 ON_CALL(mock_handle(), ResetDevice(_
))
165 .WillByDefault(Invoke(this, &USBDeviceImplTest::ResetDevice
));
166 ON_CALL(mock_handle(), ControlTransfer(_
, _
, _
, _
, _
, _
, _
, _
, _
, _
))
167 .WillByDefault(Invoke(this, &USBDeviceImplTest::ControlTransfer
));
168 ON_CALL(mock_handle(), GenericTransfer(_
, _
, _
, _
, _
, _
))
169 .WillByDefault(Invoke(this, &USBDeviceImplTest::GenericTransfer
));
170 ON_CALL(mock_handle(), IsochronousTransfer(_
, _
, _
, _
, _
, _
, _
, _
))
171 .WillByDefault(Invoke(this, &USBDeviceImplTest::IsochronousTransfer
));
176 DevicePtr
GetMockDeviceProxy() {
177 return GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
180 void AddMockConfig(const ConfigBuilder
& builder
) {
181 const UsbConfigDescriptor
& config
= builder
.config();
182 DCHECK(!ContainsKey(mock_configs_
, config
.configuration_value
));
183 mock_configs_
[config
.configuration_value
] = config
;
186 void AddMockInboundData(const std::vector
<uint8_t>& data
) {
187 mock_inbound_data_
.push(data
);
190 void AddMockOutboundData(const std::vector
<uint8_t>& data
) {
191 mock_outbound_data_
.push(data
);
195 void CloseMockHandle() {
196 EXPECT_TRUE(is_device_open_
);
197 is_device_open_
= false;
200 void SetConfiguration(uint8_t value
,
201 const UsbDeviceHandle::ResultCallback
& callback
) {
202 if (mock_configs_
.find(value
) != mock_configs_
.end()) {
203 current_config_
= value
;
210 void ClaimInterface(uint8_t interface_number
,
211 const UsbDeviceHandle::ResultCallback
& callback
) {
212 for (const auto& config
: mock_configs_
) {
213 for (const auto& interface
: config
.second
.interfaces
) {
214 if (interface
.interface_number
== interface_number
) {
215 claimed_interfaces_
.insert(interface_number
);
224 bool ReleaseInterface(uint8_t interface_number
) {
225 if (ContainsKey(claimed_interfaces_
, interface_number
)) {
226 claimed_interfaces_
.erase(interface_number
);
232 void SetInterfaceAlternateSetting(
233 uint8_t interface_number
,
234 uint8_t alternate_setting
,
235 const UsbDeviceHandle::ResultCallback
& callback
) {
236 for (const auto& config
: mock_configs_
) {
237 for (const auto& interface
: config
.second
.interfaces
) {
238 if (interface
.interface_number
== interface_number
&&
239 interface
.alternate_setting
== alternate_setting
) {
248 void ResetDevice(const UsbDeviceHandle::ResultCallback
& callback
) {
249 callback
.Run(allow_reset_
);
252 void InboundTransfer(const UsbDeviceHandle::TransferCallback
& callback
) {
253 ASSERT_GE(mock_inbound_data_
.size(), 1u);
254 const std::vector
<uint8_t>& bytes
= mock_inbound_data_
.front();
255 size_t length
= bytes
.size();
256 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(length
);
257 std::copy(bytes
.begin(), bytes
.end(), buffer
->data());
258 mock_inbound_data_
.pop();
259 callback
.Run(USB_TRANSFER_COMPLETED
, buffer
, length
);
262 void OutboundTransfer(scoped_refptr
<net::IOBuffer
> buffer
,
264 const UsbDeviceHandle::TransferCallback
& callback
) {
265 ASSERT_GE(mock_outbound_data_
.size(), 1u);
266 const std::vector
<uint8_t>& bytes
= mock_outbound_data_
.front();
267 ASSERT_EQ(bytes
.size(), length
);
268 for (size_t i
= 0; i
< length
; ++i
) {
269 EXPECT_EQ(bytes
[i
], buffer
->data()[i
])
270 << "Contents differ at index: " << i
;
272 mock_outbound_data_
.pop();
273 callback
.Run(USB_TRANSFER_COMPLETED
, buffer
, length
);
276 void ControlTransfer(UsbEndpointDirection direction
,
277 UsbDeviceHandle::TransferRequestType request_type
,
278 UsbDeviceHandle::TransferRecipient recipient
,
282 scoped_refptr
<net::IOBuffer
> buffer
,
284 unsigned int timeout
,
285 const UsbDeviceHandle::TransferCallback
& callback
) {
286 if (direction
== USB_DIRECTION_INBOUND
)
287 InboundTransfer(callback
);
289 OutboundTransfer(buffer
, length
, callback
);
292 void GenericTransfer(UsbEndpointDirection direction
,
294 scoped_refptr
<net::IOBuffer
> buffer
,
296 unsigned int timeout
,
297 const UsbDeviceHandle::TransferCallback
& callback
) {
298 if (direction
== USB_DIRECTION_INBOUND
)
299 InboundTransfer(callback
);
301 OutboundTransfer(buffer
, length
, callback
);
304 void IsochronousTransfer(UsbEndpointDirection direction
,
306 scoped_refptr
<net::IOBuffer
> buffer
,
308 unsigned int packets
,
309 unsigned int packet_length
,
310 unsigned int timeout
,
311 const UsbDeviceHandle::TransferCallback
& callback
) {
312 if (direction
== USB_DIRECTION_INBOUND
)
313 InboundTransfer(callback
);
315 OutboundTransfer(buffer
, length
, callback
);
318 scoped_ptr
<base::MessageLoop
> message_loop_
;
319 scoped_refptr
<MockUsbDevice
> mock_device_
;
320 scoped_refptr
<MockUsbDeviceHandle
> mock_handle_
;
321 bool is_device_open_
;
324 std::map
<uint8_t, UsbConfigDescriptor
> mock_configs_
;
325 uint8_t current_config_
;
327 std::queue
<std::vector
<uint8_t>> mock_inbound_data_
;
328 std::queue
<std::vector
<uint8_t>> mock_outbound_data_
;
330 std::set
<uint8_t> claimed_interfaces_
;
332 DISALLOW_COPY_AND_ASSIGN(USBDeviceImplTest
);
337 TEST_F(USBDeviceImplTest
, Close
) {
338 DevicePtr device
= GetMockDeviceProxy();
340 EXPECT_TRUE(is_device_open());
342 EXPECT_CALL(mock_handle(), Close());
345 device
->Close(loop
.QuitClosure());
348 EXPECT_FALSE(is_device_open());
351 // Test that the information returned via the Device::GetDeviceInfo matches that
352 // of the underlying device.
353 TEST_F(USBDeviceImplTest
, GetDeviceInfo
) {
355 GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
358 device
->GetDeviceInfo(base::Bind(&ExpectDeviceInfoAndThen
,
359 mock_device().guid(), 0x1234, 0x5678, "ACME",
360 "Frobinator", "ABCDEF", loop
.QuitClosure()));
363 EXPECT_CALL(mock_handle(), Close());
366 TEST_F(USBDeviceImplTest
, SetInvalidConfiguration
) {
367 DevicePtr device
= GetMockDeviceProxy();
369 EXPECT_CALL(mock_handle(), SetConfiguration(42, _
));
371 // SetConfiguration should fail because 42 is not a valid mock configuration.
373 device
->SetConfiguration(
374 42, base::Bind(&ExpectResultAndThen
, false, loop
.QuitClosure()));
377 EXPECT_CALL(mock_handle(), Close());
380 TEST_F(USBDeviceImplTest
, SetValidConfiguration
) {
381 DevicePtr device
= GetMockDeviceProxy();
383 EXPECT_CALL(mock_handle(), SetConfiguration(42, _
));
385 AddMockConfig(ConfigBuilder(42));
387 // SetConfiguration should succeed because 42 is a valid mock configuration.
389 device
->SetConfiguration(
390 42, base::Bind(&ExpectResultAndThen
, true, loop
.QuitClosure()));
393 EXPECT_CALL(mock_handle(), Close());
396 // Verify that the result of Reset() reflects the underlying UsbDeviceHandle's
397 // ResetDevice() result.
398 TEST_F(USBDeviceImplTest
, Reset
) {
399 DevicePtr device
= GetMockDeviceProxy();
401 EXPECT_CALL(mock_handle(), ResetDevice(_
));
403 set_allow_reset(true);
407 device
->Reset(base::Bind(&ExpectResultAndThen
, true, loop
.QuitClosure()));
411 EXPECT_CALL(mock_handle(), ResetDevice(_
));
413 set_allow_reset(false);
417 device
->Reset(base::Bind(&ExpectResultAndThen
, false, loop
.QuitClosure()));
421 EXPECT_CALL(mock_handle(), Close());
424 TEST_F(USBDeviceImplTest
, ClaimAndReleaseInterface
) {
425 DevicePtr device
= GetMockDeviceProxy();
427 // Now add a mock interface #1.
428 AddMockConfig(ConfigBuilder(0).AddInterface(1, 0, 1, 2, 3));
430 EXPECT_CALL(mock_handle(), ClaimInterface(2, _
));
433 // Try to claim an invalid interface and expect failure.
435 device
->ClaimInterface(
436 2, base::Bind(&ExpectResultAndThen
, false, loop
.QuitClosure()));
440 EXPECT_CALL(mock_handle(), ClaimInterface(1, _
));
444 device
->ClaimInterface(
445 1, base::Bind(&ExpectResultAndThen
, true, loop
.QuitClosure()));
449 EXPECT_CALL(mock_handle(), ReleaseInterface(2));
452 // Releasing a non-existent interface should fail.
454 device
->ReleaseInterface(
455 2, base::Bind(&ExpectResultAndThen
, false, loop
.QuitClosure()));
459 EXPECT_CALL(mock_handle(), ReleaseInterface(1));
462 // Now this should release the claimed interface and close the handle.
464 device
->ReleaseInterface(
465 1, base::Bind(&ExpectResultAndThen
, true, loop
.QuitClosure()));
469 EXPECT_CALL(mock_handle(), Close());
472 TEST_F(USBDeviceImplTest
, SetInterfaceAlternateSetting
) {
473 DevicePtr device
= GetMockDeviceProxy();
475 AddMockConfig(ConfigBuilder(0)
476 .AddInterface(1, 0, 1, 2, 3)
477 .AddInterface(1, 42, 1, 2, 3)
478 .AddInterface(2, 0, 1, 2, 3));
480 EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 42, _
));
484 device
->SetInterfaceAlternateSetting(
485 1, 42, base::Bind(&ExpectResultAndThen
, true, loop
.QuitClosure()));
489 EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 100, _
));
493 device
->SetInterfaceAlternateSetting(
494 1, 100, base::Bind(&ExpectResultAndThen
, false, loop
.QuitClosure()));
498 EXPECT_CALL(mock_handle(), Close());
501 TEST_F(USBDeviceImplTest
, ControlTransfer
) {
502 DevicePtr device
= GetMockDeviceProxy();
504 std::vector
<uint8_t> fake_data
;
505 fake_data
.push_back(41);
506 fake_data
.push_back(42);
507 fake_data
.push_back(43);
509 AddMockInboundData(fake_data
);
511 EXPECT_CALL(mock_handle(),
512 ControlTransfer(USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
,
513 UsbDeviceHandle::DEVICE
, 5, 6, 7, _
, _
, 0, _
));
516 auto params
= ControlTransferParams::New();
517 params
->type
= CONTROL_TRANSFER_TYPE_STANDARD
;
518 params
->recipient
= CONTROL_TRANSFER_RECIPIENT_DEVICE
;
523 device
->ControlTransferIn(
524 params
.Pass(), static_cast<uint32_t>(fake_data
.size()), 0,
525 base::Bind(&ExpectTransferInAndThen
, TRANSFER_STATUS_COMPLETED
,
526 fake_data
, loop
.QuitClosure()));
530 AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
531 AddMockOutboundData(fake_data
);
533 EXPECT_CALL(mock_handle(),
534 ControlTransfer(USB_DIRECTION_OUTBOUND
, UsbDeviceHandle::STANDARD
,
535 UsbDeviceHandle::INTERFACE
, 5, 6, 7, _
, _
, 0, _
));
538 auto params
= ControlTransferParams::New();
539 params
->type
= CONTROL_TRANSFER_TYPE_STANDARD
;
540 params
->recipient
= CONTROL_TRANSFER_RECIPIENT_INTERFACE
;
545 device
->ControlTransferOut(
546 params
.Pass(), mojo::Array
<uint8_t>::From(fake_data
), 0,
547 base::Bind(&ExpectTransferStatusAndThen
, TRANSFER_STATUS_COMPLETED
,
548 loop
.QuitClosure()));
552 EXPECT_CALL(mock_handle(), Close());
555 TEST_F(USBDeviceImplTest
, GenericTransfer
) {
556 DevicePtr device
= GetMockDeviceProxy();
558 std::string message1
= "say hello please";
559 std::vector
<uint8_t> fake_outbound_data(message1
.size());
560 std::copy(message1
.begin(), message1
.end(), fake_outbound_data
.begin());
562 std::string message2
= "hello world!";
563 std::vector
<uint8_t> fake_inbound_data(message2
.size());
564 std::copy(message2
.begin(), message2
.end(), fake_inbound_data
.begin());
566 AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
567 AddMockOutboundData(fake_outbound_data
);
568 AddMockInboundData(fake_inbound_data
);
570 EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_OUTBOUND
, 0, _
,
571 fake_outbound_data
.size(), 0, _
));
575 device
->GenericTransferOut(
576 0, mojo::Array
<uint8_t>::From(fake_outbound_data
), 0,
577 base::Bind(&ExpectTransferStatusAndThen
, TRANSFER_STATUS_COMPLETED
,
578 loop
.QuitClosure()));
582 EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_INBOUND
, 0, _
,
583 fake_inbound_data
.size(), 0, _
));
587 device
->GenericTransferIn(
588 0, static_cast<uint32_t>(fake_inbound_data
.size()), 0,
589 base::Bind(&ExpectTransferInAndThen
, TRANSFER_STATUS_COMPLETED
,
590 fake_inbound_data
, loop
.QuitClosure()));
594 EXPECT_CALL(mock_handle(), Close());
597 TEST_F(USBDeviceImplTest
, IsochronousTransfer
) {
598 DevicePtr device
= GetMockDeviceProxy();
600 std::string outbound_packet_data
= "aaaaaaaabbbbbbbbccccccccdddddddd";
601 std::vector
<uint8_t> fake_outbound_packets(outbound_packet_data
.size());
602 std::copy(outbound_packet_data
.begin(), outbound_packet_data
.end(),
603 fake_outbound_packets
.begin());
605 std::string inbound_packet_data
= "ddddddddccccccccbbbbbbbbaaaaaaaa";
606 std::vector
<uint8_t> fake_inbound_packets(inbound_packet_data
.size());
607 std::copy(inbound_packet_data
.begin(), inbound_packet_data
.end(),
608 fake_inbound_packets
.begin());
610 AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
611 AddMockOutboundData(fake_outbound_packets
);
612 AddMockInboundData(fake_inbound_packets
);
614 EXPECT_CALL(mock_handle(),
615 IsochronousTransfer(USB_DIRECTION_OUTBOUND
, 0, _
,
616 fake_outbound_packets
.size(), 4, 8, 0, _
));
620 mojo::Array
<mojo::Array
<uint8_t>> packets
=
621 mojo::Array
<mojo::Array
<uint8_t>>::New(4);
622 for (size_t i
= 0; i
< 4; ++i
) {
623 std::vector
<uint8_t> bytes(8);
624 std::copy(outbound_packet_data
.begin() + i
* 8,
625 outbound_packet_data
.begin() + i
* 8 + 8, bytes
.begin());
626 packets
[i
].Swap(&bytes
);
628 device
->IsochronousTransferOut(
629 0, packets
.Pass(), 0,
630 base::Bind(&ExpectTransferStatusAndThen
, TRANSFER_STATUS_COMPLETED
,
631 loop
.QuitClosure()));
635 EXPECT_CALL(mock_handle(),
636 IsochronousTransfer(USB_DIRECTION_INBOUND
, 0, _
,
637 fake_inbound_packets
.size(), 4, 8, 0, _
));
641 std::vector
<std::vector
<uint8_t>> packets(4);
642 for (size_t i
= 0; i
< 4; ++i
) {
643 packets
[i
].resize(8);
644 std::copy(inbound_packet_data
.begin() + i
* 8,
645 inbound_packet_data
.begin() + i
* 8 + 8, packets
[i
].begin());
647 device
->IsochronousTransferIn(
648 0, 4, 8, 0, base::Bind(&ExpectPacketsAndThen
, TRANSFER_STATUS_COMPLETED
,
649 packets
, loop
.QuitClosure()));
653 EXPECT_CALL(mock_handle(), Close());
657 } // namespace device