Home | History | Annotate | Download | only in usb
      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