Commit d7fcfd6e authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS MultiDevice] Re-land HostStatusProvider.

This CL relands this CL (uploaded as patchset 1):
https://chromium-review.googlesource.com/c/chromium/src/+/1113020

Which was reverted here:
https://chromium-review.googlesource.com/c/chromium/src/+/1116158

The issue here is that I forgot to make a virtual function pure virtual.

Original CL description:

This class provides an interface for fetching the current host status
and, when applicable, the current host device. Additionally, this class
provides an observer interface for being notified when the status
changes.

TBR=dcheng@chromium.org

Bug: 824568
Change-Id: Ice48e925295f50716aa696a80acdb8ad1f515bed
Reviewed-on: https://chromium-review.googlesource.com/1116072
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570626}
parent e50f3dd4
...@@ -21,6 +21,10 @@ static_library("multidevice_setup") { ...@@ -21,6 +21,10 @@ static_library("multidevice_setup") {
"host_backend_delegate.h", "host_backend_delegate.h",
"host_backend_delegate_impl.cc", "host_backend_delegate_impl.cc",
"host_backend_delegate_impl.h", "host_backend_delegate_impl.h",
"host_status_provider.cc",
"host_status_provider.h",
"host_status_provider_impl.cc",
"host_status_provider_impl.h",
"host_verifier.cc", "host_verifier.cc",
"host_verifier.h", "host_verifier.h",
"host_verifier_impl.cc", "host_verifier_impl.cc",
...@@ -69,6 +73,8 @@ static_library("test_support") { ...@@ -69,6 +73,8 @@ static_library("test_support") {
"fake_eligible_host_devices_provider.h", "fake_eligible_host_devices_provider.h",
"fake_host_backend_delegate.cc", "fake_host_backend_delegate.cc",
"fake_host_backend_delegate.h", "fake_host_backend_delegate.h",
"fake_host_status_provider.cc",
"fake_host_status_provider.h",
"fake_host_verifier.cc", "fake_host_verifier.cc",
"fake_host_verifier.h", "fake_host_verifier.h",
"fake_multidevice_setup.cc", "fake_multidevice_setup.cc",
...@@ -94,6 +100,7 @@ source_set("unit_tests") { ...@@ -94,6 +100,7 @@ source_set("unit_tests") {
"account_status_change_delegate_notifier_impl_unittest.cc", "account_status_change_delegate_notifier_impl_unittest.cc",
"eligible_host_devices_provider_impl_unittest.cc", "eligible_host_devices_provider_impl_unittest.cc",
"host_backend_delegate_impl_unittest.cc", "host_backend_delegate_impl_unittest.cc",
"host_status_provider_impl_unittest.cc",
"host_verifier_impl_unittest.cc", "host_verifier_impl_unittest.cc",
"multidevice_setup_impl_unittest.cc", "multidevice_setup_impl_unittest.cc",
"multidevice_setup_service_unittest.cc", "multidevice_setup_service_unittest.cc",
......
// 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 "chromeos/services/multidevice_setup/fake_host_status_provider.h"
namespace chromeos {
namespace multidevice_setup {
FakeHostStatusProvider::FakeHostStatusProvider() = default;
FakeHostStatusProvider::~FakeHostStatusProvider() = default;
void FakeHostStatusProvider::SetHostWithStatus(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device) {
bool should_notify =
host_status_ != host_status || host_device_ != host_device;
host_status_ = host_status;
host_device_ = host_device;
if (!should_notify)
return;
NotifyHostStatusChange(host_status_, host_device_);
}
HostStatusProvider::HostStatusWithDevice
FakeHostStatusProvider::GetHostWithStatus() const {
return HostStatusWithDevice(host_status_, host_device_);
}
FakeHostStatusProviderObserver::FakeHostStatusProviderObserver() = default;
FakeHostStatusProviderObserver::~FakeHostStatusProviderObserver() = default;
void FakeHostStatusProviderObserver::OnHostStatusChange(
const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
host_status_updates_.push_back(host_status_with_device);
}
} // namespace multidevice_setup
} // namespace chromeos
// 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.
#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_STATUS_PROVIDER_H_
#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_STATUS_PROVIDER_H_
#include <vector>
#include "base/macros.h"
#include "chromeos/services/multidevice_setup/host_status_provider.h"
namespace chromeos {
namespace multidevice_setup {
// Test HostStatusProvider implementation.
class FakeHostStatusProvider : public HostStatusProvider {
public:
FakeHostStatusProvider();
~FakeHostStatusProvider() override;
void SetHostWithStatus(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device);
private:
// HostStatusProvider:
HostStatusWithDevice GetHostWithStatus() const override;
mojom::HostStatus host_status_ = mojom::HostStatus::kNoEligibleHosts;
base::Optional<cryptauth::RemoteDeviceRef> host_device_;
DISALLOW_COPY_AND_ASSIGN(FakeHostStatusProvider);
};
// Test HostStatusProvider::Observer implementation.
class FakeHostStatusProviderObserver : public HostStatusProvider::Observer {
public:
FakeHostStatusProviderObserver();
~FakeHostStatusProviderObserver() override;
const std::vector<HostStatusProvider::HostStatusWithDevice>&
host_status_updates() const {
return host_status_updates_;
}
private:
// HostStatusProvider::Observer:
void OnHostStatusChange(const HostStatusProvider::HostStatusWithDevice&
host_status_with_device) override;
std::vector<HostStatusProvider::HostStatusWithDevice> host_status_updates_;
DISALLOW_COPY_AND_ASSIGN(FakeHostStatusProviderObserver);
};
} // namespace multidevice_setup
} // namespace chromeos
#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_STATUS_PROVIDER_H_
// 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 "chromeos/services/multidevice_setup/host_status_provider.h"
#include "base/logging.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
namespace chromeos {
namespace multidevice_setup {
HostStatusProvider::HostStatusWithDevice::HostStatusWithDevice(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device)
: host_status_(host_status), host_device_(host_device) {
if (host_status_ == mojom::HostStatus::kNoEligibleHosts ||
host_status_ == mojom::HostStatus::kEligibleHostExistsButNoHostSet) {
if (host_device_) {
PA_LOG(ERROR) << "HostStatusWithDevice::HostStatusWithDevice(): Tried to "
<< "construct a HostStatusWithDevice with a status "
<< "indicatating no device, but a device was provided. "
<< "Status: " << host_status_ << ", Device ID: "
<< host_device_->GetTruncatedDeviceIdForLogs();
NOTREACHED();
}
} else if (!host_device_) {
PA_LOG(ERROR) << "HostStatusWithDevice::HostStatusWithDevice(): Tried to "
<< "construct a HostStatusWithDevice with a status "
<< "indicatating a device, but no device was provided."
<< "Status: " << host_status_;
NOTREACHED();
}
}
HostStatusProvider::HostStatusWithDevice::HostStatusWithDevice(
const HostStatusWithDevice& other) = default;
HostStatusProvider::HostStatusWithDevice::~HostStatusWithDevice() = default;
bool HostStatusProvider::HostStatusWithDevice::operator==(
const HostStatusWithDevice& other) const {
return host_status_ == other.host_status_ &&
host_device_ == other.host_device_;
}
bool HostStatusProvider::HostStatusWithDevice::operator!=(
const HostStatusWithDevice& other) const {
return !(*this == other);
}
HostStatusProvider::HostStatusProvider() = default;
HostStatusProvider::~HostStatusProvider() = default;
void HostStatusProvider::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void HostStatusProvider::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void HostStatusProvider::NotifyHostStatusChange(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device) {
HostStatusWithDevice host_status_with_device(host_status, host_device);
for (auto& observer : observer_list_)
observer.OnHostStatusChange(host_status_with_device);
}
} // namespace multidevice_setup
} // namespace chromeos
// 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.
#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_H_
#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_H_
#include "base/macros.h"
#include "base/observer_list.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/cryptauth/remote_device_ref.h"
namespace chromeos {
namespace multidevice_setup {
// Provides the status of the current MultiDevice host, if it exists.
// Additionally, provides an observer interface for being notified when the host
// status changes.
class HostStatusProvider {
public:
class HostStatusWithDevice {
public:
HostStatusWithDevice(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device);
HostStatusWithDevice(const HostStatusWithDevice& other);
~HostStatusWithDevice();
bool operator==(const HostStatusWithDevice& other) const;
bool operator!=(const HostStatusWithDevice& other) const;
mojom::HostStatus host_status() const { return host_status_; }
// If host_status() is kNoEligibleHosts or
// kEligibleHostExistsButNoHostSet, host_device() is null.
const base::Optional<cryptauth::RemoteDeviceRef>& host_device() const {
return host_device_;
}
private:
mojom::HostStatus host_status_;
base::Optional<cryptauth::RemoteDeviceRef> host_device_;
};
class Observer {
public:
virtual ~Observer() = default;
virtual void OnHostStatusChange(
const HostStatusWithDevice& host_status_with_device) = 0;
};
virtual ~HostStatusProvider();
virtual HostStatusWithDevice GetHostWithStatus() const = 0;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
protected:
HostStatusProvider();
void NotifyHostStatusChange(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device);
private:
base::ObserverList<Observer> observer_list_;
DISALLOW_COPY_AND_ASSIGN(HostStatusProvider);
};
} // namespace multidevice_setup
} // namespace chromeos
#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_H_
// 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 "chromeos/services/multidevice_setup/host_status_provider_impl.h"
#include <algorithm>
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/multidevice_setup/eligible_host_devices_provider.h"
namespace chromeos {
namespace multidevice_setup {
// static
HostStatusProviderImpl::Factory*
HostStatusProviderImpl::Factory::test_factory_ = nullptr;
// static
HostStatusProviderImpl::Factory* HostStatusProviderImpl::Factory::Get() {
if (test_factory_)
return test_factory_;
static base::NoDestructor<Factory> factory;
return factory.get();
}
// static
void HostStatusProviderImpl::Factory::SetFactoryForTesting(
Factory* test_factory) {
test_factory_ = test_factory;
}
HostStatusProviderImpl::Factory::~Factory() = default;
std::unique_ptr<HostStatusProvider>
HostStatusProviderImpl::Factory::BuildInstance(
EligibleHostDevicesProvider* eligible_host_devices_provider,
HostBackendDelegate* host_backend_delegate,
HostVerifier* host_verifier,
device_sync::DeviceSyncClient* device_sync_client) {
return base::WrapUnique(new HostStatusProviderImpl(
eligible_host_devices_provider, host_backend_delegate, host_verifier,
device_sync_client));
}
HostStatusProviderImpl::HostStatusProviderImpl(
EligibleHostDevicesProvider* eligible_host_devices_provider,
HostBackendDelegate* host_backend_delegate,
HostVerifier* host_verifier,
device_sync::DeviceSyncClient* device_sync_client)
: eligible_host_devices_provider_(eligible_host_devices_provider),
host_backend_delegate_(host_backend_delegate),
host_verifier_(host_verifier),
device_sync_client_(device_sync_client),
current_status_and_device_(mojom::HostStatus::kNoEligibleHosts,
base::nullopt /* host_device */) {
host_backend_delegate_->AddObserver(this);
host_verifier_->AddObserver(this);
device_sync_client_->AddObserver(this);
CheckForUpdatedStatusAndNotifyIfChanged();
}
HostStatusProviderImpl::~HostStatusProviderImpl() {
host_backend_delegate_->RemoveObserver(this);
host_verifier_->RemoveObserver(this);
device_sync_client_->RemoveObserver(this);
}
HostStatusProvider::HostStatusWithDevice
HostStatusProviderImpl::GetHostWithStatus() const {
return current_status_and_device_;
}
void HostStatusProviderImpl::OnHostChangedOnBackend() {
CheckForUpdatedStatusAndNotifyIfChanged();
}
void HostStatusProviderImpl::OnPendingHostRequestChange() {
CheckForUpdatedStatusAndNotifyIfChanged();
}
void HostStatusProviderImpl::OnHostVerified() {
CheckForUpdatedStatusAndNotifyIfChanged();
}
void HostStatusProviderImpl::OnNewDevicesSynced() {
CheckForUpdatedStatusAndNotifyIfChanged();
}
void HostStatusProviderImpl::CheckForUpdatedStatusAndNotifyIfChanged() {
HostStatusWithDevice current_status_and_device = GetCurrentStatus();
if (current_status_and_device == current_status_and_device_)
return;
PA_LOG(INFO) << "HostStatusProviderImpl::"
<< "CheckForUpdatedStatusAndNotifyIfChanged(): Host status "
<< "changed. New status: "
<< current_status_and_device.host_status()
<< ", Old status: " << current_status_and_device_.host_status()
<< ", Host device "
<< "ID: "
<< (current_status_and_device.host_device()
? current_status_and_device.host_device()
->GetTruncatedDeviceIdForLogs()
: "[no host]");
current_status_and_device_ = current_status_and_device;
NotifyHostStatusChange(current_status_and_device_.host_status(),
current_status_and_device_.host_device());
}
HostStatusProvider::HostStatusWithDevice
HostStatusProviderImpl::GetCurrentStatus() {
if (host_verifier_->IsHostVerified()) {
return HostStatusWithDevice(
mojom::HostStatus::kHostVerified,
*host_backend_delegate_->GetMultiDeviceHostFromBackend());
}
if (host_backend_delegate_->GetMultiDeviceHostFromBackend() &&
!host_backend_delegate_->HasPendingHostRequest()) {
return HostStatusWithDevice(
mojom::HostStatus::kHostSetButNotYetVerified,
*host_backend_delegate_->GetMultiDeviceHostFromBackend());
}
if (host_backend_delegate_->HasPendingHostRequest() &&
host_backend_delegate_->GetPendingHostRequest()) {
return HostStatusWithDevice(
mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
*host_backend_delegate_->GetPendingHostRequest());
}
if (!eligible_host_devices_provider_->GetEligibleHostDevices().empty()) {
return HostStatusWithDevice(
mojom::HostStatus::kEligibleHostExistsButNoHostSet,
base::nullopt /* host_device */);
}
return HostStatusWithDevice(mojom::HostStatus::kNoEligibleHosts,
base::nullopt /* host_device */);
}
} // namespace multidevice_setup
} // namespace chromeos
// 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.
#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_IMPL_H_
#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_IMPL_H_
#include "base/macros.h"
#include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
#include "chromeos/services/multidevice_setup/host_backend_delegate.h"
#include "chromeos/services/multidevice_setup/host_status_provider.h"
#include "chromeos/services/multidevice_setup/host_verifier.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/cryptauth/remote_device_ref.h"
namespace chromeos {
namespace multidevice_setup {
class EligibleHostDevicesProvider;
// Concrete HostStatusProvider implementation. This class listens for events
// from HostBackendDelegate, HostVerifier, and DeviceSyncClient to determine
// when the status of the host has changed.
class HostStatusProviderImpl : public HostStatusProvider,
public HostBackendDelegate::Observer,
public HostVerifier::Observer,
public device_sync::DeviceSyncClient::Observer {
public:
class Factory {
public:
static Factory* Get();
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<HostStatusProvider> BuildInstance(
EligibleHostDevicesProvider* eligible_host_devices_provider,
HostBackendDelegate* host_backend_delegate,
HostVerifier* host_verifier,
device_sync::DeviceSyncClient* device_sync_client);
private:
static Factory* test_factory_;
};
~HostStatusProviderImpl() override;
private:
HostStatusProviderImpl(
EligibleHostDevicesProvider* eligible_host_devices_provider,
HostBackendDelegate* host_backend_delegate,
HostVerifier* host_verifier,
device_sync::DeviceSyncClient* device_sync_client);
// HostStatusProvider:
HostStatusWithDevice GetHostWithStatus() const override;
// HostBackendDelegate::Observer:
void OnHostChangedOnBackend() override;
void OnPendingHostRequestChange() override;
// HostVerifier::Observer:
void OnHostVerified() override;
// device_sync::DeviceSyncClient::Observer:
void OnNewDevicesSynced() override;
void CheckForUpdatedStatusAndNotifyIfChanged();
HostStatusWithDevice GetCurrentStatus();
EligibleHostDevicesProvider* eligible_host_devices_provider_;
HostBackendDelegate* host_backend_delegate_;
HostVerifier* host_verifier_;
device_sync::DeviceSyncClient* device_sync_client_;
HostStatusWithDevice current_status_and_device_;
DISALLOW_COPY_AND_ASSIGN(HostStatusProviderImpl);
};
} // namespace multidevice_setup
} // namespace chromeos
#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_STATUS_PROVIDER_IMPL_H_
// 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 "chromeos/services/multidevice_setup/host_status_provider_impl.h"
#include <memory>
#include "base/macros.h"
#include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/services/multidevice_setup/fake_eligible_host_devices_provider.h"
#include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h"
#include "chromeos/services/multidevice_setup/fake_host_status_provider.h"
#include "chromeos/services/multidevice_setup/fake_host_verifier.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace multidevice_setup {
namespace {
const size_t kNumTestDevices = 5;
} // namespace
class MultiDeviceSetupHostStatusProviderImplTest : public testing::Test {
protected:
MultiDeviceSetupHostStatusProviderImplTest()
: test_devices_(
cryptauth::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {}
~MultiDeviceSetupHostStatusProviderImplTest() override = default;
// testing::Test:
void SetUp() override {
fake_eligible_host_devices_provider_ =
std::make_unique<FakeEligibleHostDevicesProvider>();
fake_host_backend_delegate_ = std::make_unique<FakeHostBackendDelegate>();
fake_host_verifier_ = std::make_unique<FakeHostVerifier>();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_device_sync_client_->set_synced_devices(test_devices_);
host_status_provider_ =
HostStatusProviderImpl::Factory::Get()->BuildInstance(
fake_eligible_host_devices_provider_.get(),
fake_host_backend_delegate_.get(), fake_host_verifier_.get(),
fake_device_sync_client_.get());
fake_observer_ = std::make_unique<FakeHostStatusProviderObserver>();
host_status_provider_->AddObserver(fake_observer_.get());
}
void TearDown() override {
host_status_provider_->RemoveObserver(fake_observer_.get());
}
void MakeDevicesEligibleHosts() {
fake_eligible_host_devices_provider_->set_eligible_host_devices(
test_devices_);
fake_device_sync_client_->NotifyNewDevicesSynced();
}
// Verifies the current status and, if |expected_observer_index| is non-null,
// verifies that the observer received that update at the specified index.
void VerifyCurrentStatus(
mojom::HostStatus host_status,
const base::Optional<cryptauth::RemoteDeviceRef>& host_device,
const base::Optional<size_t>& expected_observer_index) {
HostStatusProvider::HostStatusWithDevice status_with_device(host_status,
host_device);
EXPECT_EQ(status_with_device, host_status_provider_->GetHostWithStatus());
if (!expected_observer_index)
return;
EXPECT_EQ(status_with_device,
fake_observer_->host_status_updates()[*expected_observer_index]);
}
size_t GetNumChangeEvents() {
return fake_observer_->host_status_updates().size();
}
const cryptauth::RemoteDeviceRefList& test_devices() const {
return test_devices_;
}
FakeHostBackendDelegate* fake_host_backend_delegate() {
return fake_host_backend_delegate_.get();
}
FakeHostVerifier* fake_host_verifier() { return fake_host_verifier_.get(); }
private:
cryptauth::RemoteDeviceRefList test_devices_;
std::unique_ptr<FakeEligibleHostDevicesProvider>
fake_eligible_host_devices_provider_;
std::unique_ptr<FakeHostBackendDelegate> fake_host_backend_delegate_;
std::unique_ptr<FakeHostVerifier> fake_host_verifier_;
std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
std::unique_ptr<FakeHostStatusProviderObserver> fake_observer_;
std::unique_ptr<HostStatusProvider> host_status_provider_;
DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupHostStatusProviderImplTest);
};
TEST_F(MultiDeviceSetupHostStatusProviderImplTest,
IncreaseHostState_ThenDecrease) {
VerifyCurrentStatus(mojom::HostStatus::kNoEligibleHosts,
base::nullopt /* host_device */,
base::nullopt /* expected_observer_index */);
// Add eligible hosts to the account and verify that the status has been
// updated accordingly.
MakeDevicesEligibleHosts();
EXPECT_EQ(1u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet,
base::nullopt /* host_device */,
0u /* expected_observer_index */);
// Make a request to set the host, but do not complete it yet.
fake_host_backend_delegate()->AttemptToSetMultiDeviceHostOnBackend(
test_devices()[0]);
EXPECT_EQ(2u, GetNumChangeEvents());
VerifyCurrentStatus(
mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
test_devices()[0] /* host_device */, 1u /* expected_observer_index */);
// Successfully set the host on the back-end.
fake_host_backend_delegate()->NotifyHostChangedOnBackend(test_devices()[0]);
EXPECT_EQ(3u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kHostSetButNotYetVerified,
test_devices()[0] /* host_device */,
2u /* expected_observer_index */);
// Verify the device.
fake_host_verifier()->set_is_host_verified(true);
fake_host_verifier()->NotifyHostVerified();
EXPECT_EQ(4u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kHostVerified,
test_devices()[0] /* host_device */,
3u /* expected_observer_index */);
}
TEST_F(MultiDeviceSetupHostStatusProviderImplTest, SetHostThenForget) {
MakeDevicesEligibleHosts();
EXPECT_EQ(1u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet,
base::nullopt /* host_device */,
0u /* expected_observer_index */);
// Without first attempting to set the host on the back-end, set the device.
// This simulates the case where the host is set by another device (e.g., if
// another Chromebook completes the setup flow).
fake_host_backend_delegate()->NotifyHostChangedOnBackend(test_devices()[0]);
EXPECT_EQ(2u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kHostSetButNotYetVerified,
test_devices()[0] /* host_device */,
1u /* expected_observer_index */);
// Now, start an attempt to remove the device on the back-end. This simulates
// the user clicking "forget device" in settings.
fake_host_backend_delegate()->AttemptToSetMultiDeviceHostOnBackend(
base::nullopt /* host_device */);
EXPECT_EQ(3u, GetNumChangeEvents());
VerifyCurrentStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet,
base::nullopt /* host_device */,
2u /* expected_observer_index */);
// Complete the pending back-end request. In this case, the status should stay
// the same, so the observer should not have received an additional event.
fake_host_backend_delegate()->NotifyHostChangedOnBackend(
base::nullopt /* host_device_on_backend */);
EXPECT_EQ(3u, GetNumChangeEvents());
}
} // namespace multidevice_setup
} // namespace chromeos
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h" #include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
#include "chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.h" #include "chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.h"
#include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h" #include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h"
#include "chromeos/services/multidevice_setup/host_status_provider_impl.h"
#include "chromeos/services/multidevice_setup/host_verifier_impl.h" #include "chromeos/services/multidevice_setup/host_verifier_impl.h"
#include "chromeos/services/multidevice_setup/setup_flow_completion_recorder_impl.h" #include "chromeos/services/multidevice_setup/setup_flow_completion_recorder_impl.h"
...@@ -64,6 +65,12 @@ MultiDeviceSetupImpl::MultiDeviceSetupImpl( ...@@ -64,6 +65,12 @@ MultiDeviceSetupImpl::MultiDeviceSetupImpl(
host_backend_delegate_.get(), host_backend_delegate_.get(),
device_sync_client, device_sync_client,
secure_channel_client)), secure_channel_client)),
host_status_provider_(
HostStatusProviderImpl::Factory::Get()->BuildInstance(
eligible_host_devices_provider_.get(),
host_backend_delegate_.get(),
host_verifier_.get(),
device_sync_client)),
setup_flow_completion_recorder_( setup_flow_completion_recorder_(
SetupFlowCompletionRecorderImpl::Factory::Get()->BuildInstance( SetupFlowCompletionRecorderImpl::Factory::Get()->BuildInstance(
pref_service, pref_service,
......
...@@ -26,6 +26,7 @@ namespace multidevice_setup { ...@@ -26,6 +26,7 @@ namespace multidevice_setup {
class AccountStatusChangeDelegateNotifier; class AccountStatusChangeDelegateNotifier;
class HostBackendDelegate; class HostBackendDelegate;
class HostStatusProvider;
class HostVerifier; class HostVerifier;
class EligibleHostDevicesProvider; class EligibleHostDevicesProvider;
class SetupFlowCompletionRecorder; class SetupFlowCompletionRecorder;
...@@ -65,6 +66,7 @@ class MultiDeviceSetupImpl : public mojom::MultiDeviceSetup { ...@@ -65,6 +66,7 @@ class MultiDeviceSetupImpl : public mojom::MultiDeviceSetup {
std::unique_ptr<EligibleHostDevicesProvider> eligible_host_devices_provider_; std::unique_ptr<EligibleHostDevicesProvider> eligible_host_devices_provider_;
std::unique_ptr<HostBackendDelegate> host_backend_delegate_; std::unique_ptr<HostBackendDelegate> host_backend_delegate_;
std::unique_ptr<HostVerifier> host_verifier_; std::unique_ptr<HostVerifier> host_verifier_;
std::unique_ptr<HostStatusProvider> host_status_provider_;
std::unique_ptr<SetupFlowCompletionRecorder> setup_flow_completion_recorder_; std::unique_ptr<SetupFlowCompletionRecorder> setup_flow_completion_recorder_;
std::unique_ptr<AccountStatusChangeDelegateNotifier> delegate_notifier_; std::unique_ptr<AccountStatusChangeDelegateNotifier> delegate_notifier_;
......
...@@ -13,9 +13,11 @@ ...@@ -13,9 +13,11 @@
#include "chromeos/services/multidevice_setup/fake_account_status_change_delegate_notifier.h" #include "chromeos/services/multidevice_setup/fake_account_status_change_delegate_notifier.h"
#include "chromeos/services/multidevice_setup/fake_eligible_host_devices_provider.h" #include "chromeos/services/multidevice_setup/fake_eligible_host_devices_provider.h"
#include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h" #include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h"
#include "chromeos/services/multidevice_setup/fake_host_status_provider.h"
#include "chromeos/services/multidevice_setup/fake_host_verifier.h" #include "chromeos/services/multidevice_setup/fake_host_verifier.h"
#include "chromeos/services/multidevice_setup/fake_setup_flow_completion_recorder.h" #include "chromeos/services/multidevice_setup/fake_setup_flow_completion_recorder.h"
#include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h" #include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h"
#include "chromeos/services/multidevice_setup/host_status_provider_impl.h"
#include "chromeos/services/multidevice_setup/host_verifier_impl.h" #include "chromeos/services/multidevice_setup/host_verifier_impl.h"
#include "chromeos/services/multidevice_setup/multidevice_setup_impl.h" #include "chromeos/services/multidevice_setup/multidevice_setup_impl.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
...@@ -145,6 +147,55 @@ class FakeHostVerifierFactory : public HostVerifierImpl::Factory { ...@@ -145,6 +147,55 @@ class FakeHostVerifierFactory : public HostVerifierImpl::Factory {
DISALLOW_COPY_AND_ASSIGN(FakeHostVerifierFactory); DISALLOW_COPY_AND_ASSIGN(FakeHostVerifierFactory);
}; };
class FakeHostStatusProviderFactory : public HostStatusProviderImpl::Factory {
public:
FakeHostStatusProviderFactory(
FakeEligibleHostDevicesProviderFactory*
fake_eligible_host_devices_provider_factory,
FakeHostBackendDelegateFactory* fake_host_backend_delegate_factory,
FakeHostVerifierFactory* fake_host_verifier_factory,
device_sync::FakeDeviceSyncClient* expected_device_sync_client)
: fake_eligible_host_devices_provider_factory_(
fake_eligible_host_devices_provider_factory),
fake_host_backend_delegate_factory_(fake_host_backend_delegate_factory),
fake_host_verifier_factory_(fake_host_verifier_factory),
expected_device_sync_client_(expected_device_sync_client) {}
~FakeHostStatusProviderFactory() override = default;
FakeHostStatusProvider* instance() { return instance_; }
private:
// HostStatusProviderImpl::Factory:
std::unique_ptr<HostStatusProvider> BuildInstance(
EligibleHostDevicesProvider* eligible_host_devices_provider,
HostBackendDelegate* host_backend_delegate,
HostVerifier* host_verifier,
device_sync::DeviceSyncClient* device_sync_client) override {
EXPECT_FALSE(instance_);
EXPECT_EQ(fake_eligible_host_devices_provider_factory_->instance(),
eligible_host_devices_provider);
EXPECT_EQ(fake_host_backend_delegate_factory_->instance(),
host_backend_delegate);
EXPECT_EQ(fake_host_verifier_factory_->instance(), host_verifier);
EXPECT_EQ(expected_device_sync_client_, device_sync_client);
auto instance = std::make_unique<FakeHostStatusProvider>();
instance_ = instance.get();
return instance;
}
FakeEligibleHostDevicesProviderFactory*
fake_eligible_host_devices_provider_factory_;
FakeHostBackendDelegateFactory* fake_host_backend_delegate_factory_;
FakeHostVerifierFactory* fake_host_verifier_factory_;
device_sync::FakeDeviceSyncClient* expected_device_sync_client_;
FakeHostStatusProvider* instance_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FakeHostStatusProviderFactory);
};
class FakeSetupFlowCompletionRecorderFactory class FakeSetupFlowCompletionRecorderFactory
: public SetupFlowCompletionRecorderImpl::Factory { : public SetupFlowCompletionRecorderImpl::Factory {
public: public:
...@@ -257,6 +308,14 @@ class MultiDeviceSetupImplTest : public testing::Test { ...@@ -257,6 +308,14 @@ class MultiDeviceSetupImplTest : public testing::Test {
HostVerifierImpl::Factory::SetFactoryForTesting( HostVerifierImpl::Factory::SetFactoryForTesting(
fake_host_verifier_factory_.get()); fake_host_verifier_factory_.get());
fake_host_status_provider_factory_ =
std::make_unique<FakeHostStatusProviderFactory>(
fake_eligible_host_devices_provider_factory_.get(),
fake_host_backend_delegate_factory_.get(),
fake_host_verifier_factory_.get(), fake_device_sync_client_.get());
HostStatusProviderImpl::Factory::SetFactoryForTesting(
fake_host_status_provider_factory_.get());
fake_setup_flow_completion_recorder_factory_ = fake_setup_flow_completion_recorder_factory_ =
std::make_unique<FakeSetupFlowCompletionRecorderFactory>( std::make_unique<FakeSetupFlowCompletionRecorderFactory>(
test_pref_service_.get()); test_pref_service_.get());
...@@ -279,6 +338,7 @@ class MultiDeviceSetupImplTest : public testing::Test { ...@@ -279,6 +338,7 @@ class MultiDeviceSetupImplTest : public testing::Test {
EligibleHostDevicesProviderImpl::Factory::SetFactoryForTesting(nullptr); EligibleHostDevicesProviderImpl::Factory::SetFactoryForTesting(nullptr);
HostBackendDelegateImpl::Factory::SetFactoryForTesting(nullptr); HostBackendDelegateImpl::Factory::SetFactoryForTesting(nullptr);
HostVerifierImpl::Factory::SetFactoryForTesting(nullptr); HostVerifierImpl::Factory::SetFactoryForTesting(nullptr);
HostStatusProviderImpl::Factory::SetFactoryForTesting(nullptr);
SetupFlowCompletionRecorderImpl::Factory::SetFactoryForTesting(nullptr); SetupFlowCompletionRecorderImpl::Factory::SetFactoryForTesting(nullptr);
AccountStatusChangeDelegateNotifierImpl::Factory::SetFactoryForTesting( AccountStatusChangeDelegateNotifierImpl::Factory::SetFactoryForTesting(
nullptr); nullptr);
...@@ -343,6 +403,8 @@ class MultiDeviceSetupImplTest : public testing::Test { ...@@ -343,6 +403,8 @@ class MultiDeviceSetupImplTest : public testing::Test {
std::unique_ptr<FakeHostBackendDelegateFactory> std::unique_ptr<FakeHostBackendDelegateFactory>
fake_host_backend_delegate_factory_; fake_host_backend_delegate_factory_;
std::unique_ptr<FakeHostVerifierFactory> fake_host_verifier_factory_; std::unique_ptr<FakeHostVerifierFactory> fake_host_verifier_factory_;
std::unique_ptr<FakeHostStatusProviderFactory>
fake_host_status_provider_factory_;
std::unique_ptr<FakeSetupFlowCompletionRecorderFactory> std::unique_ptr<FakeSetupFlowCompletionRecorderFactory>
fake_setup_flow_completion_recorder_factory_; fake_setup_flow_completion_recorder_factory_;
std::unique_ptr<FakeAccountStatusChangeDelegateNotifierFactory> std::unique_ptr<FakeAccountStatusChangeDelegateNotifierFactory>
......
...@@ -4,6 +4,42 @@ ...@@ -4,6 +4,42 @@
module chromeos.multidevice_setup.mojom; module chromeos.multidevice_setup.mojom;
// Enumeration of event types which can be dispatched. Only used for debugging
// purposes.
enum EventTypeForDebugging {
kNewUserPotentialHostExists,
kExistingUserConnectedHostSwitched,
kExistingUserNewChromebookAdded,
};
enum HostStatus {
// The user's account has no devices which can serve as a host for
// multi-device features.
kNoEligibleHosts,
// The user's account has one or more devices which can be used as a host for
// multi-device features, but the user has not yet completed the setup flow
// for any one of these devices.
kEligibleHostExistsButNoHostSet,
// The user has completed the setup flow for multi-device features on this
// device, but there was an error contacting the back-end (e.g., the device
// was offline during the setup flow, or the back-end rejected the request for
// some reason). The local device will continue trying to contact the back-end
// to confirm that the host is set.
kHostSetLocallyButWaitingForBackendConfirmation,
// The host has been set (both locally and on the back-end), but verification
// has not yet completed. The local device will continue trying to establish
// a Bluetooth connection to the host until verification succeeds.
kHostSetButNotYetVerified,
// The host has been set (both locally and on the back-end), and the
// verification step over Bluetooth has completed. Features should be
// available for use.
kHostVerified
};
interface AccountStatusChangeDelegate { interface AccountStatusChangeDelegate {
// Callback which indicates that one or more MultiDevice host phones are // Callback which indicates that one or more MultiDevice host phones are
// available for setup with the MultiDevice setup flow. This function is only // available for setup with the MultiDevice setup flow. This function is only
...@@ -22,14 +58,6 @@ interface AccountStatusChangeDelegate { ...@@ -22,14 +58,6 @@ interface AccountStatusChangeDelegate {
OnNewChromebookAddedForExistingUser(); OnNewChromebookAddedForExistingUser();
}; };
// Enumeration of event types which can be dispatched. Only used for debugging
// purposes.
enum EventTypeForDebugging {
kNewUserPotentialHostExists,
kExistingUserConnectedHostSwitched,
kExistingUserNewChromebookAdded,
};
// Provides an API to the MultiDevice Setup flow. Designed to be exposed // Provides an API to the MultiDevice Setup flow. Designed to be exposed
// primarily to the MultiDevice setup flow at chrome://multidevice-setup (normal // primarily to the MultiDevice setup flow at chrome://multidevice-setup (normal
// usage) as well as the ProximityAuth debug WebUI page at // usage) as well as the ProximityAuth debug WebUI page at
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment