910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <string>
#include <tuple>

#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_socket.h"
#include "extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h"
#include "extensions/common/extension_builder.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "testing/gmock/include/gmock/gmock.h"

using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
using device::BluetoothDevice;
using device::BluetoothSocket;
using device::BluetoothUUID;
using device::MockBluetoothAdapter;
using device::MockBluetoothDevice;
using device::MockBluetoothSocket;
using extensions::Extension;
using extensions::ResultCatcher;

namespace api = extensions::api;

namespace {

class BluetoothSocketApiTest : public extensions::ShellApiTest {
 public:
  BluetoothSocketApiTest() {}

  void SetUpOnMainThread() override {
    ShellApiTest::SetUpOnMainThread();
    empty_extension_ = extensions::ExtensionBuilder("Test").Build();
    SetUpMockAdapter();
  }

  void SetUpMockAdapter() {
    // The browser will clean this up when it is torn down.
    mock_adapter_ = new testing::StrictMock<MockBluetoothAdapter>();
    BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);

    mock_device1_ = std::make_unique<testing::NiceMock<MockBluetoothDevice>>(
        mock_adapter_.get(), 0, "d1", "11:12:13:14:15:16", true /* paired */,
        false /* connected */);
    mock_device2_ = std::make_unique<testing::NiceMock<MockBluetoothDevice>>(
        mock_adapter_.get(), 0, "d2", "21:22:23:24:25:26", true /* paired */,
        false /* connected */);
  }

 protected:
  scoped_refptr<testing::StrictMock<MockBluetoothAdapter> > mock_adapter_;
  std::unique_ptr<testing::NiceMock<MockBluetoothDevice>> mock_device1_;
  std::unique_ptr<testing::NiceMock<MockBluetoothDevice>> mock_device2_;

 private:
  scoped_refptr<const Extension> empty_extension_;
};

}  // namespace

// TODO(crbug.com/41266338): Flaky on many trybot platforms.
IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, DISABLED_Connect) {
  ResultCatcher catcher;
  catcher.RestrictToBrowserContext(browser_context());

  // Return the right mock device object for the address used by the test,
  // return NULL for the "Device not found" test.
  EXPECT_CALL(*mock_adapter_, GetDevice(mock_device1_->GetAddress()))
      .WillRepeatedly(testing::Return(mock_device1_.get()));
  EXPECT_CALL(*mock_adapter_, GetDevice(std::string("aa:aa:aa:aa:aa:aa")))
      .WillOnce(testing::Return(static_cast<BluetoothDevice*>(nullptr)));

  // Return a mock socket object as a successful result to the connect() call.
  BluetoothUUID service_uuid("8e3ad063-db38-4289-aa8f-b30e4223cf40");
  scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_socket
      = new testing::StrictMock<MockBluetoothSocket>();
  EXPECT_CALL(*mock_device1_,
              ConnectToService(service_uuid, testing::_, testing::_))
      .WillOnce(base::test::RunOnceCallback<1>(mock_socket));

  // Since the socket is unpaused, expect a call to Receive() from the socket
  // dispatcher. Since there is no data, this will not call its callback.
  EXPECT_CALL(*mock_socket, Receive(testing::_, testing::_, testing::_));

  // The test also cleans up by calling Disconnect.
  EXPECT_CALL(*mock_socket, Disconnect(testing::_))
      .WillOnce(base::test::RunOnceCallback<0>());

  // Run the test.
  ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
  scoped_refptr<const Extension> extension(
      LoadApp("api_test/bluetooth_socket/connect"));
  ASSERT_TRUE(extension.get());
  EXPECT_TRUE(listener.WaitUntilSatisfied());

  listener.Reply("go");
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Listen) {
  ResultCatcher catcher;
  catcher.RestrictToBrowserContext(browser_context());

  // Return a mock socket object as a successful result to the create service
  // call.
  BluetoothUUID service_uuid("2de497f9-ab28-49db-b6d2-066ea69f1737");
  scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_server_socket
      = new testing::StrictMock<MockBluetoothSocket>();
  BluetoothAdapter::ServiceOptions service_options;
  service_options.name = "MyServiceName";
  EXPECT_CALL(
      *mock_adapter_,
      CreateRfcommService(
          service_uuid,
          testing::Field(&BluetoothAdapter::ServiceOptions::name,
                         testing::Eq("MyServiceName")),
          testing::_, testing::_))
      .WillOnce(base::test::RunOnceCallback<2>(mock_server_socket));

  // Since the socket is unpaused, expect a call to Accept() from the socket
  // dispatcher. We'll immediately send back another mock socket to represent
  // the client API. Further calls will return no data and behave as if
  // pending.
  scoped_refptr<testing::StrictMock<MockBluetoothSocket> > mock_client_socket
      = new testing::StrictMock<MockBluetoothSocket>();
  EXPECT_CALL(*mock_server_socket, Accept(testing::_, testing::_))
      .Times(2)
      .WillOnce(base::test::RunOnceCallback<0>(mock_device1_.get(),
                                               mock_client_socket))
      .WillOnce(testing::Return());

  // Run the test, it sends a ready signal once it's ready for us to dispatch
  // a client connection to it.
  ExtensionTestMessageListener socket_listening("ready",
                                                ReplyBehavior::kWillReply);
  scoped_refptr<const Extension> extension(
      LoadApp("api_test/bluetooth_socket/listen"));
  ASSERT_TRUE(extension.get());
  EXPECT_TRUE(socket_listening.WaitUntilSatisfied());

  // Connection events are dispatched using a couple of PostTask to the UI
  // thread. Waiting until idle ensures the event is dispatched to the
  // receiver(s).
  base::RunLoop().RunUntilIdle();
  ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
  socket_listening.Reply("go");

  // Second stage of tests checks for error conditions, and will clean up
  // the existing server and client sockets.
  EXPECT_CALL(*mock_server_socket, Disconnect(testing::_))
      .WillOnce(base::test::RunOnceCallback<0>());

  EXPECT_CALL(*mock_client_socket, Disconnect(testing::_))
      .WillOnce(base::test::RunOnceCallback<0>());

  EXPECT_TRUE(listener.WaitUntilSatisfied());
  listener.Reply("go");
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, PermissionDenied) {
  ResultCatcher catcher;
  catcher.RestrictToBrowserContext(browser_context());

  // Run the test.
  scoped_refptr<const Extension> extension(
      LoadApp("api_test/bluetooth_socket/permission_denied"));
  ASSERT_TRUE(extension.get());

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}