Home | History | Annotate | Download | only in bluetooth_socket
      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 <string>
      6 
      7 #include "base/memory/ref_counted.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h"
     10 #include "chrome/browser/extensions/extension_apitest.h"
     11 #include "chrome/browser/extensions/extension_function_test_utils.h"
     12 #include "chrome/browser/extensions/extension_service.h"
     13 #include "chrome/browser/extensions/extension_test_message_listener.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/test/base/ui_test_utils.h"
     16 #include "device/bluetooth/bluetooth_adapter_factory.h"
     17 #include "device/bluetooth/bluetooth_uuid.h"
     18 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
     19 #include "device/bluetooth/test/mock_bluetooth_device.h"
     20 #include "device/bluetooth/test/mock_bluetooth_socket.h"
     21 #include "testing/gmock/include/gmock/gmock.h"
     22 
     23 using device::BluetoothAdapter;
     24 using device::BluetoothAdapterFactory;
     25 using device::BluetoothDevice;
     26 using device::BluetoothSocket;
     27 using device::BluetoothUUID;
     28 using device::MockBluetoothAdapter;
     29 using device::MockBluetoothDevice;
     30 using device::MockBluetoothSocket;
     31 using extensions::Extension;
     32 
     33 namespace utils = extension_function_test_utils;
     34 namespace api = extensions::api;
     35 
     36 namespace {
     37 
     38 class BluetoothSocketApiTest : public ExtensionApiTest {
     39  public:
     40   BluetoothSocketApiTest() {}
     41 
     42   virtual void SetUpOnMainThread() OVERRIDE {
     43     ExtensionApiTest::SetUpOnMainThread();
     44     empty_extension_ = utils::CreateEmptyExtension();
     45     SetUpMockAdapter();
     46   }
     47 
     48   virtual void CleanUpOnMainThread() OVERRIDE {
     49     ExtensionApiTest::CleanUpOnMainThread();
     50   }
     51 
     52   void SetUpMockAdapter() {
     53     // The browser will clean this up when it is torn down.
     54     mock_adapter_ = new testing::StrictMock<MockBluetoothAdapter>();
     55     BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
     56 
     57     mock_device1_.reset(new testing::NiceMock<MockBluetoothDevice>(
     58         mock_adapter_, 0, "d1", "11:12:13:14:15:16",
     59         true /* paired */, false /* connected */));
     60     mock_device2_.reset(new testing::NiceMock<MockBluetoothDevice>(
     61         mock_adapter_, 0, "d2", "21:22:23:24:25:26",
     62         true /* paired */, false /* connected */));
     63   }
     64 
     65  protected:
     66   scoped_refptr<testing::StrictMock<MockBluetoothAdapter> > mock_adapter_;
     67   scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device1_;
     68   scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device2_;
     69 
     70  private:
     71   scoped_refptr<Extension> empty_extension_;
     72 };
     73 
     74 // testing::InvokeArgument<N> does not work with base::Callback, fortunately
     75 // gmock makes it simple to create action templates that do for the various
     76 // possible numbers of arguments.
     77 ACTION_TEMPLATE(InvokeCallbackArgument,
     78                 HAS_1_TEMPLATE_PARAMS(int, k),
     79                 AND_0_VALUE_PARAMS()) {
     80   ::std::tr1::get<k>(args).Run();
     81 }
     82 
     83 ACTION_TEMPLATE(InvokeCallbackArgument,
     84                 HAS_1_TEMPLATE_PARAMS(int, k),
     85                 AND_1_VALUE_PARAMS(p0)) {
     86   ::std::tr1::get<k>(args).Run(p0);
     87 }
     88 
     89 ACTION_TEMPLATE(InvokeCallbackArgument,
     90                 HAS_1_TEMPLATE_PARAMS(int, k),
     91                 AND_2_VALUE_PARAMS(p0, p1)) {
     92   ::std::tr1::get<k>(args).Run(p0, p1);
     93 }
     94 
     95 }  // namespace
     96 
     97 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Connect) {
     98   ResultCatcher catcher;
     99   catcher.RestrictToProfile(browser()->profile());
    100 
    101   // Return the right mock device object for the address used by the test,
    102   // return NULL for the "Device not found" test.
    103   EXPECT_CALL(*mock_adapter_, GetDevice(mock_device1_->GetAddress()))
    104       .WillRepeatedly(testing::Return(mock_device1_.get()));
    105   EXPECT_CALL(*mock_adapter_, GetDevice(std::string("aa:aa:aa:aa:aa:aa")))
    106       .WillOnce(testing::Return(static_cast<BluetoothDevice*>(NULL)));
    107 
    108   // Return a mock socket object as a successful result to the connect() call.
    109   BluetoothUUID service_uuid("8e3ad063-db38-4289-aa8f-b30e4223cf40");
    110   scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_socket
    111       = new testing::StrictMock<MockBluetoothSocket>();
    112   EXPECT_CALL(*mock_device1_,
    113               ConnectToService(service_uuid, testing::_, testing::_))
    114       .WillOnce(InvokeCallbackArgument<1>(mock_socket));
    115 
    116   // Since the socket is unpaused, expect a call to Receive() from the socket
    117   // dispatcher. Since there is no data, this will not call its callback.
    118   EXPECT_CALL(*mock_socket, Receive(testing::_, testing::_, testing::_));
    119 
    120   // The test also cleans up by calling Disconnect and Close.
    121   EXPECT_CALL(*mock_socket, Disconnect(testing::_))
    122       .WillOnce(InvokeCallbackArgument<0>());
    123   EXPECT_CALL(*mock_socket, Close());
    124 
    125   // Run the test.
    126   ExtensionTestMessageListener listener("ready", true);
    127   scoped_refptr<const Extension> extension(
    128       LoadExtension(test_data_dir_.AppendASCII("bluetooth_socket/connect")));
    129   ASSERT_TRUE(extension.get());
    130   EXPECT_TRUE(listener.WaitUntilSatisfied());
    131 
    132   listener.Reply("go");
    133   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    134 }
    135 
    136 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Listen) {
    137   ResultCatcher catcher;
    138   catcher.RestrictToProfile(browser()->profile());
    139 
    140   // Return a mock socket object as a successful result to the create service
    141   // call.
    142   BluetoothUUID service_uuid("2de497f9-ab28-49db-b6d2-066ea69f1737");
    143   scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_server_socket
    144       = new testing::StrictMock<MockBluetoothSocket>();
    145   EXPECT_CALL(*mock_adapter_,
    146               CreateRfcommService(service_uuid,
    147                                   BluetoothAdapter::kChannelAuto,
    148                                   testing::_, testing::_))
    149       .WillOnce(InvokeCallbackArgument<2>(mock_server_socket));
    150 
    151   // Since the socket is unpaused, expect a call to Accept() from the socket
    152   // dispatcher. We'll immediately send back another mock socket to represent
    153   // the client API. Further calls will return no data and behave as if
    154   // pending.
    155   scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_client_socket
    156       = new testing::StrictMock<MockBluetoothSocket>();
    157   EXPECT_CALL(*mock_server_socket, Accept(testing::_, testing::_))
    158       .Times(2)
    159       .WillOnce(InvokeCallbackArgument<0>(mock_device1_.get(),
    160                                           mock_client_socket))
    161       .WillOnce(testing::Return());
    162 
    163   // Run the test, it sends a ready signal once it's ready for us to dispatch
    164   // a client connection to it.
    165   ExtensionTestMessageListener socket_listening("ready", true);
    166   scoped_refptr<const Extension> extension(
    167       LoadExtension(test_data_dir_.AppendASCII("bluetooth_socket/listen")));
    168   ASSERT_TRUE(extension.get());
    169   EXPECT_TRUE(socket_listening.WaitUntilSatisfied());
    170 
    171   // Connection events are dispatched using a couple of PostTask to the UI
    172   // thread. Waiting until idle ensures the event is dispatched to the
    173   // receiver(s).
    174   base::RunLoop().RunUntilIdle();
    175   ExtensionTestMessageListener listener("ready", true);
    176   socket_listening.Reply("go");
    177 
    178   // Second stage of tests checks for error conditions, and will clean up
    179   // the existing server and client sockets.
    180   EXPECT_CALL(*mock_server_socket, Disconnect(testing::_))
    181       .WillOnce(InvokeCallbackArgument<0>());
    182   EXPECT_CALL(*mock_server_socket, Close());
    183 
    184   EXPECT_CALL(*mock_client_socket, Disconnect(testing::_))
    185       .WillOnce(InvokeCallbackArgument<0>());
    186   EXPECT_CALL(*mock_client_socket, Close());
    187 
    188   EXPECT_TRUE(listener.WaitUntilSatisfied());
    189   listener.Reply("go");
    190   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    191 }
    192 
    193 IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, PermissionDenied) {
    194   ResultCatcher catcher;
    195   catcher.RestrictToProfile(browser()->profile());
    196 
    197   // Run the test.
    198   scoped_refptr<const Extension> extension(
    199       LoadExtension(test_data_dir_.AppendASCII(
    200           "bluetooth_socket/permission_denied")));
    201   ASSERT_TRUE(extension.get());
    202 
    203   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    204 }
    205