blob: ac8e0f7f7f28fd06d3e9803d0a7c3eb652858b62 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/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 "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;
namespace utils = extension_function_test_utils;
namespace api = extensions::api;
namespace {
class BluetoothSocketApiTest : public ExtensionApiTest {
public:
BluetoothSocketApiTest() {}
virtual void SetUpOnMainThread() OVERRIDE {
ExtensionApiTest::SetUpOnMainThread();
empty_extension_ = utils::CreateEmptyExtension();
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_.reset(new testing::NiceMock<MockBluetoothDevice>(
mock_adapter_, 0, "d1", "11:12:13:14:15:16",
true /* paired */, false /* connected */));
mock_device2_.reset(new testing::NiceMock<MockBluetoothDevice>(
mock_adapter_, 0, "d2", "21:22:23:24:25:26",
true /* paired */, false /* connected */));
}
protected:
scoped_refptr<testing::StrictMock<MockBluetoothAdapter> > mock_adapter_;
scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device1_;
scoped_ptr<testing::NiceMock<MockBluetoothDevice> > mock_device2_;
private:
scoped_refptr<Extension> empty_extension_;
};
// testing::InvokeArgument<N> does not work with base::Callback, fortunately
// gmock makes it simple to create action templates that do for the various
// possible numbers of arguments.
ACTION_TEMPLATE(InvokeCallbackArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_0_VALUE_PARAMS()) {
::std::tr1::get<k>(args).Run();
}
ACTION_TEMPLATE(InvokeCallbackArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(p0)) {
::std::tr1::get<k>(args).Run(p0);
}
ACTION_TEMPLATE(InvokeCallbackArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(p0, p1)) {
::std::tr1::get<k>(args).Run(p0, p1);
}
} // namespace
IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Connect) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
// 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_.get(), GetDevice(mock_device1_->GetAddress()))
.WillRepeatedly(testing::Return(mock_device1_.get()));
EXPECT_CALL(*mock_adapter_.get(), GetDevice(std::string("aa:aa:aa:aa:aa:aa")))
.WillOnce(testing::Return(static_cast<BluetoothDevice*>(NULL)));
// 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(InvokeCallbackArgument<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.get(), Receive(testing::_, testing::_, testing::_));
// The test also cleans up by calling Disconnect and Close.
EXPECT_CALL(*mock_socket.get(), Disconnect(testing::_))
.WillOnce(InvokeCallbackArgument<0>());
EXPECT_CALL(*mock_socket.get(), Close());
// Run the test.
ExtensionTestMessageListener listener("ready", true);
scoped_refptr<const Extension> extension(
LoadExtension(test_data_dir_.AppendASCII("bluetooth_socket/connect")));
ASSERT_TRUE(extension.get());
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
#if defined(_LIBCPP_VERSION)
// This test fails in libc++ builds, see http://crbug.com/392205.
#define MAYBE_Listen DISABLED_Listen
#else
#define MAYBE_Listen Listen
#endif
IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, MAYBE_Listen) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
// 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.reset(new std::string("MyServiceName"));
EXPECT_CALL(
*mock_adapter_.get(),
CreateRfcommService(
service_uuid,
testing::Field(&BluetoothAdapter::ServiceOptions::name,
testing::Pointee(testing::Eq("MyServiceName"))),
testing::_,
testing::_)).WillOnce(InvokeCallbackArgument<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.get(), Accept(testing::_, testing::_))
.Times(2)
.WillOnce(
InvokeCallbackArgument<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", true);
scoped_refptr<const Extension> extension(
LoadExtension(test_data_dir_.AppendASCII("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", true);
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.get(), Disconnect(testing::_))
.WillOnce(InvokeCallbackArgument<0>());
EXPECT_CALL(*mock_server_socket.get(), Close());
EXPECT_CALL(*mock_client_socket.get(), Disconnect(testing::_))
.WillOnce(InvokeCallbackArgument<0>());
EXPECT_CALL(*mock_client_socket.get(), Close());
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, PermissionDenied) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
// Run the test.
scoped_refptr<const Extension> extension(
LoadExtension(test_data_dir_.AppendASCII(
"bluetooth_socket/permission_denied")));
ASSERT_TRUE(extension.get());
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}