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