1 // Copyright (c) 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.
9 #include "base/callback.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/scoped_observer.h"
13 #include "base/test/test_io_thread.h"
14 #include "device/hid/hid_connection.h"
15 #include "device/hid/hid_service.h"
16 #include "device/test/usb_test_gadget.h"
17 #include "net/base/io_buffer.h"
18 #include "testing/gtest/include/gtest/gtest.h"
24 using net::IOBufferWithSize
;
26 void ClaimTestDevice(scoped_ptr
<UsbTestGadget
>* gadget
) {
27 base::MessageLoop::ScopedNestableTaskAllower
allow(
28 base::MessageLoop::current());
29 *gadget
= UsbTestGadget::Claim();
31 ASSERT_TRUE((*gadget
)->SetType(UsbTestGadget::HID_ECHO
));
34 void UnclaimTestDevice(scoped_ptr
<UsbTestGadget
> gadget
) {
35 base::MessageLoop::ScopedNestableTaskAllower
allow(
36 base::MessageLoop::current());
37 ASSERT_TRUE(gadget
->Unclaim());
40 // Helper class that can be used to block until a HID device with a particular
41 // serial number is available. Example usage:
43 // DeviceCatcher device_catcher("ABC123");
44 // HidDeviceId device_id = device_catcher.WaitForDevice();
45 // /* Call HidService::Connect(device_id) to open the device. */
47 class DeviceCatcher
: HidService::Observer
{
49 DeviceCatcher(const std::string
& serial_number
)
50 : serial_number_(serial_number
), observer_(this) {
51 HidService
* hid_service
= HidService::GetInstance(
52 base::MessageLoop::current()->message_loop_proxy());
53 observer_
.Add(hid_service
);
54 hid_service
->GetDevices(base::Bind(&DeviceCatcher::OnEnumerationComplete
,
55 base::Unretained(this)));
58 const HidDeviceId
& WaitForDevice() {
60 observer_
.RemoveAll();
65 void OnEnumerationComplete(
66 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
67 for (const scoped_refptr
<HidDeviceInfo
>& device_info
: devices
) {
68 if (device_info
->serial_number() == serial_number_
) {
69 device_id_
= device_info
->device_id();
76 void OnDeviceAdded(scoped_refptr
<HidDeviceInfo
> device_info
) override
{
77 if (device_info
->serial_number() == serial_number_
) {
78 device_id_
= device_info
->device_id();
83 std::string serial_number_
;
84 ScopedObserver
<device::HidService
, device::HidService::Observer
> observer_
;
85 base::RunLoop run_loop_
;
86 HidDeviceId device_id_
;
89 class TestConnectCallback
{
92 : callback_(base::Bind(&TestConnectCallback::SetConnection
,
93 base::Unretained(this))) {}
94 ~TestConnectCallback() {}
96 void SetConnection(scoped_refptr
<HidConnection
> connection
) {
97 connection_
= connection
;
101 scoped_refptr
<HidConnection
> WaitForConnection() {
106 const HidService::ConnectCallback
& callback() { return callback_
; }
109 HidService::ConnectCallback callback_
;
110 base::RunLoop run_loop_
;
111 scoped_refptr
<HidConnection
> connection_
;
114 class TestIoCallback
{
118 base::Bind(&TestIoCallback::SetReadResult
, base::Unretained(this))),
119 write_callback_(base::Bind(&TestIoCallback::SetWriteResult
,
120 base::Unretained(this))) {}
123 void SetReadResult(bool success
,
124 scoped_refptr
<net::IOBuffer
> buffer
,
132 void SetWriteResult(bool success
) {
137 bool WaitForResult() {
142 const HidConnection::ReadCallback
& read_callback() { return read_callback_
; }
143 const HidConnection::WriteCallback
write_callback() {
144 return write_callback_
;
146 scoped_refptr
<net::IOBuffer
> buffer() const { return buffer_
; }
147 size_t size() const { return size_
; }
150 base::RunLoop run_loop_
;
153 scoped_refptr
<net::IOBuffer
> buffer_
;
154 HidConnection::ReadCallback read_callback_
;
155 HidConnection::WriteCallback write_callback_
;
160 class HidConnectionTest
: public testing::Test
{
162 void SetUp() override
{
163 if (!UsbTestGadget::IsTestEnabled()) return;
165 message_loop_
.reset(new base::MessageLoopForUI());
166 io_thread_
.reset(new base::TestIOThread(base::TestIOThread::kAutoStart
));
168 service_
= HidService::GetInstance(io_thread_
->task_runner());
169 ASSERT_TRUE(service_
);
171 io_thread_
->PostTaskAndWait(FROM_HERE
,
172 base::Bind(&ClaimTestDevice
, &test_gadget_
));
173 ASSERT_TRUE(test_gadget_
);
175 DeviceCatcher
device_catcher(test_gadget_
->GetSerialNumber());
176 device_id_
= device_catcher
.WaitForDevice();
177 ASSERT_NE(device_id_
, kInvalidHidDeviceId
);
180 void TearDown() override
{
182 io_thread_
->PostTaskAndWait(
184 base::Bind(&UnclaimTestDevice
, base::Passed(&test_gadget_
)));
188 scoped_ptr
<base::MessageLoopForUI
> message_loop_
;
189 scoped_ptr
<base::TestIOThread
> io_thread_
;
190 HidService
* service_
;
191 scoped_ptr
<UsbTestGadget
> test_gadget_
;
192 HidDeviceId device_id_
;
195 TEST_F(HidConnectionTest
, ReadWrite
) {
196 if (!UsbTestGadget::IsTestEnabled()) return;
198 TestConnectCallback connect_callback
;
199 service_
->Connect(device_id_
, connect_callback
.callback());
200 scoped_refptr
<HidConnection
> conn
= connect_callback
.WaitForConnection();
201 ASSERT_TRUE(conn
.get());
203 const char kBufferSize
= 9;
204 for (char i
= 0; i
< 8; ++i
) {
205 scoped_refptr
<IOBufferWithSize
> buffer(new IOBufferWithSize(kBufferSize
));
206 buffer
->data()[0] = 0;
207 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
208 buffer
->data()[j
] = i
+ j
- 1;
211 TestIoCallback write_callback
;
212 conn
->Write(buffer
, buffer
->size(), write_callback
.write_callback());
213 ASSERT_TRUE(write_callback
.WaitForResult());
215 TestIoCallback read_callback
;
216 conn
->Read(read_callback
.read_callback());
217 ASSERT_TRUE(read_callback
.WaitForResult());
218 ASSERT_EQ(9UL, read_callback
.size());
219 ASSERT_EQ(0, read_callback
.buffer()->data()[0]);
220 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
221 ASSERT_EQ(i
+ j
- 1, read_callback
.buffer()->data()[j
]);
228 } // namespace device