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