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 "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