blob: 562073c2797b861ccd0d1cb67cbc9de504621893 [file] [log] [blame]
// Copyright 2018 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 "chromecast/browser/bluetooth/cast_bluetooth_chooser.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromecast {
namespace {
class SimpleDeviceAccessProvider : public mojom::BluetoothDeviceAccessProvider {
public:
SimpleDeviceAccessProvider() = default;
~SimpleDeviceAccessProvider() override = default;
// mojom::BluetoothDeviceAccessProvider implementation:
void RequestDeviceAccess(
mojom::BluetoothDeviceAccessProviderClientPtr client) override {
DCHECK(!client_);
client.set_connection_error_handler(connection_closed_.Get());
for (const auto& address : approved_devices_)
client->GrantAccess(address);
client_ = std::move(client);
}
mojom::BluetoothDeviceAccessProviderClientPtr& client() { return client_; }
base::MockCallback<base::OnceClosure>& connection_closed() {
return connection_closed_;
}
std::vector<std::string>& approved_devices() { return approved_devices_; }
private:
mojom::BluetoothDeviceAccessProviderClientPtr client_;
base::MockCallback<base::OnceClosure> connection_closed_;
std::vector<std::string> approved_devices_;
DISALLOW_COPY_AND_ASSIGN(SimpleDeviceAccessProvider);
};
} // namespace
using testing::AnyOf;
class CastBluetoothChooserTest : public testing::Test {
public:
CastBluetoothChooserTest() : provider_binding_(&provider_) {
mojom::BluetoothDeviceAccessProviderPtr provider;
provider_binding_.Bind(mojo::MakeRequest(&provider));
cast_bluetooth_chooser_ = std::make_unique<CastBluetoothChooser>(
handler_.Get(), std::move(provider));
scoped_task_environment_.RunUntilIdle();
}
~CastBluetoothChooserTest() override = default;
void AddDeviceToChooser(const std::string& address) {
chooser().AddOrUpdateDevice(address, false, base::string16(), false, false,
0);
}
SimpleDeviceAccessProvider& provider() { return provider_; }
content::BluetoothChooser& chooser() { return *cast_bluetooth_chooser_; }
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::MockCallback<content::BluetoothChooser::EventHandler> handler_;
private:
SimpleDeviceAccessProvider provider_;
mojo::Binding<mojom::BluetoothDeviceAccessProvider> provider_binding_;
std::unique_ptr<CastBluetoothChooser> cast_bluetooth_chooser_;
DISALLOW_COPY_AND_ASSIGN(CastBluetoothChooserTest);
};
TEST_F(CastBluetoothChooserTest, GrantAccessBeforeDeviceAvailable) {
// No devices have been made available to |chooser| yet. Grant it access to a
// device. |handler| should not run yet.
EXPECT_TRUE(provider().client());
provider().client()->GrantAccess("aa:bb:cc:dd:ee:ff");
scoped_task_environment_.RunUntilIdle();
// Make some unapproved devices available. |handler| should not run yet.
AddDeviceToChooser("11:22:33:44:55:66");
AddDeviceToChooser("99:88:77:66:55:44");
// Now make the approved device available. |handler| should be called.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::SELECTED,
"aa:bb:cc:dd:ee:ff"));
EXPECT_CALL(provider().connection_closed(), Run());
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
scoped_task_environment_.RunUntilIdle();
}
TEST_F(CastBluetoothChooserTest, DiscoverDeviceBeforeAccessGranted) {
// Make some devices available before access is granted. |handler| should not
// run yet.
AddDeviceToChooser("11:22:33:44:55:66");
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
AddDeviceToChooser("00:00:00:11:00:00");
AddDeviceToChooser("99:88:77:66:55:44");
// Now approve one of those devices. |handler| should run.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::SELECTED,
"00:00:00:11:00:00"));
EXPECT_CALL(provider().connection_closed(), Run());
provider().client()->GrantAccess("00:00:00:11:00:00");
scoped_task_environment_.RunUntilIdle();
}
TEST_F(CastBluetoothChooserTest, GrantAccessToAllDevicesBeforeDiscovery) {
// Grant access to all devices. |handler| should not run until the first
// device is made available.
provider().client()->GrantAccessToAllDevices();
scoped_task_environment_.RunUntilIdle();
// Now make the some device available. |handler| should be called.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::SELECTED,
"aa:bb:cc:dd:ee:ff"));
EXPECT_CALL(provider().connection_closed(), Run());
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
scoped_task_environment_.RunUntilIdle();
}
TEST_F(CastBluetoothChooserTest, GrantAccessToAllDevicesAfterDiscovery) {
// Make some devices available before access is granted. |handler| should not
// run yet.
AddDeviceToChooser("11:22:33:44:55:66");
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
AddDeviceToChooser("00:00:00:11:00:00");
// Now grant access to all devices. |handler| should be called with one of the
// available devices.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::SELECTED,
AnyOf("11:22:33:44:55:66", "aa:bb:cc:dd:ee:ff",
"00:00:00:11:00:00")));
EXPECT_CALL(provider().connection_closed(), Run());
provider().client()->GrantAccessToAllDevices();
scoped_task_environment_.RunUntilIdle();
}
TEST_F(CastBluetoothChooserTest, TearDownClientAfterAllAccessGranted) {
// Grant access to all devices. |handler| should not run until the first
// device is made available.
provider().client()->GrantAccessToAllDevices();
scoped_task_environment_.RunUntilIdle();
// Tear down the client. Now that it has granted access to the client, it does
// not need to keep a reference to it. However, the chooser should stay alive
// and wait for devices to be made available.
provider().client().reset();
EXPECT_FALSE(provider().client());
scoped_task_environment_.RunUntilIdle();
// As soon as a device is available, run the handler.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::SELECTED,
"aa:bb:cc:dd:ee:ff"));
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
}
TEST_F(CastBluetoothChooserTest, TearDownClientBeforeApprovedDeviceDiscovered) {
// Make some devices available before access is granted. |handler| should not
// run yet.
AddDeviceToChooser("11:22:33:44:55:66");
AddDeviceToChooser("aa:bb:cc:dd:ee:ff");
// Tear the client down before any access is granted. |handler| should run,
// but with Event::CANCELLED.
EXPECT_CALL(handler_, Run(content::BluetoothChooser::Event::CANCELLED, ""));
provider().client().reset();
EXPECT_FALSE(provider().client());
scoped_task_environment_.RunUntilIdle();
}
} // namespace chromecast