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. 4 5 #include "chrome/browser/extensions/extension_apitest.h" 6 #include "chrome/browser/ui/browser.h" 7 #include "components/usb_service/usb_service.h" 8 #include "content/public/browser/browser_thread.h" 9 #include "content/public/test/test_utils.h" 10 #include "extensions/browser/api/usb/usb_api.h" 11 #include "net/base/io_buffer.h" 12 #include "testing/gmock/include/gmock/gmock.h" 13 14 using testing::AnyNumber; 15 using testing::_; 16 using testing::Return; 17 using content::BrowserThread; 18 using usb_service::UsbConfigDescriptor; 19 using usb_service::UsbDevice; 20 using usb_service::UsbDeviceHandle; 21 using usb_service::UsbEndpointDirection; 22 using usb_service::UsbInterfaceDescriptor; 23 using usb_service::UsbService; 24 using usb_service::UsbTransferCallback; 25 26 namespace { 27 28 ACTION_TEMPLATE(InvokeUsbTransferCallback, 29 HAS_1_TEMPLATE_PARAMS(int, k), 30 AND_1_VALUE_PARAMS(p1)) { 31 net::IOBuffer* io_buffer = new net::IOBuffer(1); 32 memset(io_buffer->data(), 0, 1); // Avoid uninitialized reads. 33 ::std::tr1::get<k>(args).Run(p1, io_buffer, 1); 34 } 35 36 // MSVC erroneously thinks that at least one of the arguments for the transfer 37 // methods differ by const or volatility and emits a warning about the old 38 // standards-noncompliant behaviour of their compiler. 39 #if defined(OS_WIN) 40 #pragma warning(push) 41 #pragma warning(disable : 4373) 42 #endif 43 44 class MockUsbDeviceHandle : public UsbDeviceHandle { 45 public: 46 MockUsbDeviceHandle() : UsbDeviceHandle() {} 47 48 MOCK_METHOD0(Close, void()); 49 50 MOCK_METHOD10(ControlTransfer, 51 void(const UsbEndpointDirection direction, 52 const TransferRequestType request_type, 53 const TransferRecipient recipient, 54 const uint8 request, 55 const uint16 value, 56 const uint16 index, 57 net::IOBuffer* buffer, 58 const size_t length, 59 const unsigned int timeout, 60 const UsbTransferCallback& callback)); 61 62 MOCK_METHOD6(BulkTransfer, 63 void(const UsbEndpointDirection direction, 64 const uint8 endpoint, 65 net::IOBuffer* buffer, 66 const size_t length, 67 const unsigned int timeout, 68 const UsbTransferCallback& callback)); 69 70 MOCK_METHOD6(InterruptTransfer, 71 void(const UsbEndpointDirection direction, 72 const uint8 endpoint, 73 net::IOBuffer* buffer, 74 const size_t length, 75 const unsigned int timeout, 76 const UsbTransferCallback& callback)); 77 78 MOCK_METHOD8(IsochronousTransfer, 79 void(const UsbEndpointDirection direction, 80 const uint8 endpoint, 81 net::IOBuffer* buffer, 82 const size_t length, 83 const unsigned int packets, 84 const unsigned int packet_length, 85 const unsigned int timeout, 86 const UsbTransferCallback& callback)); 87 88 MOCK_METHOD0(ResetDevice, bool()); 89 MOCK_METHOD1(ClaimInterface, bool(const int interface_number)); 90 MOCK_METHOD1(ReleaseInterface, bool(const int interface_number)); 91 MOCK_METHOD2(SetInterfaceAlternateSetting, 92 bool(const int interface_number, const int alternate_setting)); 93 MOCK_METHOD1(GetSerial, bool(base::string16* serial)); 94 95 virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE { 96 return device_; 97 } 98 99 void set_device(UsbDevice* device) { device_ = device; } 100 101 protected: 102 UsbDevice* device_; 103 104 virtual ~MockUsbDeviceHandle() {} 105 }; 106 107 class MockUsbConfigDescriptor : public UsbConfigDescriptor { 108 public: 109 MOCK_CONST_METHOD0(GetNumInterfaces, size_t()); 110 MOCK_CONST_METHOD1(GetInterface, 111 scoped_refptr<const UsbInterfaceDescriptor>(size_t index)); 112 113 protected: 114 virtual ~MockUsbConfigDescriptor() {} 115 }; 116 117 class MockUsbDevice : public UsbDevice { 118 public: 119 explicit MockUsbDevice(MockUsbDeviceHandle* mock_handle) 120 : UsbDevice(0, 0, 0), mock_handle_(mock_handle) { 121 mock_handle->set_device(this); 122 } 123 124 virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE { 125 return mock_handle_; 126 } 127 128 virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE { 129 EXPECT_TRUE(false) << "Should not be reached"; 130 return false; 131 } 132 133 #if defined(OS_CHROMEOS) 134 virtual void RequestUsbAcess( 135 int interface_id, 136 const base::Callback<void(bool success)>& callback) OVERRIDE { 137 BrowserThread::PostTask( 138 BrowserThread::FILE, FROM_HERE, base::Bind(callback, true)); 139 } 140 #endif // OS_CHROMEOS 141 142 MOCK_METHOD0(ListInterfaces, scoped_refptr<UsbConfigDescriptor>()); 143 144 private: 145 MockUsbDeviceHandle* mock_handle_; 146 virtual ~MockUsbDevice() {} 147 }; 148 149 class MockUsbService : public UsbService { 150 public: 151 explicit MockUsbService(scoped_refptr<UsbDevice> device) : device_(device) {} 152 153 protected: 154 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE { 155 EXPECT_EQ(unique_id, 0U); 156 return device_; 157 } 158 159 virtual void GetDevices( 160 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE { 161 STLClearObject(devices); 162 devices->push_back(device_); 163 } 164 165 scoped_refptr<UsbDevice> device_; 166 }; 167 168 #if defined(OS_WIN) 169 #pragma warning(pop) 170 #endif 171 172 class UsbApiTest : public ExtensionApiTest { 173 public: 174 virtual void SetUpOnMainThread() OVERRIDE { 175 mock_device_handle_ = new MockUsbDeviceHandle(); 176 mock_device_ = new MockUsbDevice(mock_device_handle_.get()); 177 scoped_refptr<content::MessageLoopRunner> runner = 178 new content::MessageLoopRunner; 179 BrowserThread::PostTaskAndReply(BrowserThread::FILE, 180 FROM_HERE, 181 base::Bind(&UsbApiTest::SetUpService, this), 182 runner->QuitClosure()); 183 runner->Run(); 184 } 185 186 void SetUpService() { 187 UsbService::SetInstanceForTest(new MockUsbService(mock_device_)); 188 } 189 190 virtual void CleanUpOnMainThread() OVERRIDE { 191 scoped_refptr<content::MessageLoopRunner> runner = 192 new content::MessageLoopRunner; 193 UsbService* service = NULL; 194 BrowserThread::PostTaskAndReply( 195 BrowserThread::FILE, 196 FROM_HERE, 197 base::Bind(&UsbService::SetInstanceForTest, service), 198 runner->QuitClosure()); 199 runner->Run(); 200 } 201 202 protected: 203 scoped_refptr<MockUsbDeviceHandle> mock_device_handle_; 204 scoped_refptr<MockUsbDevice> mock_device_; 205 }; 206 207 } // namespace 208 209 IN_PROC_BROWSER_TEST_F(UsbApiTest, DeviceHandling) { 210 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(4); 211 ASSERT_TRUE(RunExtensionTest("usb/device_handling")); 212 } 213 214 IN_PROC_BROWSER_TEST_F(UsbApiTest, ResetDevice) { 215 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(2); 216 EXPECT_CALL(*mock_device_handle_.get(), ResetDevice()) 217 .WillOnce(Return(true)) 218 .WillOnce(Return(false)); 219 EXPECT_CALL( 220 *mock_device_handle_.get(), 221 InterruptTransfer(usb_service::USB_DIRECTION_OUTBOUND, 2, _, 1, _, _)) 222 .WillOnce( 223 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_COMPLETED)); 224 ASSERT_TRUE(RunExtensionTest("usb/reset_device")); 225 } 226 227 IN_PROC_BROWSER_TEST_F(UsbApiTest, ListInterfaces) { 228 scoped_refptr<MockUsbConfigDescriptor> mock_descriptor = 229 new MockUsbConfigDescriptor(); 230 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber()); 231 EXPECT_CALL(*mock_descriptor.get(), GetNumInterfaces()).WillOnce(Return(0)); 232 EXPECT_CALL(*mock_device_.get(), ListInterfaces()) 233 .WillOnce(Return(mock_descriptor)); 234 ASSERT_TRUE(RunExtensionTest("usb/list_interfaces")); 235 } 236 237 IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferEvent) { 238 EXPECT_CALL(*mock_device_handle_.get(), 239 ControlTransfer(usb_service::USB_DIRECTION_OUTBOUND, 240 UsbDeviceHandle::STANDARD, 241 UsbDeviceHandle::DEVICE, 242 1, 243 2, 244 3, 245 _, 246 1, 247 _, 248 _)) 249 .WillOnce( 250 InvokeUsbTransferCallback<9>(usb_service::USB_TRANSFER_COMPLETED)); 251 EXPECT_CALL(*mock_device_handle_.get(), 252 BulkTransfer(usb_service::USB_DIRECTION_OUTBOUND, 1, _, 1, _, _)) 253 .WillOnce( 254 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_COMPLETED)); 255 EXPECT_CALL( 256 *mock_device_handle_.get(), 257 InterruptTransfer(usb_service::USB_DIRECTION_OUTBOUND, 2, _, 1, _, _)) 258 .WillOnce( 259 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_COMPLETED)); 260 EXPECT_CALL(*mock_device_handle_.get(), 261 IsochronousTransfer( 262 usb_service::USB_DIRECTION_OUTBOUND, 3, _, 1, 1, 1, _, _)) 263 .WillOnce( 264 InvokeUsbTransferCallback<7>(usb_service::USB_TRANSFER_COMPLETED)); 265 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber()); 266 ASSERT_TRUE(RunExtensionTest("usb/transfer_event")); 267 } 268 269 IN_PROC_BROWSER_TEST_F(UsbApiTest, ZeroLengthTransfer) { 270 EXPECT_CALL(*mock_device_handle_.get(), BulkTransfer(_, _, _, 0, _, _)) 271 .WillOnce( 272 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_COMPLETED)); 273 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber()); 274 ASSERT_TRUE(RunExtensionTest("usb/zero_length_transfer")); 275 } 276 277 IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferFailure) { 278 EXPECT_CALL(*mock_device_handle_.get(), BulkTransfer(_, _, _, _, _, _)) 279 .WillOnce( 280 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_COMPLETED)) 281 .WillOnce(InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_ERROR)) 282 .WillOnce( 283 InvokeUsbTransferCallback<5>(usb_service::USB_TRANSFER_TIMEOUT)); 284 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber()); 285 ASSERT_TRUE(RunExtensionTest("usb/transfer_failure")); 286 } 287 288 IN_PROC_BROWSER_TEST_F(UsbApiTest, InvalidLengthTransfer) { 289 EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(AnyNumber()); 290 ASSERT_TRUE(RunExtensionTest("usb/invalid_length_transfer")); 291 } 292