Commit 391932af authored by Polina Bondarenko's avatar Polina Bondarenko Committed by Chromium LUCI CQ

arc: Add SnapshotSessionController

Add SnapshotSessionController to control MGS with loaded ARC
data snapshot and ARC data snapshot update flow.
Consider MGS as failed if not 100% of required ARC apps are installed in
5 mins.

BUG=b:161221001
TEST=components_unittests
TEST=browser_tests

Change-Id: I47b5021df115b4af6aa3fba543a34daf192c2fd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2550839Reviewed-by: default avatarHidehiko Abe <hidehiko@chromium.org>
Reviewed-by: default avatarRoman Sorokin [CET] <rsorokin@chromium.org>
Reviewed-by: default avatarOleksandr Peletskyi <peletskyi@chromium.org>
Commit-Queue: Polina Bondarenko <pbond@chromium.org>
Auto-Submit: Polina Bondarenko <pbond@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835132}
parent a6497b29
...@@ -792,7 +792,7 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest, ...@@ -792,7 +792,7 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
EXPECT_TRUE(user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()); EXPECT_TRUE(user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
EnableArcForProfile(ProfileManager::GetActiveUserProfile()); EnableArcForProfile(ProfileManager::GetActiveUserProfile());
arc_data_snapshotd_manager()->OnSessionStateChanged(); arc_data_snapshotd_manager()->OnSnapshotSessionStarted();
EXPECT_TRUE(auto_login_account_id().is_valid()); EXPECT_TRUE(auto_login_account_id().is_valid());
EXPECT_EQ(0, auto_login_delay()); EXPECT_EQ(0, auto_login_delay());
......
...@@ -322,6 +322,8 @@ static_library("arc_test_support") { ...@@ -322,6 +322,8 @@ static_library("arc_test_support") {
"test/fake_accessibility_helper_instance.h", "test/fake_accessibility_helper_instance.h",
"test/fake_app_instance.cc", "test/fake_app_instance.cc",
"test/fake_app_instance.h", "test/fake_app_instance.h",
"test/fake_apps_tracker.cc",
"test/fake_apps_tracker.h",
"test/fake_arc_bridge_host.cc", "test/fake_arc_bridge_host.cc",
"test/fake_arc_bridge_host.h", "test/fake_arc_bridge_host.h",
"test/fake_arc_session.cc", "test/fake_arc_session.cc",
...@@ -361,6 +363,7 @@ static_library("arc_test_support") { ...@@ -361,6 +363,7 @@ static_library("arc_test_support") {
deps = [ deps = [
"//base", "//base",
"//components/arc/enterprise",
"//components/keyed_service/content", "//components/keyed_service/content",
"//components/prefs:test_support", "//components/prefs:test_support",
"//components/user_prefs", "//components/user_prefs",
...@@ -386,6 +389,7 @@ source_set("unit_tests") { ...@@ -386,6 +389,7 @@ source_set("unit_tests") {
"enterprise/arc_data_snapshotd_bridge_unittest.cc", "enterprise/arc_data_snapshotd_bridge_unittest.cc",
"enterprise/arc_data_snapshotd_manager_unittest.cc", "enterprise/arc_data_snapshotd_manager_unittest.cc",
"enterprise/snapshot_hours_policy_service_unittest.cc", "enterprise/snapshot_hours_policy_service_unittest.cc",
"enterprise/snapshot_session_controller_unittest.cc",
"ime/arc_ime_service_unittest.cc", "ime/arc_ime_service_unittest.cc",
"ime/key_event_result_receiver_unittest.cc", "ime/key_event_result_receiver_unittest.cc",
"intent_helper/activity_icon_loader_unittest.cc", "intent_helper/activity_icon_loader_unittest.cc",
......
...@@ -13,6 +13,8 @@ static_library("enterprise") { ...@@ -13,6 +13,8 @@ static_library("enterprise") {
"arc_data_snapshotd_manager.h", "arc_data_snapshotd_manager.h",
"snapshot_hours_policy_service.cc", "snapshot_hours_policy_service.cc",
"snapshot_hours_policy_service.h", "snapshot_hours_policy_service.h",
"snapshot_session_controller.cc",
"snapshot_session_controller.h",
] ]
deps = [ deps = [
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "components/arc/enterprise/arc_data_remove_requested_pref_handler.h" #include "components/arc/enterprise/arc_data_remove_requested_pref_handler.h"
#include "components/arc/enterprise/arc_data_snapshotd_bridge.h" #include "components/arc/enterprise/arc_data_snapshotd_bridge.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "ui/ozone/public/ozone_switches.h" #include "ui/ozone/public/ozone_switches.h"
...@@ -242,6 +241,15 @@ void ArcDataSnapshotdManager::Snapshot::OnSnapshotTaken() { ...@@ -242,6 +241,15 @@ void ArcDataSnapshotdManager::Snapshot::OnSnapshotTaken() {
started_ = false; started_ = false;
} }
ArcDataSnapshotdManager::SnapshotInfo*
ArcDataSnapshotdManager::Snapshot::GetCurrentSnapshot() {
if (last_)
return last_.get();
DCHECK(previous_);
return previous_.get();
}
ArcDataSnapshotdManager::Snapshot::Snapshot( ArcDataSnapshotdManager::Snapshot::Snapshot(
PrefService* local_state, PrefService* local_state,
bool blocked_ui_mode, bool blocked_ui_mode,
...@@ -295,7 +303,8 @@ ArcDataSnapshotdManager::~ArcDataSnapshotdManager() { ...@@ -295,7 +303,8 @@ ArcDataSnapshotdManager::~ArcDataSnapshotdManager() {
DCHECK(g_arc_data_snapshotd_manager); DCHECK(g_arc_data_snapshotd_manager);
g_arc_data_snapshotd_manager = nullptr; g_arc_data_snapshotd_manager = nullptr;
session_manager::SessionManager::Get()->RemoveObserver(this); if (session_controller_)
session_controller_->RemoveObserver(this);
snapshot_.Sync(); snapshot_.Sync();
EnsureDaemonStopped(base::DoNothing()); EnsureDaemonStopped(base::DoNothing());
...@@ -364,42 +373,56 @@ bool ArcDataSnapshotdManager::IsAutoLoginAllowed() { ...@@ -364,42 +373,56 @@ bool ArcDataSnapshotdManager::IsAutoLoginAllowed() {
} }
} }
void ArcDataSnapshotdManager::OnSessionStateChanged() { void ArcDataSnapshotdManager::OnSnapshotSessionStarted() {
if (state_ != State::kMgsToLaunch)
return;
state_ = State::kMgsLaunched;
}
void ArcDataSnapshotdManager::OnSnapshotSessionStopped() {
if (state_ != State::kRunning)
NOTREACHED();
state_ = State::kNone;
snapshot_.GetCurrentSnapshot()->set_verified(true);
snapshot_.Sync();
session_controller_->RemoveObserver(this);
session_controller_.reset();
}
void ArcDataSnapshotdManager::OnSnapshotSessionFailed() {
session_controller_->RemoveObserver(this);
session_controller_.reset();
switch (state_) { switch (state_) {
case State::kMgsLaunched: case State::kMgsLaunched:
if (user_manager::UserManager::Get() &&
user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
return;
}
LOG(ERROR) << "MGS has failed.";
state_ = State::kNone; state_ = State::kNone;
apps_tracker_->StopTracking();
OnSnapshotTaken(false /* success */); OnSnapshotTaken(false /* success */);
break; break;
case State::kMgsToLaunch:
if (user_manager::UserManager::Get() &&
user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
state_ = State::kMgsLaunched;
apps_tracker_->StartTracking(base::BindRepeating(
&ArcDataSnapshotdManager::Update, weak_ptr_factory_.GetWeakPtr()));
return;
}
break;
case State::kRunning: case State::kRunning:
if (user_manager::UserManager::Get() &&
user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
return;
}
// It is a correct state. Exit MGS withg loaded snapshot.
state_ = State::kNone; state_ = State::kNone;
return;
snapshot_.ClearSnapshot(snapshot_.GetCurrentSnapshot()->is_last());
snapshot_.Sync();
DCHECK(!attempt_user_exit_callback_.is_null());
EnsureDaemonStopped(std::move(attempt_user_exit_callback_));
break;
case State::kBlockedUi: case State::kBlockedUi:
case State::kNone: case State::kNone:
case State::kRestored: case State::kRestored:
break; case State::kMgsToLaunch:
NOTREACHED();
} }
} }
void ArcDataSnapshotdManager::OnSnapshotAppInstalled(int percent) {
if (state_ != State::kMgsLaunched)
return;
Update(percent);
}
void ArcDataSnapshotdManager::StopDaemon(base::OnceClosure callback) { void ArcDataSnapshotdManager::StopDaemon(base::OnceClosure callback) {
VLOG(1) << "Stopping arc-data-snapshotd"; VLOG(1) << "Stopping arc-data-snapshotd";
daemon_weak_ptr_factory_.InvalidateWeakPtrs(); daemon_weak_ptr_factory_.InvalidateWeakPtrs();
...@@ -511,9 +534,13 @@ void ArcDataSnapshotdManager::OnKeyPairGenerated(bool success) { ...@@ -511,9 +534,13 @@ void ArcDataSnapshotdManager::OnKeyPairGenerated(bool success) {
if (success) { if (success) {
VLOG(1) << "Managed Guest Session is ready to be started with blocked UI."; VLOG(1) << "Managed Guest Session is ready to be started with blocked UI.";
state_ = State::kMgsToLaunch; state_ = State::kMgsToLaunch;
session_manager::SessionManager::Get()->AddObserver(this); session_controller_ =
SnapshotSessionController::Create(apps_tracker_.get());
session_controller_->AddObserver(this);
// Move last to previous snapshot: // Move last to previous snapshot:
snapshot_.StartNewSnapshot(); snapshot_.StartNewSnapshot();
snapshot_.Sync();
if (!reset_autologin_callback_.is_null()) if (!reset_autologin_callback_.is_null())
std::move(reset_autologin_callback_).Run(); std::move(reset_autologin_callback_).Run();
...@@ -572,7 +599,9 @@ void ArcDataSnapshotdManager::Update(int percent) { ...@@ -572,7 +599,9 @@ void ArcDataSnapshotdManager::Update(int percent) {
// If the policy changes or an app gets uninstalled, the compliance with the // If the policy changes or an app gets uninstalled, the compliance with the
// required apps list will be fixed automatically on the next session // required apps list will be fixed automatically on the next session
// startup. // startup.
apps_tracker_->StopTracking(); session_controller_->RemoveObserver(this);
session_controller_.reset();
delegate_->RequestStopArcInstance( delegate_->RequestStopArcInstance(
base::BindOnce(&ArcDataSnapshotdManager::OnArcInstanceStopped, base::BindOnce(&ArcDataSnapshotdManager::OnArcInstanceStopped,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
...@@ -635,9 +664,15 @@ void ArcDataSnapshotdManager::OnSnapshotLoaded(base::OnceClosure callback, ...@@ -635,9 +664,15 @@ void ArcDataSnapshotdManager::OnSnapshotLoaded(base::OnceClosure callback,
<< " snapshot"; << " snapshot";
state_ = State::kRunning; state_ = State::kRunning;
// Clear last snapshot if the previous one was loaded. // Clear last snapshot if the previous one was loaded.
if (!last && snapshot_.last()) if (!last && snapshot_.last()) {
snapshot_.ClearSnapshot(true /* last */); snapshot_.ClearSnapshot(true /* last */);
snapshot_.Sync();
}
EnsureDaemonStopped(base::DoNothing()); EnsureDaemonStopped(base::DoNothing());
session_controller_ = SnapshotSessionController::Create(apps_tracker_.get());
session_controller_->AddObserver(this);
std::move(callback).Run(); std::move(callback).Run();
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "components/arc/enterprise/arc_apps_tracker.h" #include "components/arc/enterprise/arc_apps_tracker.h"
#include "components/arc/enterprise/snapshot_session_controller.h"
#include "components/session_manager/core/session_manager_observer.h" #include "components/session_manager/core/session_manager_observer.h"
class PrefService; class PrefService;
...@@ -30,7 +31,7 @@ class ArcDataSnapshotdBridge; ...@@ -30,7 +31,7 @@ class ArcDataSnapshotdBridge;
// This class manages ARC data/ directory snapshots and controls the lifetime of // This class manages ARC data/ directory snapshots and controls the lifetime of
// the arc-data-snapshotd daemon. // the arc-data-snapshotd daemon.
class ArcDataSnapshotdManager final class ArcDataSnapshotdManager final
: public session_manager::SessionManagerObserver { : public SnapshotSessionController::Observer {
public: public:
// State of the flow. // State of the flow.
enum class State { enum class State {
...@@ -94,6 +95,9 @@ class ArcDataSnapshotdManager final ...@@ -94,6 +95,9 @@ class ArcDataSnapshotdManager final
// Returns true if OS version is updated, since the snapshot has been taken. // Returns true if OS version is updated, since the snapshot has been taken.
bool IsOsVersionUpdated() const; bool IsOsVersionUpdated() const;
void set_verified(bool verified) { verified_ = true; }
bool is_verified() const { return verified_; }
bool is_last() const { return is_last_; } bool is_last() const { return is_last_; }
private: private:
...@@ -153,6 +157,9 @@ class ArcDataSnapshotdManager final ...@@ -153,6 +157,9 @@ class ArcDataSnapshotdManager final
// Updates the last snapshot creation date and OS version. // Updates the last snapshot creation date and OS version.
void OnSnapshotTaken(); void OnSnapshotTaken();
// Returns the info of a snapshot in use.
SnapshotInfo* GetCurrentSnapshot();
void set_blocked_ui_mode(bool blocked_ui_mode) { void set_blocked_ui_mode(bool blocked_ui_mode) {
blocked_ui_mode_ = blocked_ui_mode; blocked_ui_mode_ = blocked_ui_mode;
} }
...@@ -204,8 +211,18 @@ class ArcDataSnapshotdManager final ...@@ -204,8 +211,18 @@ class ArcDataSnapshotdManager final
// waiting for the response from arc-data-snapshotd daemon. // waiting for the response from arc-data-snapshotd daemon.
bool IsAutoLoginAllowed(); bool IsAutoLoginAllowed();
// session_manager::SessionManagerObserver: // SnapshotSessionController::Observer overrides:
void OnSessionStateChanged() override; void OnSnapshotSessionStarted() override;
void OnSnapshotSessionStopped() override;
void OnSnapshotSessionFailed() override;
void OnSnapshotAppInstalled(int percent) override;
static void set_snapshot_enabled_for_testing(bool enabled) {
is_snapshot_enabled_for_testing_ = enabled;
}
static bool is_snapshot_enabled_for_testing() {
return is_snapshot_enabled_for_testing_;
}
// Get |bridge_| for testing. // Get |bridge_| for testing.
ArcDataSnapshotdBridge* bridge() { return bridge_.get(); } ArcDataSnapshotdBridge* bridge() { return bridge_.get(); }
...@@ -215,14 +232,12 @@ class ArcDataSnapshotdManager final ...@@ -215,14 +232,12 @@ class ArcDataSnapshotdManager final
void set_reset_autologin_callback(base::OnceClosure callback) { void set_reset_autologin_callback(base::OnceClosure callback) {
reset_autologin_callback_ = std::move(callback); reset_autologin_callback_ = std::move(callback);
} }
void set_state_for_testing(State state) { state_ = state; }
static void set_snapshot_enabled_for_testing(bool enabled) { void set_session_controller_for_testing(
is_snapshot_enabled_for_testing_ = enabled; std::unique_ptr<SnapshotSessionController> session_controller) {
} session_controller_ = std::move(session_controller);
static bool is_snapshot_enabled_for_testing() {
return is_snapshot_enabled_for_testing_;
} }
void set_state_for_testing(State state) { state_ = state; }
private: private:
// Attempts to arc-data-snapshotd daemon regardless of state of the class. // Attempts to arc-data-snapshotd daemon regardless of state of the class.
...@@ -295,6 +310,10 @@ class ArcDataSnapshotdManager final ...@@ -295,6 +310,10 @@ class ArcDataSnapshotdManager final
// Callback to reset an autologin timer once userless MGS is ready to start. // Callback to reset an autologin timer once userless MGS is ready to start.
base::OnceClosure reset_autologin_callback_; base::OnceClosure reset_autologin_callback_;
// Initialized only when needed to observe and call back on a user session
// events.
std::unique_ptr<SnapshotSessionController> session_controller_;
// Used for cancelling previously posted tasks to daemon. // Used for cancelling previously posted tasks to daemon.
base::WeakPtrFactory<ArcDataSnapshotdManager> daemon_weak_ptr_factory_{this}; base::WeakPtrFactory<ArcDataSnapshotdManager> daemon_weak_ptr_factory_{this};
// WeakPtrFactory to use for callbacks. // WeakPtrFactory to use for callbacks.
......
// Copyright 2020 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 "components/arc/enterprise/snapshot_session_controller.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user_manager.h"
namespace arc {
namespace data_snapshotd {
namespace {
// The maximum duration of all required apps being installed.
const base::TimeDelta kDuration = base::TimeDelta::FromMinutes(5);
// This class tracks a user session lifetime and notifies its observers about
// the appropriate session state changes.
class SnapshotSessionControllerImpl final
: public SnapshotSessionController,
public session_manager::SessionManagerObserver {
public:
explicit SnapshotSessionControllerImpl(ArcAppsTracker* apps_tracker);
SnapshotSessionControllerImpl(const SnapshotSessionControllerImpl&) = delete;
SnapshotSessionControllerImpl& operator=(
const SnapshotSessionControllerImpl&) = delete;
~SnapshotSessionControllerImpl() override;
// SnapshotSessionController overrides:
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
const base::OneShotTimer* get_timer_for_testing() const override {
return &duration_timer_;
}
// session_manager::SessionManagerObserver overrides:
void OnSessionStateChanged() override;
private:
// Calls StartSession() is MGS is active.
bool MaybeStartSession();
void StartSession();
void StopSession();
// Callback to be passed to |apps_tracker_|.
void OnAppInstalled(int percent);
// Called back once the session duration exceeds the maximum duration.
void OnTimerFired();
void NotifySnapshotSessionStarted();
void NotifySnapshotSessionStopped();
void NotifySnapshotSessionFailed();
void NotifySnapshotAppInstalled(int percent);
// Owned by ArcDataSnapshotdManager.
ArcAppsTracker* apps_tracker_;
base::OneShotTimer duration_timer_;
base::ObserverList<Observer> observers_;
// True, if |apps_tracker_| notified 100% of required apps installed.
// Note: the value never flips back to false.
bool all_apps_installed_ = false;
base::WeakPtrFactory<SnapshotSessionControllerImpl> weak_ptr_factory_{this};
};
} // namespace
// static
std::unique_ptr<SnapshotSessionController> SnapshotSessionController::Create(
ArcAppsTracker* apps_tracker) {
return std::make_unique<SnapshotSessionControllerImpl>(apps_tracker);
}
const base::OneShotTimer* SnapshotSessionController::get_timer_for_testing()
const {
return nullptr;
}
SnapshotSessionController::~SnapshotSessionController() = default;
SnapshotSessionControllerImpl::SnapshotSessionControllerImpl(
ArcAppsTracker* apps_tracker)
: apps_tracker_(apps_tracker) {
session_manager::SessionManager::Get()->AddObserver(this);
// Start tracking apps for active MGS.
ignore_result(MaybeStartSession());
}
SnapshotSessionControllerImpl::~SnapshotSessionControllerImpl() {
session_manager::SessionManager::Get()->RemoveObserver(this);
}
void SnapshotSessionControllerImpl::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void SnapshotSessionControllerImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void SnapshotSessionControllerImpl::OnSessionStateChanged() {
if (!MaybeStartSession())
StopSession();
}
bool SnapshotSessionControllerImpl::MaybeStartSession() {
if (user_manager::UserManager::Get() &&
user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
StartSession();
return true;
}
return false;
}
void SnapshotSessionControllerImpl::StartSession() {
DCHECK(!duration_timer_.IsRunning());
duration_timer_.Start(
FROM_HERE, kDuration,
base::BindOnce(&SnapshotSessionControllerImpl::OnTimerFired,
weak_ptr_factory_.GetWeakPtr()));
apps_tracker_->StartTracking(
base::BindRepeating(&SnapshotSessionControllerImpl::OnAppInstalled,
weak_ptr_factory_.GetWeakPtr()));
NotifySnapshotSessionStarted();
}
void SnapshotSessionControllerImpl::StopSession() {
if (all_apps_installed_) {
NotifySnapshotSessionStopped();
} else {
DCHECK(duration_timer_.IsRunning());
duration_timer_.Stop();
apps_tracker_->StopTracking();
NotifySnapshotSessionFailed();
}
}
void SnapshotSessionControllerImpl::OnAppInstalled(int percent) {
if (percent == 100) {
all_apps_installed_ = true;
apps_tracker_->StopTracking();
duration_timer_.Stop();
}
NotifySnapshotAppInstalled(percent);
}
void SnapshotSessionControllerImpl::OnTimerFired() {
DCHECK(!all_apps_installed_);
apps_tracker_->StopTracking();
NotifySnapshotSessionFailed();
}
void SnapshotSessionControllerImpl::NotifySnapshotSessionStarted() {
for (auto& observer : observers_)
observer.OnSnapshotSessionStarted();
}
void SnapshotSessionControllerImpl::NotifySnapshotSessionStopped() {
for (auto& observer : observers_)
observer.OnSnapshotSessionStopped();
}
void SnapshotSessionControllerImpl::NotifySnapshotSessionFailed() {
for (auto& observer : observers_)
observer.OnSnapshotSessionFailed();
}
void SnapshotSessionControllerImpl::NotifySnapshotAppInstalled(int percent) {
for (auto& observer : observers_)
observer.OnSnapshotAppInstalled(percent);
}
} // namespace data_snapshotd
} // namespace arc
// Copyright 2020 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 COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_SESSION_CONTROLLER_H_
#define COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_SESSION_CONTROLLER_H_
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "components/arc/enterprise/arc_apps_tracker.h"
#include "components/session_manager/core/session_manager_observer.h"
namespace base {
class OneShotTimer;
} // namespace base
namespace arc {
namespace data_snapshotd {
// This class observes the MGS state changes and duration.
class SnapshotSessionController {
public:
// Observer interface.
class Observer : public base::CheckedObserver {
public:
// Called once MGS is started.
virtual void OnSnapshotSessionStarted() = 0;
// Called once MGS is finished with all required apps installed.
virtual void OnSnapshotSessionStopped() = 0;
// Called once MGS is finished with not all required apps installed.
virtual void OnSnapshotSessionFailed() = 0;
// Called once any required ARC app is installed.
// |percent| is the number of percent of installed apps among the required
// ARC apps in range [0..100].
virtual void OnSnapshotAppInstalled(int percent) = 0;
};
virtual ~SnapshotSessionController();
static std::unique_ptr<SnapshotSessionController> Create(
ArcAppsTracker* apps_tracker);
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual const base::OneShotTimer* get_timer_for_testing() const;
};
} // namespace data_snapshotd
} // namespace arc
#endif // COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_SESSION_CONTROLLER_H_
// Copyright 2020 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 "components/arc/enterprise/snapshot_session_controller.h"
#include <memory>
#include <string>
#include "base/test/task_environment.h"
#include "components/arc/test/fake_apps_tracker.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace arc {
namespace data_snapshotd {
namespace {
constexpr char kPublicAccountEmail[] = "public-session-account@localhost";
class FakeObserver final : public SnapshotSessionController::Observer {
public:
FakeObserver() = default;
FakeObserver(const FakeObserver&) = delete;
FakeObserver& operator=(const FakeObserver&) = delete;
~FakeObserver() override = default;
void OnSnapshotSessionStarted() override { session_started_num_++; }
void OnSnapshotSessionStopped() override { session_stopped_num_++; }
void OnSnapshotSessionFailed() override { session_failed_num_++; }
void OnSnapshotAppInstalled(int percent) override {
apps_installed_percent_ = percent;
}
int session_started_num() const { return session_started_num_; }
int session_stopped_num() const { return session_stopped_num_; }
int session_failed_num() const { return session_failed_num_; }
int apps_installed_percent() const { return apps_installed_percent_; }
private:
int session_started_num_ = 0;
int session_stopped_num_ = 0;
int session_failed_num_ = 0;
int apps_installed_percent_ = -1;
};
} // namespace
// Tests SnapshotSessionController class instance.
class SnapshotSessionControllerTest : public testing::Test {
protected:
SnapshotSessionControllerTest() = default;
void SetUp() override {
fake_user_manager_ = new user_manager::FakeUserManager();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(fake_user_manager_));
apps_tracker_ = std::make_unique<FakeAppsTracker>();
observer_ = std::make_unique<FakeObserver>();
session_manager_.SetSessionState(session_manager::SessionState::UNKNOWN);
}
void LoginAsPublicSession() {
auto account_id = AccountId::FromUserEmail(kPublicAccountEmail);
user_manager()->AddPublicAccountUser(account_id);
user_manager()->UserLoggedIn(account_id, account_id.GetUserEmail(), false,
false);
session_manager_.SetSessionState(session_manager::SessionState::ACTIVE);
}
void LogoutPublicSession() {
auto account_id = AccountId::FromUserEmail(kPublicAccountEmail);
user_manager()->RemoveUserFromList(account_id);
session_manager_.SetSessionState(session_manager::SessionState::LOCKED);
}
user_manager::FakeUserManager* user_manager() { return fake_user_manager_; }
FakeAppsTracker* apps_tracker() { return apps_tracker_.get(); }
FakeObserver* observer() { return observer_.get(); }
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
private:
session_manager::SessionManager session_manager_;
user_manager::FakeUserManager* fake_user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<FakeAppsTracker> apps_tracker_;
std::unique_ptr<FakeObserver> observer_;
};
TEST_F(SnapshotSessionControllerTest, BasicPreLogin) {
LoginAsPublicSession();
auto session_controller = SnapshotSessionController::Create(apps_tracker());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
}
TEST_F(SnapshotSessionControllerTest, BasicNoLogin) {
auto session_controller = SnapshotSessionController::Create(apps_tracker());
EXPECT_FALSE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(0, apps_tracker()->start_tracking_num());
}
TEST_F(SnapshotSessionControllerTest, StartSession) {
auto session_controller = SnapshotSessionController::Create(apps_tracker());
session_controller->AddObserver(observer());
LoginAsPublicSession();
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
EXPECT_EQ(1, observer()->session_started_num());
session_controller->RemoveObserver(observer());
}
TEST_F(SnapshotSessionControllerTest, StopSessionFailure) {
LoginAsPublicSession();
auto session_controller = SnapshotSessionController::Create(apps_tracker());
session_controller->AddObserver(observer());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
LogoutPublicSession();
EXPECT_EQ(1, observer()->session_failed_num());
EXPECT_FALSE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->stop_tracking_num());
session_controller->RemoveObserver(observer());
}
TEST_F(SnapshotSessionControllerTest, StopSessionSuccess) {
LoginAsPublicSession();
auto session_controller = SnapshotSessionController::Create(apps_tracker());
session_controller->AddObserver(observer());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
apps_tracker()->update_callback().Run(100 /* percent */);
EXPECT_EQ(1, apps_tracker()->stop_tracking_num());
LogoutPublicSession();
EXPECT_EQ(1, observer()->session_stopped_num());
EXPECT_FALSE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->stop_tracking_num());
session_controller->RemoveObserver(observer());
}
TEST_F(SnapshotSessionControllerTest, OnAppInstalled) {
LoginAsPublicSession();
auto session_controller = SnapshotSessionController::Create(apps_tracker());
session_controller->AddObserver(observer());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
apps_tracker()->update_callback().Run(10 /* percent */);
EXPECT_EQ(0, apps_tracker()->stop_tracking_num());
EXPECT_EQ(10, observer()->apps_installed_percent());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
session_controller->RemoveObserver(observer());
}
TEST_F(SnapshotSessionControllerTest, StopSessionFailureDuration) {
LoginAsPublicSession();
auto session_controller = SnapshotSessionController::Create(apps_tracker());
session_controller->AddObserver(observer());
EXPECT_TRUE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, apps_tracker()->start_tracking_num());
task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(5));
task_environment_.RunUntilIdle();
EXPECT_EQ(1, apps_tracker()->stop_tracking_num());
EXPECT_FALSE(session_controller->get_timer_for_testing()->IsRunning());
EXPECT_EQ(1, observer()->session_failed_num());
session_controller->RemoveObserver(observer());
}
} // namespace data_snapshotd
} // namespace arc
// Copyright 2020 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 "components/arc/test/fake_apps_tracker.h"
namespace arc {
namespace data_snapshotd {
FakeAppsTracker::FakeAppsTracker() = default;
FakeAppsTracker::~FakeAppsTracker() = default;
void FakeAppsTracker::StartTracking(
base::RepeatingCallback<void(int)> update_callback) {
start_tracking_num_++;
update_callback_ = std::move(update_callback);
}
void FakeAppsTracker::StopTracking() {
stop_tracking_num_++;
update_callback_.Reset();
}
} // namespace data_snapshotd
} // namespace arc
// Copyright 2020 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 COMPONENTS_ARC_TEST_FAKE_APPS_TRACKER_H_
#define COMPONENTS_ARC_TEST_FAKE_APPS_TRACKER_H_
#include "base/callback.h"
#include "components/arc/enterprise/arc_apps_tracker.h"
namespace arc {
namespace data_snapshotd {
// Fake implementation of ArcAppsTracker for tests.
class FakeAppsTracker : public ArcAppsTracker {
public:
FakeAppsTracker();
FakeAppsTracker(const FakeAppsTracker&) = delete;
FakeAppsTracker& operator=(const FakeAppsTracker&) = delete;
~FakeAppsTracker() override;
// ArcAppsTracker overrides:
void StartTracking(
base::RepeatingCallback<void(int)> update_callback) override;
void StopTracking() override;
base::RepeatingCallback<void(int)>& update_callback() {
return update_callback_;
}
int start_tracking_num() const { return start_tracking_num_; }
int stop_tracking_num() const { return stop_tracking_num_; }
private:
int start_tracking_num_ = 0;
int stop_tracking_num_ = 0;
base::RepeatingCallback<void(int)> update_callback_;
};
} // namespace data_snapshotd
} // namespace arc
#endif // COMPONENTS_ARC_TEST_FAKE_APPS_TRACKER_H_
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