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.
4
5 #include <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "device/hid/hid_connection.h"
13 #include "device/hid/hid_service.h"
14 #include "device/test/usb_test_gadget.h"
15 #include "net/base/io_buffer.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace device {
19
20 namespace {
21
22 using net::IOBufferWithSize;
23
24 class TestCompletionCallback {
25 public:
TestCompletionCallback()26 TestCompletionCallback()
27 : read_callback_(base::Bind(&TestCompletionCallback::SetReadResult,
28 base::Unretained(this))),
29 write_callback_(base::Bind(&TestCompletionCallback::SetWriteResult,
30 base::Unretained(this))) {}
~TestCompletionCallback()31 ~TestCompletionCallback() {}
32
SetReadResult(bool success,scoped_refptr<net::IOBuffer> buffer,size_t size)33 void SetReadResult(bool success,
34 scoped_refptr<net::IOBuffer> buffer,
35 size_t size) {
36 result_ = success;
37 buffer_ = buffer;
38 size_ = size;
39 run_loop_.Quit();
40 }
41
SetWriteResult(bool success)42 void SetWriteResult(bool success) {
43 result_ = success;
44 run_loop_.Quit();
45 }
46
WaitForResult()47 bool WaitForResult() {
48 run_loop_.Run();
49 return result_;
50 }
51
read_callback()52 const HidConnection::ReadCallback& read_callback() { return read_callback_; }
write_callback()53 const HidConnection::WriteCallback write_callback() {
54 return write_callback_;
55 }
buffer() const56 scoped_refptr<net::IOBuffer> buffer() const { return buffer_; }
size() const57 size_t size() const { return size_; }
58
59 private:
60 base::RunLoop run_loop_;
61 bool result_;
62 size_t size_;
63 scoped_refptr<net::IOBuffer> buffer_;
64 HidConnection::ReadCallback read_callback_;
65 HidConnection::WriteCallback write_callback_;
66 };
67
68 } // namespace
69
70 class HidConnectionTest : public testing::Test {
71 protected:
SetUp()72 virtual void SetUp() OVERRIDE {
73 if (!UsbTestGadget::IsTestEnabled()) return;
74
75 message_loop_.reset(new base::MessageLoopForIO());
76 service_ = HidService::GetInstance(
77 message_loop_->message_loop_proxy(),
78 message_loop_->message_loop_proxy());
79 ASSERT_TRUE(service_);
80
81 test_gadget_ = UsbTestGadget::Claim();
82 ASSERT_TRUE(test_gadget_);
83 ASSERT_TRUE(test_gadget_->SetType(UsbTestGadget::HID_ECHO));
84
85 device_id_ = kInvalidHidDeviceId;
86
87 base::RunLoop run_loop;
88 message_loop_->PostDelayedTask(
89 FROM_HERE,
90 base::Bind(&HidConnectionTest::FindDevice,
91 base::Unretained(this), run_loop.QuitClosure(), 5),
92 base::TimeDelta::FromMilliseconds(250));
93 run_loop.Run();
94
95 ASSERT_NE(device_id_, kInvalidHidDeviceId);
96 }
97
FindDevice(const base::Closure & done,int retries)98 void FindDevice(const base::Closure& done, int retries) {
99 std::vector<HidDeviceInfo> devices;
100 service_->GetDevices(&devices);
101
102 for (std::vector<HidDeviceInfo>::iterator it = devices.begin();
103 it != devices.end();
104 ++it) {
105 if (it->serial_number == test_gadget_->GetSerialNumber()) {
106 device_id_ = it->device_id;
107 break;
108 }
109 }
110
111 if (device_id_ == kInvalidHidDeviceId && --retries > 0) {
112 message_loop_->PostDelayedTask(
113 FROM_HERE,
114 base::Bind(&HidConnectionTest::FindDevice, base::Unretained(this),
115 done, retries),
116 base::TimeDelta::FromMilliseconds(10));
117 } else {
118 message_loop_->PostTask(FROM_HERE, done);
119 }
120 }
121
122 scoped_ptr<base::MessageLoopForIO> message_loop_;
123 HidService* service_;
124 scoped_ptr<UsbTestGadget> test_gadget_;
125 HidDeviceId device_id_;
126 };
127
TEST_F(HidConnectionTest,ReadWrite)128 TEST_F(HidConnectionTest, ReadWrite) {
129 if (!UsbTestGadget::IsTestEnabled()) return;
130
131 scoped_refptr<HidConnection> conn = service_->Connect(device_id_);
132 ASSERT_TRUE(conn.get());
133
134 for (int i = 0; i < 8; ++i) {
135 scoped_refptr<IOBufferWithSize> buffer(new IOBufferWithSize(9));
136 buffer->data()[0] = 0;
137 for (int j = 1; j < buffer->size(); ++j) {
138 buffer->data()[j] = i + j - 1;
139 }
140
141 TestCompletionCallback write_callback;
142 conn->Write(buffer, buffer->size(), write_callback.write_callback());
143 ASSERT_TRUE(write_callback.WaitForResult());
144
145 TestCompletionCallback read_callback;
146 conn->Read(read_callback.read_callback());
147 ASSERT_TRUE(read_callback.WaitForResult());
148 ASSERT_EQ(9UL, read_callback.size());
149 ASSERT_EQ(0, read_callback.buffer()->data()[0]);
150 for (int j = 1; j < buffer->size(); ++j) {
151 ASSERT_EQ(i + j - 1, read_callback.buffer()->data()[j]);
152 }
153 }
154
155 conn->Close();
156 }
157
158 } // namespace device
159