blob: 8a54f39c0a4ab77e99f2036da671a49dd1fb52d9 [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 <memory>
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/services/multidevice_setup/fake_account_status_change_delegate.h"
#include "chromeos/services/multidevice_setup/fake_host_status_observer.h"
#include "chromeos/services/multidevice_setup/multidevice_setup_impl.h"
#include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
#include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup.h"
#include "chromeos/services/multidevice_setup/public/mojom/constants.mojom.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace multidevice_setup {
namespace {
const size_t kNumTestDevices = 3;
class FakeMultiDeviceSetupFactory : public MultiDeviceSetupImpl::Factory {
public:
FakeMultiDeviceSetupFactory(
sync_preferences::TestingPrefServiceSyncable*
expected_testing_pref_service,
device_sync::FakeDeviceSyncClient* expected_device_sync_client,
secure_channel::FakeSecureChannelClient* expected_secure_channel_client)
: expected_testing_pref_service_(expected_testing_pref_service),
expected_device_sync_client_(expected_device_sync_client),
expected_secure_channel_client_(expected_secure_channel_client) {}
~FakeMultiDeviceSetupFactory() override = default;
FakeMultiDeviceSetup* instance() { return instance_; }
private:
std::unique_ptr<mojom::MultiDeviceSetup> BuildInstance(
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client) override {
EXPECT_FALSE(instance_);
EXPECT_EQ(expected_testing_pref_service_, pref_service);
EXPECT_EQ(expected_device_sync_client_, device_sync_client);
EXPECT_EQ(expected_secure_channel_client_, secure_channel_client);
auto instance = std::make_unique<FakeMultiDeviceSetup>();
instance_ = instance.get();
return instance;
}
sync_preferences::TestingPrefServiceSyncable* expected_testing_pref_service_;
device_sync::FakeDeviceSyncClient* expected_device_sync_client_;
secure_channel::FakeSecureChannelClient* expected_secure_channel_client_;
FakeMultiDeviceSetup* instance_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FakeMultiDeviceSetupFactory);
};
} // namespace
class MultiDeviceSetupServiceTest : public testing::Test {
protected:
MultiDeviceSetupServiceTest()
: test_devices_(
cryptauth::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {}
~MultiDeviceSetupServiceTest() override = default;
// testing::Test:
void SetUp() override {
test_pref_service_ =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_secure_channel_client_ =
std::make_unique<secure_channel::FakeSecureChannelClient>();
fake_multidevice_setup_factory_ =
std::make_unique<FakeMultiDeviceSetupFactory>(
test_pref_service_.get(), fake_device_sync_client_.get(),
fake_secure_channel_client_.get());
MultiDeviceSetupImpl::Factory::SetFactoryForTesting(
fake_multidevice_setup_factory_.get());
connector_factory_ =
service_manager::TestConnectorFactory::CreateForUniqueService(
std::make_unique<MultiDeviceSetupService>(
test_pref_service_.get(), fake_device_sync_client_.get(),
fake_secure_channel_client_.get()));
auto connector = connector_factory_->CreateConnector();
connector->BindInterface(mojom::kServiceName, &multidevice_setup_ptr_);
multidevice_setup_ptr_.FlushForTesting();
}
void TearDown() override {
MultiDeviceSetupImpl::Factory::SetFactoryForTesting(nullptr);
}
void CallTriggerEventForDebuggingBeforeInitializationComplete(
mojom::EventTypeForDebugging type) {
EXPECT_FALSE(last_debug_event_success_);
base::RunLoop run_loop;
multidevice_setup_ptr_->TriggerEventForDebugging(
type,
base::BindOnce(&MultiDeviceSetupServiceTest::OnDebugEventTriggered,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
// Always expected to fail before initialization completes.
EXPECT_FALSE(*last_debug_event_success_);
last_debug_event_success_.reset();
}
void FinishInitialization() {
EXPECT_FALSE(fake_multidevice_setup());
fake_device_sync_client_->set_local_device_metadata(test_devices_[0]);
fake_device_sync_client_->NotifyReady();
EXPECT_TRUE(fake_multidevice_setup());
}
FakeMultiDeviceSetup* fake_multidevice_setup() {
return fake_multidevice_setup_factory_->instance();
}
mojom::MultiDeviceSetupPtr& multidevice_setup_ptr() {
return multidevice_setup_ptr_;
}
private:
void OnDebugEventTriggered(base::OnceClosure quit_closure, bool success) {
last_debug_event_success_ = success;
std::move(quit_closure).Run();
}
const base::test::ScopedTaskEnvironment scoped_task_environment_;
const cryptauth::RemoteDeviceRefList test_devices_;
std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
test_pref_service_;
std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
std::unique_ptr<secure_channel::FakeSecureChannelClient>
fake_secure_channel_client_;
std::unique_ptr<FakeMultiDeviceSetupFactory> fake_multidevice_setup_factory_;
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
base::Optional<bool> last_debug_event_success_;
mojom::MultiDeviceSetupPtr multidevice_setup_ptr_;
DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupServiceTest);
};
TEST_F(MultiDeviceSetupServiceTest,
TriggerEventForDebuggingBeforeInitialization) {
CallTriggerEventForDebuggingBeforeInitializationComplete(
mojom::EventTypeForDebugging::kNewUserPotentialHostExists);
CallTriggerEventForDebuggingBeforeInitializationComplete(
mojom::EventTypeForDebugging::kExistingUserConnectedHostSwitched);
CallTriggerEventForDebuggingBeforeInitializationComplete(
mojom::EventTypeForDebugging::kExistingUserNewChromebookAdded);
}
TEST_F(MultiDeviceSetupServiceTest, CallFunctionsBeforeInitialization) {
// SetAccountStatusChangeDelegate().
auto fake_account_status_change_delegate =
std::make_unique<FakeAccountStatusChangeDelegate>();
multidevice_setup_ptr()->SetAccountStatusChangeDelegate(
fake_account_status_change_delegate->GenerateInterfacePtr());
multidevice_setup_ptr().FlushForTesting();
// AddHostStatusObserver().
auto fake_host_status_observer = std::make_unique<FakeHostStatusObserver>();
multidevice_setup_ptr()->AddHostStatusObserver(
fake_host_status_observer->GenerateInterfacePtr());
multidevice_setup_ptr().FlushForTesting();
// GetEligibleHostDevices().
multidevice_setup_ptr()->GetEligibleHostDevices(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
// GetHostStatus().
multidevice_setup_ptr()->GetHostStatus(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
// RetrySetHostNow().
multidevice_setup_ptr()->RetrySetHostNow(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
// None of these requests should have been processed yet, since initialization
// was not complete.
EXPECT_FALSE(fake_multidevice_setup());
// Finish initialization; all of the pending calls should have been forwarded.
FinishInitialization();
EXPECT_TRUE(fake_multidevice_setup()->delegate());
EXPECT_EQ(1u, fake_multidevice_setup()->observers().size());
EXPECT_EQ(1u, fake_multidevice_setup()->get_eligible_hosts_args().size());
EXPECT_EQ(1u, fake_multidevice_setup()->get_host_args().size());
EXPECT_EQ(1u, fake_multidevice_setup()->retry_set_host_now_args().size());
}
TEST_F(MultiDeviceSetupServiceTest, SetThenRemoveBeforeInitialization) {
multidevice_setup_ptr()->SetHostDevice("publicKey", base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
multidevice_setup_ptr()->RemoveHostDevice();
multidevice_setup_ptr().FlushForTesting();
EXPECT_FALSE(fake_multidevice_setup());
// Finish initialization; since the SetHostDevice() call was followed by a
// RemoveHostDevice() call, only the RemoveHostDevice() call should have been
// forwarded.
FinishInitialization();
EXPECT_TRUE(fake_multidevice_setup()->set_host_args().empty());
EXPECT_EQ(1u, fake_multidevice_setup()->num_remove_host_calls());
}
TEST_F(MultiDeviceSetupServiceTest, RemoveThenSetThenSetBeforeInitialization) {
multidevice_setup_ptr()->RemoveHostDevice();
multidevice_setup_ptr().FlushForTesting();
multidevice_setup_ptr()->SetHostDevice("publicKey1", base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
multidevice_setup_ptr()->SetHostDevice("publicKey2", base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
EXPECT_FALSE(fake_multidevice_setup());
// Finish initialization; only the second SetHostDevice() call should have
// been forwarded.
FinishInitialization();
EXPECT_EQ(1u, fake_multidevice_setup()->set_host_args().size());
EXPECT_EQ("publicKey2", fake_multidevice_setup()->set_host_args()[0].first);
EXPECT_EQ(0u, fake_multidevice_setup()->num_remove_host_calls());
}
TEST_F(MultiDeviceSetupServiceTest, FinishInitializationFirst) {
// Finish initialization before calling anything; this should result in
// the calls being forwarded immediately.
FinishInitialization();
// SetAccountStatusChangeDelegate().
auto fake_account_status_change_delegate =
std::make_unique<FakeAccountStatusChangeDelegate>();
multidevice_setup_ptr()->SetAccountStatusChangeDelegate(
fake_account_status_change_delegate->GenerateInterfacePtr());
multidevice_setup_ptr().FlushForTesting();
EXPECT_TRUE(fake_multidevice_setup()->delegate());
// AddHostStatusObserver().
auto fake_host_status_observer = std::make_unique<FakeHostStatusObserver>();
multidevice_setup_ptr()->AddHostStatusObserver(
fake_host_status_observer->GenerateInterfacePtr());
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->observers().size());
// GetEligibleHostDevices().
multidevice_setup_ptr()->GetEligibleHostDevices(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->get_eligible_hosts_args().size());
// SetHostDevice().
multidevice_setup_ptr()->SetHostDevice("publicKey", base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->set_host_args().size());
// RemoveHostDevice().
multidevice_setup_ptr()->RemoveHostDevice();
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->num_remove_host_calls());
// GetHostStatus().
multidevice_setup_ptr()->GetHostStatus(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->get_host_args().size());
// RetrySetHostNow().
multidevice_setup_ptr()->RetrySetHostNow(base::DoNothing());
multidevice_setup_ptr().FlushForTesting();
EXPECT_EQ(1u, fake_multidevice_setup()->retry_set_host_now_args().size());
}
} // namespace multidevice_setup
} // namespace chromeos