#include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h"
#include <memory>
#include <optional>
#include <utility>
#include "ash/public/cpp/update_types.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/mock_callback.h"
#include "base/test/power_monitor_test.h"
#include "base/test/task_environment.h"
#include "base/time/clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/shell.h"
#include "ash/test/ash_test_helper.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ui/ash/system/system_tray_client_impl.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "ui/display/manager/display_configurator.h"
#include "ui/display/manager/test/action_logger.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
#else
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#endif
_;
Eq;
ResultOf;
Return;
namespace {
class ControllerDelegate { … };
class FakeRelaunchNotificationController
: public RelaunchNotificationController { … };
class MockControllerDelegate : public ControllerDelegate { … };
class FakeUpgradeDetector : public UpgradeDetector { … };
}
class RelaunchNotificationControllerTest : public ::testing::Test { … };
TEST_F(RelaunchNotificationControllerTest, CreateDestroy) { … }
#if defined(THREAD_SANATIZER)
#define MAYBE_PolicyUnset …
#else
#define MAYBE_PolicyUnset …
#endif
TEST_F(RelaunchNotificationControllerTest, MAYBE_PolicyUnset) { … }
TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) { … }
TEST_F(RelaunchNotificationControllerTest, RequiredByPolicy) { … }
TEST_F(RelaunchNotificationControllerTest, PolicyChangesNoUpgrade) { … }
TEST_F(RelaunchNotificationControllerTest, PolicyChangesWithUpgrade) { … }
TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReached) { … }
TEST_F(RelaunchNotificationControllerTest, RequiredDeadlineReachedNoPolicy) { … }
TEST_F(RelaunchNotificationControllerTest, NonePeriodChange) { … }
TEST_F(RelaunchNotificationControllerTest, VeryLowPeriodChange) { … }
TEST_F(RelaunchNotificationControllerTest, PeriodChangeRecommended) { … }
TEST_F(RelaunchNotificationControllerTest, PeriodChangeRequired) { … }
TEST_F(RelaunchNotificationControllerTest, DeadlineShortenGracePeriod) { … }
TEST_F(RelaunchNotificationControllerTest, DeviceSleepBeforeNotification) { … }
TEST_F(RelaunchNotificationControllerTest, DeferredRequired) { … }
TEST_F(RelaunchNotificationControllerTest, OverriddenToRequired) { … }
TEST_F(RelaunchNotificationControllerTest, NotifyAllWithShortestPeriod) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
class RelaunchNotificationControllerPlatformImplTest : public ::testing::Test {
protected:
RelaunchNotificationControllerPlatformImplTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~RelaunchNotificationControllerPlatformImplTest() override = default;
void SetUp() override {
ash::AshTestHelper::InitParams init_params;
init_params.start_session = false;
ash_test_helper_.SetUp(std::move(init_params));
user_manager_ = new ash::FakeChromeUserManager();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(user_manager_.get()));
const char test_user_email[] = "[email protected]";
const AccountId test_account_id(AccountId::FromUserEmail(test_user_email));
user_manager_->AddUser(test_account_id);
user_manager_->LoginUser(test_account_id);
session_manager::SessionManager::Get()->CreateSession(
test_account_id, test_user_email, false);
session_manager::SessionManager::Get()->SetSessionState(
session_manager::SessionState::ACTIVE);
logger_ = std::make_unique<display::test::ActionLogger>();
native_display_delegate_ =
new display::test::TestNativeDisplayDelegate(logger_.get());
ash::Shell::Get()->display_configurator()->SetDelegateForTesting(
std::unique_ptr<display::NativeDisplayDelegate>(
native_display_delegate_));
}
void LockScreen() {
session_manager::SessionManager::Get()->SetSessionState(
session_manager::SessionState::LOCKED);
}
void UnLockScreen() {
session_manager::SessionManager::Get()->SetSessionState(
session_manager::SessionState::ACTIVE);
}
void TurnDisplayOff() {
ash::Shell::Get()->display_configurator()->SetDisplayPower(
chromeos::DISPLAY_POWER_ALL_OFF, 0, base::DoNothing());
}
void TurnDisplayOn() {
ash::Shell::Get()->display_configurator()->SetDisplayPower(
chromeos::DISPLAY_POWER_ALL_ON, 0, base::DoNothing());
}
RelaunchNotificationControllerPlatformImpl& platform_impl() { return impl_; }
const base::Clock* GetMockClock() { return task_environment_.GetMockClock(); }
private:
content::BrowserTaskEnvironment task_environment_;
RelaunchNotificationControllerPlatformImpl impl_;
ash::AshTestHelper ash_test_helper_;
raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged> user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<display::test::ActionLogger> logger_;
raw_ptr<display::NativeDisplayDelegate> native_display_delegate_;
};
TEST_F(RelaunchNotificationControllerPlatformImplTest,
SynchronousNotification) {
UnLockScreen();
TurnDisplayOn();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(RelaunchNotificationControllerPlatformImplTest,
DeferredNotificationDisplayOff) {
TurnDisplayOff();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
TurnDisplayOn();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(RelaunchNotificationControllerPlatformImplTest,
DeferredNotificationSessionLocked) {
LockScreen();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
UnLockScreen();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RequiredDeadlineReachedAfterMultipleResume) {
TurnDisplayOff();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
TurnDisplayOn();
TurnDisplayOff();
TurnDisplayOn();
TurnDisplayOff();
TurnDisplayOn();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RequiredDeadlineReachedBeforeMultipleUnlock) {
LockScreen();
::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_CALL(callback, Run());
UnLockScreen();
LockScreen();
UnLockScreen();
LockScreen();
UnLockScreen();
::testing::Mock::VerifyAndClearExpectations(&callback);
}
class MockSystemTrayClientImpl : public SystemTrayClientImpl {
public:
MockSystemTrayClientImpl() : SystemTrayClientImpl(this) {}
MOCK_METHOD(void,
SetRelaunchNotificationState,
(const ash::RelaunchNotificationState&),
(override));
};
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RelaunchNotificationStateRequired) {
base::MockOnceCallback<base::Time()> callback;
MockSystemTrayClientImpl system_tray_client_impl;
ash::RelaunchNotificationState relaunch_notification_state;
EXPECT_CALL(system_tray_client_impl, SetRelaunchNotificationState(_))
.WillOnce(testing::SaveArg<0>(&relaunch_notification_state));
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), false,
callback.Get());
EXPECT_EQ(relaunch_notification_state.requirement_type,
ash::RelaunchNotificationState::kRequired);
EXPECT_EQ(relaunch_notification_state.policy_source,
ash::RelaunchNotificationState::kUser);
EXPECT_LE(relaunch_notification_state.rounded_time_until_reboot_required,
base::Seconds(1));
}
TEST_F(RelaunchNotificationControllerPlatformImplTest,
RelaunchNotificationStateRequiredWithOverride) {
base::MockOnceCallback<base::Time()> callback;
MockSystemTrayClientImpl system_tray_client_impl;
ash::RelaunchNotificationState relaunch_notification_state;
EXPECT_CALL(system_tray_client_impl, SetRelaunchNotificationState(_))
.WillOnce(testing::SaveArg<0>(&relaunch_notification_state));
platform_impl().NotifyRelaunchRequired(
GetMockClock()->Now(), true,
callback.Get());
EXPECT_EQ(relaunch_notification_state.requirement_type,
ash::RelaunchNotificationState::kRequired);
EXPECT_EQ(relaunch_notification_state.policy_source,
ash::RelaunchNotificationState::kDevice);
EXPECT_LE(relaunch_notification_state.rounded_time_until_reboot_required,
base::Seconds(1));
}
#else
class RelaunchNotificationControllerPlatformImplTest
: public TestWithBrowserView { … };
TEST_F(RelaunchNotificationControllerPlatformImplTest,
DISABLED_SynchronousNotification) { … }
#if BUILDFLAG(IS_MAC)
#define MAYBE_DeferredDeadline …
#else
#define MAYBE_DeferredDeadline …
#endif
TEST_F(RelaunchNotificationControllerPlatformImplTest, MAYBE_DeferredDeadline) { … }
#endif