blob: ab20c41340084c6bf1c963b30b372b1802e0c42f [file] [log] [blame]
reillygee658b72014-09-04 19:40:301// 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.
4
thakisacd68a22016-04-11 16:12:235#include "device/usb/usb_device_handle.h"
6
avi176e2692015-12-22 19:26:527#include <stddef.h>
8
thakisacd68a22016-04-11 16:12:239#include <memory>
10
reillygee658b72014-09-04 19:40:3011#include "base/bind.h"
12#include "base/message_loop/message_loop.h"
13#include "base/run_loop.h"
14#include "base/strings/utf_string_conversions.h"
reillygb87cb272015-04-16 19:11:0415#include "base/test/test_io_thread.h"
reillygbadbc5412015-08-28 23:08:1016#include "device/test/test_device_client.h"
reillygee658b72014-09-04 19:40:3017#include "device/test/usb_test_gadget.h"
18#include "device/usb/usb_device.h"
reillyga9de0fa2016-01-28 01:38:0119#include "net/base/io_buffer.h"
reillygee658b72014-09-04 19:40:3020#include "testing/gtest/include/gtest/gtest.h"
21
22namespace device {
23
24namespace {
25
26class UsbDeviceHandleTest : public ::testing::Test {
27 public:
dcheng07c34a12014-10-29 18:55:1028 void SetUp() override {
reillygb87cb272015-04-16 19:11:0429 message_loop_.reset(new base::MessageLoopForUI);
30 io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart));
reillygbadbc5412015-08-28 23:08:1031 device_client_.reset(new TestDeviceClient(io_thread_->task_runner()));
reillygee658b72014-09-04 19:40:3032 }
33
34 protected:
thakisacd68a22016-04-11 16:12:2335 std::unique_ptr<base::TestIOThread> io_thread_;
reillygee658b72014-09-04 19:40:3036
37 private:
thakisacd68a22016-04-11 16:12:2338 std::unique_ptr<base::MessageLoop> message_loop_;
39 std::unique_ptr<TestDeviceClient> device_client_;
reillygee658b72014-09-04 19:40:3040};
41
reillygb87cb272015-04-16 19:11:0442class TestOpenCallback {
43 public:
44 TestOpenCallback()
45 : callback_(
46 base::Bind(&TestOpenCallback::SetResult, base::Unretained(this))) {}
47
48 scoped_refptr<UsbDeviceHandle> WaitForResult() {
49 run_loop_.Run();
50 return device_handle_;
51 }
52
53 const UsbDevice::OpenCallback& callback() const { return callback_; }
54
55 private:
56 void SetResult(scoped_refptr<UsbDeviceHandle> device_handle) {
57 device_handle_ = device_handle;
58 run_loop_.Quit();
59 }
60
61 const UsbDevice::OpenCallback callback_;
62 base::RunLoop run_loop_;
63 scoped_refptr<UsbDeviceHandle> device_handle_;
64};
65
66class TestResultCallback {
67 public:
68 TestResultCallback()
69 : callback_(base::Bind(&TestResultCallback::SetResult,
70 base::Unretained(this))) {}
71
72 bool WaitForResult() {
73 run_loop_.Run();
74 return success_;
75 }
76
77 const UsbDeviceHandle::ResultCallback& callback() const { return callback_; }
78
79 private:
80 void SetResult(bool success) {
81 success_ = success;
82 run_loop_.Quit();
83 }
84
85 const UsbDeviceHandle::ResultCallback callback_;
86 base::RunLoop run_loop_;
87 bool success_;
88};
89
reillygee658b72014-09-04 19:40:3090class TestCompletionCallback {
91 public:
92 TestCompletionCallback()
93 : callback_(base::Bind(&TestCompletionCallback::SetResult,
94 base::Unretained(this))) {}
95
reillygb87cb272015-04-16 19:11:0496 void WaitForResult() { run_loop_.Run(); }
97
98 const UsbDeviceHandle::TransferCallback& callback() const {
99 return callback_;
100 }
101 UsbTransferStatus status() const { return status_; }
102 size_t transferred() const { return transferred_; }
103
104 private:
reillygee658b72014-09-04 19:40:30105 void SetResult(UsbTransferStatus status,
106 scoped_refptr<net::IOBuffer> buffer,
107 size_t transferred) {
108 status_ = status;
109 transferred_ = transferred;
110 run_loop_.Quit();
111 }
112
reillygb87cb272015-04-16 19:11:04113 const UsbDeviceHandle::TransferCallback callback_;
reillygee658b72014-09-04 19:40:30114 base::RunLoop run_loop_;
115 UsbTransferStatus status_;
116 size_t transferred_;
117};
118
119TEST_F(UsbDeviceHandleTest, InterruptTransfer) {
reillygb87cb272015-04-16 19:11:04120 if (!UsbTestGadget::IsTestEnabled()) {
reillygee658b72014-09-04 19:40:30121 return;
122 }
123
thakisacd68a22016-04-11 16:12:23124 std::unique_ptr<UsbTestGadget> gadget =
reillygb87cb272015-04-16 19:11:04125 UsbTestGadget::Claim(io_thread_->task_runner());
126 ASSERT_TRUE(gadget.get());
127 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
128
129 TestOpenCallback open_device;
130 gadget->GetDevice()->Open(open_device.callback());
131 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
132 ASSERT_TRUE(handle.get());
133
134 TestResultCallback claim_interface;
135 handle->ClaimInterface(0, claim_interface.callback());
136 ASSERT_TRUE(claim_interface.WaitForResult());
reillyg67650d62014-12-13 01:18:52137
reillyg1f45f772016-04-02 02:46:55138 const UsbInterfaceDescriptor* interface =
139 handle->FindInterfaceByEndpoint(0x81);
140 EXPECT_TRUE(interface);
141 EXPECT_EQ(0, interface->interface_number);
142 interface = handle->FindInterfaceByEndpoint(0x01);
143 EXPECT_TRUE(interface);
144 EXPECT_EQ(0, interface->interface_number);
145 EXPECT_FALSE(handle->FindInterfaceByEndpoint(0x82));
146 EXPECT_FALSE(handle->FindInterfaceByEndpoint(0x02));
147
reillygee658b72014-09-04 19:40:30148 scoped_refptr<net::IOBufferWithSize> in_buffer(new net::IOBufferWithSize(64));
149 TestCompletionCallback in_completion;
juncaie03494ff2015-09-03 20:06:23150 handle->GenericTransfer(USB_DIRECTION_INBOUND, 0x81, in_buffer.get(),
151 in_buffer->size(),
152 5000, // 5 second timeout
153 in_completion.callback());
reillygee658b72014-09-04 19:40:30154
155 scoped_refptr<net::IOBufferWithSize> out_buffer(
156 new net::IOBufferWithSize(in_buffer->size()));
157 TestCompletionCallback out_completion;
158 for (int i = 0; i < out_buffer->size(); ++i) {
159 out_buffer->data()[i] = i;
160 }
161
juncaie03494ff2015-09-03 20:06:23162 handle->GenericTransfer(USB_DIRECTION_OUTBOUND, 0x01, out_buffer.get(),
163 out_buffer->size(),
164 5000, // 5 second timeout
165 out_completion.callback());
reillygee658b72014-09-04 19:40:30166 out_completion.WaitForResult();
167 ASSERT_EQ(USB_TRANSFER_COMPLETED, out_completion.status());
reillyg67650d62014-12-13 01:18:52168 EXPECT_EQ(static_cast<size_t>(out_buffer->size()),
reillygee658b72014-09-04 19:40:30169 out_completion.transferred());
170
171 in_completion.WaitForResult();
172 ASSERT_EQ(USB_TRANSFER_COMPLETED, in_completion.status());
reillyg67650d62014-12-13 01:18:52173 EXPECT_EQ(static_cast<size_t>(in_buffer->size()),
reillygee658b72014-09-04 19:40:30174 in_completion.transferred());
reillyg67650d62014-12-13 01:18:52175 for (size_t i = 0; i < in_completion.transferred(); ++i) {
reillyg631048ab2015-07-06 21:27:47176 EXPECT_EQ(out_buffer->data()[i], in_buffer->data()[i])
177 << "Mismatch at index " << i << ".";
reillygee658b72014-09-04 19:40:30178 }
reillygb87cb272015-04-16 19:11:04179
reillyg6bc4255e2016-02-04 22:45:36180 TestResultCallback release_interface;
181 handle->ReleaseInterface(0, release_interface.callback());
182 ASSERT_TRUE(release_interface.WaitForResult());
183
reillygb87cb272015-04-16 19:11:04184 handle->Close();
reillygee658b72014-09-04 19:40:30185}
186
187TEST_F(UsbDeviceHandleTest, BulkTransfer) {
reillygb87cb272015-04-16 19:11:04188 if (!UsbTestGadget::IsTestEnabled()) {
reillygee658b72014-09-04 19:40:30189 return;
190 }
191
thakisacd68a22016-04-11 16:12:23192 std::unique_ptr<UsbTestGadget> gadget =
reillygb87cb272015-04-16 19:11:04193 UsbTestGadget::Claim(io_thread_->task_runner());
194 ASSERT_TRUE(gadget.get());
195 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
196
197 TestOpenCallback open_device;
198 gadget->GetDevice()->Open(open_device.callback());
199 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
200 ASSERT_TRUE(handle.get());
201
202 TestResultCallback claim_interface;
203 handle->ClaimInterface(1, claim_interface.callback());
204 ASSERT_TRUE(claim_interface.WaitForResult());
reillyg67650d62014-12-13 01:18:52205
reillyg1f45f772016-04-02 02:46:55206 EXPECT_FALSE(handle->FindInterfaceByEndpoint(0x81));
207 EXPECT_FALSE(handle->FindInterfaceByEndpoint(0x01));
208 const UsbInterfaceDescriptor* interface =
209 handle->FindInterfaceByEndpoint(0x82);
210 EXPECT_TRUE(interface);
211 EXPECT_EQ(1, interface->interface_number);
212 interface = handle->FindInterfaceByEndpoint(0x02);
213 EXPECT_TRUE(interface);
214 EXPECT_EQ(1, interface->interface_number);
215
reillygee658b72014-09-04 19:40:30216 scoped_refptr<net::IOBufferWithSize> in_buffer(
217 new net::IOBufferWithSize(512));
218 TestCompletionCallback in_completion;
juncaie03494ff2015-09-03 20:06:23219 handle->GenericTransfer(USB_DIRECTION_INBOUND, 0x82, in_buffer.get(),
220 in_buffer->size(),
221 5000, // 5 second timeout
222 in_completion.callback());
reillygee658b72014-09-04 19:40:30223
224 scoped_refptr<net::IOBufferWithSize> out_buffer(
225 new net::IOBufferWithSize(in_buffer->size()));
226 TestCompletionCallback out_completion;
227 for (int i = 0; i < out_buffer->size(); ++i) {
228 out_buffer->data()[i] = i;
229 }
230
juncaie03494ff2015-09-03 20:06:23231 handle->GenericTransfer(USB_DIRECTION_OUTBOUND, 0x02, out_buffer.get(),
232 out_buffer->size(),
233 5000, // 5 second timeout
234 out_completion.callback());
reillygee658b72014-09-04 19:40:30235 out_completion.WaitForResult();
236 ASSERT_EQ(USB_TRANSFER_COMPLETED, out_completion.status());
reillyg67650d62014-12-13 01:18:52237 EXPECT_EQ(static_cast<size_t>(out_buffer->size()),
reillygee658b72014-09-04 19:40:30238 out_completion.transferred());
239
240 in_completion.WaitForResult();
241 ASSERT_EQ(USB_TRANSFER_COMPLETED, in_completion.status());
reillyg67650d62014-12-13 01:18:52242 EXPECT_EQ(static_cast<size_t>(in_buffer->size()),
reillygee658b72014-09-04 19:40:30243 in_completion.transferred());
reillyg67650d62014-12-13 01:18:52244 for (size_t i = 0; i < in_completion.transferred(); ++i) {
reillyg631048ab2015-07-06 21:27:47245 EXPECT_EQ(out_buffer->data()[i], in_buffer->data()[i])
246 << "Mismatch at index " << i << ".";
reillygee658b72014-09-04 19:40:30247 }
reillygb87cb272015-04-16 19:11:04248
reillyg6bc4255e2016-02-04 22:45:36249 TestResultCallback release_interface;
250 handle->ReleaseInterface(1, release_interface.callback());
251 ASSERT_TRUE(release_interface.WaitForResult());
252
reillygb87cb272015-04-16 19:11:04253 handle->Close();
reillygee658b72014-09-04 19:40:30254}
255
reillyg2f3b62852016-04-20 01:47:27256TEST_F(UsbDeviceHandleTest, ControlTransfer) {
257 if (!UsbTestGadget::IsTestEnabled())
258 return;
259
260 std::unique_ptr<UsbTestGadget> gadget =
261 UsbTestGadget::Claim(io_thread_->task_runner());
262 ASSERT_TRUE(gadget.get());
263
264 TestOpenCallback open_device;
265 gadget->GetDevice()->Open(open_device.callback());
266 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
267 ASSERT_TRUE(handle.get());
268
269 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(255));
270 TestCompletionCallback completion;
271 handle->ControlTransfer(USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD,
272 UsbDeviceHandle::DEVICE, 0x06, 0x0301, 0x0409, buffer,
273 buffer->size(), 0, completion.callback());
274 completion.WaitForResult();
275 ASSERT_EQ(USB_TRANSFER_COMPLETED, completion.status());
276 const char expected_str[] = "\x18\x03G\0o\0o\0g\0l\0e\0 \0I\0n\0c\0.\0";
277 EXPECT_EQ(sizeof(expected_str) - 1, completion.transferred());
278 for (size_t i = 0; i < completion.transferred(); ++i) {
279 EXPECT_EQ(expected_str[i], buffer->data()[i]) << "Mismatch at index " << i
280 << ".";
281 }
282
283 handle->Close();
284}
285
reillyg631048ab2015-07-06 21:27:47286TEST_F(UsbDeviceHandleTest, SetInterfaceAlternateSetting) {
287 if (!UsbTestGadget::IsTestEnabled()) {
288 return;
289 }
290
thakisacd68a22016-04-11 16:12:23291 std::unique_ptr<UsbTestGadget> gadget =
reillyg631048ab2015-07-06 21:27:47292 UsbTestGadget::Claim(io_thread_->task_runner());
293 ASSERT_TRUE(gadget.get());
294 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
295
296 TestOpenCallback open_device;
297 gadget->GetDevice()->Open(open_device.callback());
298 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
299 ASSERT_TRUE(handle.get());
300
301 TestResultCallback claim_interface;
302 handle->ClaimInterface(2, claim_interface.callback());
303 ASSERT_TRUE(claim_interface.WaitForResult());
304
305 TestResultCallback set_interface;
306 handle->SetInterfaceAlternateSetting(2, 1, set_interface.callback());
307 ASSERT_TRUE(set_interface.WaitForResult());
308
reillyg6bc4255e2016-02-04 22:45:36309 TestResultCallback release_interface;
310 handle->ReleaseInterface(2, release_interface.callback());
311 ASSERT_TRUE(release_interface.WaitForResult());
312
reillyg631048ab2015-07-06 21:27:47313 handle->Close();
314}
315
reillyge0a173d2016-04-21 22:00:59316TEST_F(UsbDeviceHandleTest, CancelOnClose) {
317 if (!UsbTestGadget::IsTestEnabled()) {
318 return;
319 }
320
321 std::unique_ptr<UsbTestGadget> gadget =
322 UsbTestGadget::Claim(io_thread_->task_runner());
323 ASSERT_TRUE(gadget.get());
324 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
325
326 TestOpenCallback open_device;
327 gadget->GetDevice()->Open(open_device.callback());
328 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
329 ASSERT_TRUE(handle.get());
330
331 TestResultCallback claim_interface;
332 handle->ClaimInterface(1, claim_interface.callback());
333 ASSERT_TRUE(claim_interface.WaitForResult());
334
335 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(512));
336 TestCompletionCallback completion;
337 handle->GenericTransfer(USB_DIRECTION_INBOUND, 0x82, buffer.get(),
338 buffer->size(),
339 5000, // 5 second timeout
340 completion.callback());
341
342 handle->Close();
343 completion.WaitForResult();
344 ASSERT_EQ(USB_TRANSFER_CANCELLED, completion.status());
345}
346
347TEST_F(UsbDeviceHandleTest, CancelOnDisconnect) {
348 if (!UsbTestGadget::IsTestEnabled()) {
349 return;
350 }
351
352 std::unique_ptr<UsbTestGadget> gadget =
353 UsbTestGadget::Claim(io_thread_->task_runner());
354 ASSERT_TRUE(gadget.get());
355 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
356
357 TestOpenCallback open_device;
358 gadget->GetDevice()->Open(open_device.callback());
359 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
360 ASSERT_TRUE(handle.get());
361
362 TestResultCallback claim_interface;
363 handle->ClaimInterface(1, claim_interface.callback());
364 ASSERT_TRUE(claim_interface.WaitForResult());
365
366 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(512));
367 TestCompletionCallback completion;
368 handle->GenericTransfer(USB_DIRECTION_INBOUND, 0x82, buffer.get(),
369 buffer->size(),
370 5000, // 5 second timeout
371 completion.callback());
372
373 ASSERT_TRUE(gadget->Disconnect());
374 completion.WaitForResult();
375 ASSERT_EQ(USB_TRANSFER_DISCONNECT, completion.status());
376
377 handle->Close();
378}
379
380TEST_F(UsbDeviceHandleTest, Timeout) {
381 if (!UsbTestGadget::IsTestEnabled()) {
382 return;
383 }
384
385 std::unique_ptr<UsbTestGadget> gadget =
386 UsbTestGadget::Claim(io_thread_->task_runner());
387 ASSERT_TRUE(gadget.get());
388 ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
389
390 TestOpenCallback open_device;
391 gadget->GetDevice()->Open(open_device.callback());
392 scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
393 ASSERT_TRUE(handle.get());
394
395 TestResultCallback claim_interface;
396 handle->ClaimInterface(1, claim_interface.callback());
397 ASSERT_TRUE(claim_interface.WaitForResult());
398
399 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(512));
400 TestCompletionCallback completion;
401 handle->GenericTransfer(USB_DIRECTION_INBOUND, 0x82, buffer.get(),
402 buffer->size(),
403 10, // 10 millisecond timeout
404 completion.callback());
405
406 completion.WaitForResult();
407 ASSERT_EQ(USB_TRANSFER_TIMEOUT, completion.status());
408
409 handle->Close();
410}
411
reillygee658b72014-09-04 19:40:30412} // namespace
413
414} // namespace device