// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/policy/handlers/adb_sideloading_allowance_mode_policy_handler.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/timer/mock_timer.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/notifications/mock_adb_sideloading_policy_change_notification.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/prefs/browser_prefs.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 "chromeos/dbus/power/fake_power_manager_client.h"
#include "components/account_id/account_id.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr char kFakeUserName[] = "[email protected]";
constexpr char kFakeGaiaId[] = "1234567890";
} // namespace
namespace policy {
class AdbSideloadingAllowanceModePolicyHandlerTest : public testing::Test {
public:
using NotificationType = ash::AdbSideloadingPolicyChangeNotification::Type;
AdbSideloadingAllowanceModePolicyHandlerTest()
: local_state_(TestingBrowserProcess::GetGlobal()),
user_manager_(new ash::FakeChromeUserManager()),
user_manager_enabler_(base::WrapUnique(user_manager_.get())),
mock_notification_(
new ash::MockAdbSideloadingPolicyChangeNotification()) {
chromeos::PowerManagerClient::InitializeFake();
adb_sideloading_allowance_mode_policy_handler_ =
std::make_unique<AdbSideloadingAllowanceModePolicyHandler>(
ash::CrosSettings::Get(), local_state_.Get(),
chromeos::PowerManagerClient::Get(), mock_notification_);
adb_sideloading_allowance_mode_policy_handler_
->SetCheckSideloadingStatusCallbackForTesting(
base::BindRepeating(&AdbSideloadingAllowanceModePolicyHandlerTest::
CheckSideloadingStatus,
weak_factory_.GetWeakPtr()));
}
~AdbSideloadingAllowanceModePolicyHandlerTest() override {
adb_sideloading_allowance_mode_policy_handler_.reset();
chromeos::PowerManagerClient::Shutdown();
}
void CheckSideloadingStatus(base::OnceCallback<void(bool)> callback) {
std::move(callback).Run(is_arc_sideloading_enabled_);
}
protected:
void EnableSideloading() { is_arc_sideloading_enabled_ = true; }
void DisableSideloading() { is_arc_sideloading_enabled_ = false; }
void SetDevicePolicy(int policy) {
scoped_testing_cros_settings_.device_settings()->SetInteger(
ash::kDeviceCrostiniArcAdbSideloadingAllowed, policy);
base::RunLoop().RunUntilIdle();
}
void SetDevicePolicyToAllow() {
SetDevicePolicy(
enterprise_management::DeviceCrostiniArcAdbSideloadingAllowedProto::
ALLOW_FOR_AFFILIATED_USERS);
}
void SetDevicePolicyToDisallow() {
SetDevicePolicy(enterprise_management::
DeviceCrostiniArcAdbSideloadingAllowedProto::DISALLOW);
}
void SetDevicePolicyToDisallowWithPowerwash() {
SetDevicePolicy(
enterprise_management::DeviceCrostiniArcAdbSideloadingAllowedProto::
DISALLOW_WITH_POWERWASH);
}
void CreateUser() {
const AccountId account_id(
AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId));
user_manager_->AddUser(account_id);
user_manager_->LoginUser(account_id);
}
void FakePlannedNotificationTime() {
// Fake that the first notification had been displayed more than 24 hours
// ago.
base::Time yesterday = base::Time::Now() - base::Hours(25);
local_state_.Get()->SetInt64(
prefs::kAdbSideloadingPowerwashPlannedNotificationShownTime,
yesterday.ToDeltaSinceWindowsEpoch().InSeconds());
}
bool is_arc_sideloading_enabled_ = false;
content::BrowserTaskEnvironment task_environment_;
ScopedTestingLocalState local_state_;
raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged> user_manager_;
user_manager::ScopedUserManager user_manager_enabler_;
ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
raw_ptr<ash::MockAdbSideloadingPolicyChangeNotification, DanglingUntriaged>
mock_notification_;
std::unique_ptr<AdbSideloadingAllowanceModePolicyHandler>
adb_sideloading_allowance_mode_policy_handler_;
base::WeakPtrFactory<AdbSideloadingAllowanceModePolicyHandlerTest>
weak_factory_{this};
};
// Verify that when the device policy is set to DISALLOW, but
// arc_sideloading_allowed is false that no notification is displayed
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowNotificationDisabled) {
CreateUser();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
DisableSideloading();
SetDevicePolicyToDisallow();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
}
// Verify that when the device policy is set to DISALLOW, the notification is
// displayed
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowNotificationEnabled) {
CreateUser();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
EnableSideloading();
SetDevicePolicyToDisallow();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kSideloadingDisallowed);
}
// Verify that when the device policy is set to DISALLOW_WITH_POWERWASH, but
// arc_sideloading_allowed is false that no notification is displayed
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowWithPowerwashNotificationDisabled) {
CreateUser();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
DisableSideloading();
SetDevicePolicyToDisallowWithPowerwash();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
}
// Verify that when the device policy is set to DISALLOW_WITH_POWERWASH, the
// first notification is displayed
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowWithPowerwashNotificationEnabled) {
CreateUser();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kNone);
EnableSideloading();
SetDevicePolicyToDisallowWithPowerwash();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kPowerwashPlanned);
}
// Verify that the second powerwash notification is displayed when the time runs
// out
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowWithPowerwashNotificationTimeRunsOut) {
CreateUser();
EnableSideloading();
FakePlannedNotificationTime();
SetDevicePolicyToDisallowWithPowerwash();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kPowerwashOnNextReboot);
}
// Verify that the second powerwash notification is displayed when the timer is
// triggered
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest,
ShowDisallowWithPowerwashNotificationTimerTrigger) {
auto mock_timer = std::make_unique<base::MockOneShotTimer>();
auto* mock_timer_ptr = mock_timer.get();
adb_sideloading_allowance_mode_policy_handler_
->SetNotificationTimerForTesting(std::move(mock_timer));
CreateUser();
EnableSideloading();
SetDevicePolicyToDisallowWithPowerwash();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kPowerwashPlanned);
mock_timer_ptr->Fire();
EXPECT_EQ(mock_notification_->last_shown_notification,
NotificationType::kPowerwashOnNextReboot);
}
// Verify that the preferences are reset correctly
TEST_F(AdbSideloadingAllowanceModePolicyHandlerTest, Preferences) {
auto mock_timer = std::make_unique<base::MockOneShotTimer>();
auto* mock_timer_ptr = mock_timer.get();
adb_sideloading_allowance_mode_policy_handler_
->SetNotificationTimerForTesting(std::move(mock_timer));
// First all the preferences should have their default values
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingDisallowedNotificationShown));
EXPECT_EQ(local_state_.Get()->GetTime(
prefs::kAdbSideloadingPowerwashPlannedNotificationShownTime),
base::Time::Min());
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingPowerwashOnNextRebootNotificationShown));
EnableSideloading();
SetDevicePolicyToDisallow();
base::RunLoop().RunUntilIdle();
// Check that the preference for this notification is set
EXPECT_TRUE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingDisallowedNotificationShown));
SetDevicePolicyToDisallowWithPowerwash();
base::RunLoop().RunUntilIdle();
// Check that the other notification's preference is reset
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingDisallowedNotificationShown));
// Check that the preferences for this notification are set
EXPECT_NE(local_state_.Get()->GetTime(
prefs::kAdbSideloadingPowerwashPlannedNotificationShownTime),
base::Time::Min());
mock_timer_ptr->Fire();
EXPECT_TRUE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingPowerwashOnNextRebootNotificationShown));
SetDevicePolicyToDisallow();
base::RunLoop().RunUntilIdle();
// Check that the preference for this notification is set
EXPECT_TRUE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingDisallowedNotificationShown));
// Check that the other notification's preferences are reset
EXPECT_EQ(local_state_.Get()->GetTime(
prefs::kAdbSideloadingPowerwashPlannedNotificationShownTime),
base::Time::Min());
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingPowerwashOnNextRebootNotificationShown));
SetDevicePolicyToAllow();
base::RunLoop().RunUntilIdle();
// Check that all the preferences are reset again
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingDisallowedNotificationShown));
EXPECT_EQ(local_state_.Get()->GetTime(
prefs::kAdbSideloadingPowerwashPlannedNotificationShownTime),
base::Time::Min());
EXPECT_FALSE(local_state_.Get()->GetBoolean(
prefs::kAdbSideloadingPowerwashOnNextRebootNotificationShown));
}
} // namespace policy