blob: 71163c98ec9d8dc357dd361ec7adb5715635a7a3 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/policy/core/common/policy_service_impl.h"
#include <memory>
#include <utility>
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/policy/core/common/external_data_fetcher.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/mock_policy_service.h"
#include "components/policy/core/common/policy_migrator.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/strings/grit/components_strings.h"
#include "extensions/buildflags/buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Return;
namespace policy {
namespace {
const char kExtension[] = "extension-id";
const char kSameLevelPolicy[] = "policy-same-level-and-scope";
const char kDiffLevelPolicy[] = "chrome-diff-level-and-scope";
const std::string kUrl1 = "example.com";
const std::string kUrl2 = "gmail.com";
const std::string kUrl3 = "google.com";
const std::string kUrl4 = "youtube.com";
const std::string kAffiliationId1 = "abc";
const std::string kAffiliationId2 = "def";
// Helper to compare the arguments to an EXPECT_CALL of OnPolicyUpdated() with
// their expected values.
MATCHER_P(PolicyEquals, expected, "") {
return arg.Equals(*expected);
}
// Helper to compare the arguments to an EXPECT_CALL of OnPolicyValueUpdated()
// with their expected values.
MATCHER_P(ValueEquals, expected, "") {
return *expected == *arg;
}
// Helper that fills |bundle| with test policies.
void AddTestPolicies(PolicyBundle* bundle,
const char* value,
PolicyLevel level,
PolicyScope scope) {
PolicyMap* policy_map =
&bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
policy_map->Set(kSameLevelPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(value),
nullptr);
policy_map->Set(kDiffLevelPolicy, level, scope, POLICY_SOURCE_CLOUD,
base::Value(value), nullptr);
policy_map =
&bundle->Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension));
policy_map->Set(kSameLevelPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(value),
nullptr);
policy_map->Set(kDiffLevelPolicy, level, scope, POLICY_SOURCE_CLOUD,
base::Value(value), nullptr);
}
// Observer class that changes the policy in the passed provider when the
// callback is invoked.
class ChangePolicyObserver : public PolicyService::Observer {
public:
explicit ChangePolicyObserver(MockConfigurationPolicyProvider* provider)
: provider_(provider),
observer_invoked_(false) {}
void OnPolicyUpdated(const PolicyNamespace&,
const PolicyMap& previous,
const PolicyMap& current) override {
PolicyMap new_policy;
new_policy.Set("foo", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(14), nullptr);
provider_->UpdateChromePolicy(new_policy);
observer_invoked_ = true;
}
bool observer_invoked() const { return observer_invoked_; }
private:
raw_ptr<MockConfigurationPolicyProvider> provider_;
bool observer_invoked_;
};
class MockPolicyMigrator : public PolicyMigrator {
public:
MOCK_METHOD1(Migrate, void(PolicyBundle* bundle));
};
} // namespace
class PolicyServiceTest : public testing::Test {
public:
PolicyServiceTest() = default;
PolicyServiceTest(const PolicyServiceTest&) = delete;
PolicyServiceTest& operator=(const PolicyServiceTest&) = delete;
void SetUp() override {
EXPECT_CALL(provider0_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider0_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
provider0_.Init();
provider1_.Init();
provider2_.Init();
policy0_.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(13), nullptr);
provider0_.UpdateChromePolicy(policy0_);
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
providers.push_back(&provider1_);
providers.push_back(&provider2_);
auto migrator = std::make_unique<MockPolicyMigrator>();
EXPECT_CALL(*migrator, Migrate(_))
.WillRepeatedly(Invoke([](PolicyBundle* bundle) {
bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
}));
PolicyServiceImpl::Migrators migrators;
migrators.push_back(std::move(migrator));
policy_service_ = std::make_unique<PolicyServiceImpl>(std::move(providers),
std::move(migrators));
}
void TearDown() override {
provider0_.Shutdown();
provider1_.Shutdown();
provider2_.Shutdown();
}
MOCK_METHOD2(OnPolicyValueUpdated, void(const base::Value*,
const base::Value*));
MOCK_METHOD0(OnPolicyRefresh, void());
// Returns true if the policies for namespace |ns| match |expected|.
bool VerifyPolicies(const PolicyNamespace& ns,
const PolicyMap& expected) {
return policy_service_->GetPolicies(ns).Equals(expected);
}
PolicyBundle CreateBundle(
PolicyScope scope,
PolicySource source,
std::vector<std::pair<std::string, base::Value>> policies,
PolicyNamespace policy_namespace) {
PolicyBundle policy_bundle;
PolicyMap& policy_map = policy_bundle.Get(policy_namespace);
for (auto& policy : policies) {
policy_map.Set(std::move(policy.first), POLICY_LEVEL_MANDATORY, scope,
source, std::move(policy.second), nullptr);
}
return policy_bundle;
}
void RunUntilIdle() {
base::RunLoop loop;
loop.RunUntilIdle();
}
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
MockConfigurationPolicyProvider provider0_;
MockConfigurationPolicyProvider provider1_;
MockConfigurationPolicyProvider provider2_;
PolicyMap policy0_;
PolicyMap policy1_;
PolicyMap policy2_;
std::unique_ptr<PolicyServiceImpl> policy_service_;
};
TEST_F(PolicyServiceTest, LoadsPoliciesBeforeProvidersRefresh) {
PolicyMap expected;
expected.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(13), nullptr);
expected.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expected));
}
TEST_F(PolicyServiceTest, NotifyObservers) {
MockPolicyServiceObserver observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
PolicyMap expectedPrevious;
expectedPrevious.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(13),
nullptr);
expectedPrevious.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap expectedCurrent;
expectedCurrent = expectedPrevious.Clone();
expectedCurrent.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
EXPECT_CALL(observer, OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_CHROME,
std::string()),
PolicyEquals(&expectedPrevious),
PolicyEquals(&expectedCurrent)));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
// No changes.
EXPECT_CALL(observer, OnPolicyUpdated(_, _, _)).Times(0);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expectedCurrent));
// New policy.
expectedPrevious = expectedCurrent.Clone();
expectedCurrent.Set("bbb", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(456), nullptr);
policy0_.Set("bbb", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(456), nullptr);
EXPECT_CALL(observer, OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_CHROME,
std::string()),
PolicyEquals(&expectedPrevious),
PolicyEquals(&expectedCurrent)));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
// Removed policy.
expectedPrevious = expectedCurrent.Clone();
expectedCurrent.Erase("bbb");
policy0_.Erase("bbb");
EXPECT_CALL(observer, OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_CHROME,
std::string()),
PolicyEquals(&expectedPrevious),
PolicyEquals(&expectedCurrent)));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
// Changed policy.
expectedPrevious = expectedCurrent.Clone();
expectedCurrent.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(789), nullptr);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(789), nullptr);
EXPECT_CALL(observer, OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_CHROME,
std::string()),
PolicyEquals(&expectedPrevious),
PolicyEquals(&expectedCurrent)));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
// No changes again.
EXPECT_CALL(observer, OnPolicyUpdated(_, _, _)).Times(0);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expectedCurrent));
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
}
TEST_F(PolicyServiceTest, NotifyObserversInMultipleNamespaces) {
const std::string kExtension0("extension-0");
const std::string kExtension1("extension-1");
const std::string kExtension2("extension-2");
MockPolicyServiceObserver chrome_observer;
MockPolicyServiceObserver extension_observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &chrome_observer);
policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &extension_observer);
PolicyMap previous_policy_map;
previous_policy_map.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(13),
nullptr);
previous_policy_map.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap policy_map;
policy_map = previous_policy_map.Clone();
policy_map.Set("policy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value("value"), nullptr);
PolicyBundle bundle;
// The initial setup includes a policy for chrome that is now changing.
bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) =
policy_map.Clone();
bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)) =
policy_map.Clone();
bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)) =
policy_map.Clone();
const PolicyMap kEmptyPolicyMap;
EXPECT_CALL(
chrome_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()),
PolicyEquals(&previous_policy_map),
PolicyEquals(&policy_map)));
EXPECT_CALL(
extension_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0),
PolicyEquals(&kEmptyPolicyMap),
PolicyEquals(&policy_map)));
EXPECT_CALL(
extension_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1),
PolicyEquals(&kEmptyPolicyMap),
PolicyEquals(&policy_map)));
provider0_.UpdatePolicy(std::move(bundle));
RunUntilIdle();
Mock::VerifyAndClearExpectations(&chrome_observer);
Mock::VerifyAndClearExpectations(&extension_observer);
// Chrome policy stays the same, kExtension0 is gone, kExtension1 changes,
// and kExtension2 is new.
previous_policy_map = policy_map.Clone();
bundle = PolicyBundle();
bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) =
policy_map.Clone();
policy_map.Set("policy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value("another value"), nullptr);
bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)) =
policy_map.Clone();
bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2)) =
policy_map.Clone();
EXPECT_CALL(chrome_observer, OnPolicyUpdated(_, _, _)).Times(0);
EXPECT_CALL(
extension_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0),
PolicyEquals(&previous_policy_map),
PolicyEquals(&kEmptyPolicyMap)));
EXPECT_CALL(
extension_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1),
PolicyEquals(&previous_policy_map),
PolicyEquals(&policy_map)));
EXPECT_CALL(
extension_observer,
OnPolicyUpdated(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2),
PolicyEquals(&kEmptyPolicyMap),
PolicyEquals(&policy_map)));
provider0_.UpdatePolicy(std::move(bundle));
RunUntilIdle();
Mock::VerifyAndClearExpectations(&chrome_observer);
Mock::VerifyAndClearExpectations(&extension_observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &chrome_observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS,
&extension_observer);
}
TEST_F(PolicyServiceTest, ObserverChangesPolicy) {
ChangePolicyObserver observer(&provider0_);
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
policy0_.Set("bbb", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(1234), nullptr);
// Should not crash.
provider0_.UpdateChromePolicy(policy0_);
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
EXPECT_TRUE(observer.observer_invoked());
}
TEST_F(PolicyServiceTest, HasProvider) {
MockConfigurationPolicyProvider other_provider;
EXPECT_TRUE(policy_service_->HasProvider(&provider0_));
EXPECT_TRUE(policy_service_->HasProvider(&provider1_));
EXPECT_TRUE(policy_service_->HasProvider(&provider2_));
EXPECT_FALSE(policy_service_->HasProvider(&other_provider));
}
TEST_F(PolicyServiceTest, NotifyProviderUpdateObserver) {
MockPolicyServiceProviderUpdateObserver provider_update_observer;
policy_service_->AddProviderUpdateObserver(&provider_update_observer);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(123), nullptr);
EXPECT_CALL(provider_update_observer,
OnProviderUpdatePropagated(&provider0_));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&provider_update_observer);
// No changes, ProviderUpdateObserver still notified.
EXPECT_CALL(provider_update_observer,
OnProviderUpdatePropagated(&provider0_));
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(&provider_update_observer);
policy_service_->RemoveProviderUpdateObserver(&provider_update_observer);
}
TEST_F(PolicyServiceTest, Priorities) {
PolicyMap expected;
expected.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(13), nullptr);
expected.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
expected.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(0), nullptr);
expected.GetMutable("aaa")->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
expected.GetMutable("aaa")->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(0), nullptr);
policy1_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
policy2_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(2), nullptr);
provider0_.UpdateChromePolicy(policy0_);
provider1_.UpdateChromePolicy(policy1_);
provider2_.UpdateChromePolicy(policy2_);
expected.GetMutable("aaa")->AddConflictingPolicy(
policy1_.Get("aaa")->DeepCopy());
expected.GetMutable("aaa")->AddConflictingPolicy(
policy2_.Get("aaa")->DeepCopy());
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expected));
expected.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
expected.GetMutable("aaa")->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
policy0_.Erase("aaa");
provider0_.UpdateChromePolicy(policy0_);
expected.GetMutable("aaa")->AddConflictingPolicy(
policy2_.Get("aaa")->DeepCopy());
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expected));
expected.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(2), nullptr);
expected.GetMutable("aaa")->AddMessage(PolicyMap::MessageType::kInfo,
IDS_POLICY_CONFLICT_SAME_VALUE);
policy1_.Set("aaa", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
expected.GetMutable("aaa")->AddConflictingPolicy(
policy2_.Get("aaa")->DeepCopy());
provider1_.UpdateChromePolicy(policy2_);
EXPECT_TRUE(VerifyPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), expected));
}
TEST_F(PolicyServiceTest, PolicyChangeRegistrar) {
std::unique_ptr<PolicyChangeRegistrar> registrar(new PolicyChangeRegistrar(
policy_service_.get(),
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
// Starting to observe existing policies doesn't trigger a notification.
EXPECT_CALL(*this, OnPolicyValueUpdated(_, _)).Times(0);
registrar->Observe(
"pre", base::BindRepeating(&PolicyServiceTest::OnPolicyValueUpdated,
base::Unretained(this)));
registrar->Observe(
"aaa", base::BindRepeating(&PolicyServiceTest::OnPolicyValueUpdated,
base::Unretained(this)));
RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
// Changing it now triggers a notification.
base::Value kValue0(0);
EXPECT_CALL(*this, OnPolicyValueUpdated(NULL, ValueEquals(&kValue0)));
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue0.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
// Changing other values doesn't trigger a notification.
EXPECT_CALL(*this, OnPolicyValueUpdated(_, _)).Times(0);
policy0_.Set("bbb", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue0.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
// Modifying the value triggers a notification.
base::Value kValue1(1);
EXPECT_CALL(*this, OnPolicyValueUpdated(ValueEquals(&kValue0),
ValueEquals(&kValue1)));
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue1.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
// Removing the value triggers a notification.
EXPECT_CALL(*this, OnPolicyValueUpdated(ValueEquals(&kValue1), NULL));
policy0_.Erase("aaa");
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
// No more notifications after destroying the registrar.
EXPECT_CALL(*this, OnPolicyValueUpdated(_, _)).Times(0);
registrar.reset();
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue1.Clone(), nullptr);
policy0_.Set("pre", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, kValue1.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
}
TEST_F(PolicyServiceTest, RefreshPolicies) {
EXPECT_CALL(provider0_, RefreshPolicies()).Times(AnyNumber());
EXPECT_CALL(provider1_, RefreshPolicies()).Times(AnyNumber());
EXPECT_CALL(provider2_, RefreshPolicies()).Times(AnyNumber());
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
policy_service_->RefreshPolicies(base::BindOnce(
&PolicyServiceTest::OnPolicyRefresh, base::Unretained(this)));
// Let any queued observer tasks run.
RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
base::Value kValue0(0);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue0.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
base::Value kValue1(1);
policy1_.Set("aaa", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue1.Clone(), nullptr);
provider1_.UpdateChromePolicy(policy1_);
Mock::VerifyAndClearExpectations(this);
// A provider can refresh more than once after a RefreshPolicies call, but
// OnPolicyRefresh should be triggered only after all providers are
// refreshed.
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
policy1_.Set("bbb", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue1.Clone(), nullptr);
provider1_.UpdateChromePolicy(policy1_);
Mock::VerifyAndClearExpectations(this);
// If another RefreshPolicies() call happens while waiting for a previous
// one to complete, then all providers must refresh again.
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
policy_service_->RefreshPolicies(base::BindOnce(
&PolicyServiceTest::OnPolicyRefresh, base::Unretained(this)));
RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, OnPolicyRefresh()).Times(0);
policy2_.Set("bbb", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue0.Clone(), nullptr);
provider2_.UpdateChromePolicy(policy2_);
Mock::VerifyAndClearExpectations(this);
// Providers 0 and 1 must reload again.
EXPECT_CALL(*this, OnPolicyRefresh()).Times(2);
base::Value kValue2(2);
policy0_.Set("aaa", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, kValue2.Clone(), nullptr);
provider0_.UpdateChromePolicy(policy0_);
provider1_.UpdateChromePolicy(policy1_);
Mock::VerifyAndClearExpectations(this);
const PolicyMap& policies = policy_service_->GetPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
EXPECT_EQ(kValue2, *policies.GetValue("aaa", base::Value::Type::INTEGER));
EXPECT_EQ(kValue0, *policies.GetValue("bbb", base::Value::Type::INTEGER));
}
TEST_F(PolicyServiceTest, NamespaceMerge) {
PolicyBundle bundle0;
PolicyBundle bundle1;
PolicyBundle bundle2;
AddTestPolicies(&bundle0, "bundle0", POLICY_LEVEL_RECOMMENDED,
POLICY_SCOPE_USER);
AddTestPolicies(&bundle1, "bundle1", POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER);
AddTestPolicies(&bundle2, "bundle2", POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE);
PolicyMap expected;
// For policies of the same level and scope, the first provider takes
// precedence, on every namespace.
expected.Set(kSameLevelPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value("bundle0"),
nullptr);
expected.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
expected.GetMutable(kSameLevelPolicy)
->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
expected.GetMutable(kSameLevelPolicy)
->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
expected.GetMutable(kSameLevelPolicy)
->AddConflictingPolicy(
bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.Get(kSameLevelPolicy)
->DeepCopy());
expected.GetMutable(kSameLevelPolicy)
->AddConflictingPolicy(
bundle2.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.Get(kSameLevelPolicy)
->DeepCopy());
// For policies with different levels and scopes, the highest priority
// level/scope combination takes precedence, on every namespace.
expected.Set(kDiffLevelPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_CLOUD, base::Value("bundle2"), nullptr);
expected.GetMutable(kDiffLevelPolicy)
->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
expected.GetMutable(kDiffLevelPolicy)
->AddConflictingPolicy(
bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.Get(kDiffLevelPolicy)
->DeepCopy());
expected.GetMutable(kDiffLevelPolicy)
->AddConflictingPolicy(
bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
.Get(kDiffLevelPolicy)
->DeepCopy());
provider0_.UpdatePolicy(std::move(bundle0));
provider1_.UpdatePolicy(std::move(bundle1));
provider2_.UpdatePolicy(std::move(bundle2));
RunUntilIdle();
EXPECT_TRUE(policy_service_->GetPolicies(
PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())).Equals(expected));
expected.Erase("migrated");
EXPECT_TRUE(policy_service_->GetPolicies(
PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension)).Equals(expected));
}
TEST_F(PolicyServiceTest, IsInitializationComplete) {
// |provider0_| has all domains initialized.
Mock::VerifyAndClearExpectations(&provider1_);
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider1_, IsInitializationComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
providers.push_back(&provider1_);
providers.push_back(&provider2_);
policy_service_ = std::make_unique<PolicyServiceImpl>(std::move(providers));
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// |provider2_| still doesn't have POLICY_DOMAIN_CHROME initialized, so
// the initialization status of that domain won't change.
MockPolicyServiceObserver observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
Mock::VerifyAndClearExpectations(&provider1_);
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider1_,
IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(false));
const PolicyMap kPolicyMap;
provider1_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Same if |provider1_| doesn't have POLICY_DOMAIN_EXTENSIONS initialized.
EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_,
IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Now initialize POLICY_DOMAIN_CHROME on all the providers.
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME));
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_,
IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
// Other domains are still not initialized.
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Initialize the remaining domains.
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer,
OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
Mock::VerifyAndClearExpectations(&provider1_);
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_,
IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider1_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Cleanup.
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
}
using DomainParameters = std::tuple<bool, // provider initialized
bool, // first policy fetched
bool // observer present
>;
using ObserverTestParameters = std::tuple<DomainParameters, // CHROME
DomainParameters, // EXTENSIONS
DomainParameters // SIGNIN_EXTENSIONS
>;
class PolicyServiceTestForObservers
: public testing::Test,
public testing::WithParamInterface<ObserverTestParameters> {
public:
PolicyServiceTestForObservers() = default;
PolicyServiceTestForObservers(const PolicyServiceTestForObservers& other) =
delete;
PolicyServiceTestForObservers& operator=(
const PolicyServiceTestForObservers& other) = delete;
~PolicyServiceTestForObservers() override = default;
void SetUp() override {
SetupDomain<POLICY_DOMAIN_CHROME>();
SetupDomain<POLICY_DOMAIN_EXTENSIONS>();
SetupDomain<POLICY_DOMAIN_SIGNIN_EXTENSIONS>();
provider_.Init();
}
void AddObservers(PolicyService* service) {
AddObserver<POLICY_DOMAIN_CHROME>(service);
AddObserver<POLICY_DOMAIN_EXTENSIONS>(service);
AddObserver<POLICY_DOMAIN_SIGNIN_EXTENSIONS>(service);
}
void RemoveObservers(PolicyService* service) {
RemoveObserver<POLICY_DOMAIN_CHROME>(service);
RemoveObserver<POLICY_DOMAIN_EXTENSIONS>(service);
RemoveObserver<POLICY_DOMAIN_SIGNIN_EXTENSIONS>(service);
}
void TearDown() override { provider_.Shutdown(); }
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
MockConfigurationPolicyProvider provider_;
MockPolicyServiceObserver observer_;
private:
template <PolicyDomain domain>
void SetupDomain() {
DomainParameters params = std::get<domain>(GetParam());
EXPECT_CALL(provider_, IsInitializationComplete(domain))
.WillRepeatedly(Return(std::get<0>(params)));
EXPECT_CALL(provider_, IsFirstPolicyLoadComplete(domain))
.WillRepeatedly(Return(std::get<1>(params)));
}
template <PolicyDomain domain>
void AddObserver(PolicyService* service) {
DomainParameters params = std::get<domain>(GetParam());
const bool isInitialized = std::get<0>(params);
const bool isPolicyFetched = std::get<1>(params);
const bool hasObserver = std::get<2>(params);
if (hasObserver)
service->AddObserver(domain, &observer_);
EXPECT_CALL(observer_, OnPolicyServiceInitialized(domain))
.Times(isInitialized && hasObserver);
EXPECT_CALL(observer_, OnFirstPoliciesLoaded(domain))
.Times(isInitialized && isPolicyFetched && hasObserver);
}
template <PolicyDomain domain>
void RemoveObserver(PolicyService* service) {
DomainParameters params = std::get<domain>(GetParam());
const bool hasObserver = std::get<2>(params);
if (hasObserver)
service->RemoveObserver(domain, &observer_);
}
};
TEST_P(PolicyServiceTestForObservers, MaybeNotifyPolicyDomainStatusChange) {
auto local_policy_service =
PolicyServiceImpl::CreateWithThrottledInitialization(
PolicyServiceImpl::Providers{&provider_});
AddObservers(local_policy_service.get());
local_policy_service->UnthrottleInitialization();
Mock::VerifyAndClearExpectations(&observer_);
Mock::VerifyAndClearExpectations(&provider_);
RemoveObservers(local_policy_service.get());
}
INSTANTIATE_TEST_SUITE_P(
AllDomains,
PolicyServiceTestForObservers,
testing::Combine(
testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()),
testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()),
testing::Combine(testing::Bool(), testing::Bool(), testing::Bool())));
TEST_F(PolicyServiceTest, IsInitializationCompleteMightDestroyThis) {
Mock::VerifyAndClearExpectations(&provider0_);
EXPECT_CALL(provider0_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider0_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
auto local_policy_service =
PolicyServiceImpl::CreateWithThrottledInitialization(
std::move(providers));
EXPECT_FALSE(
local_policy_service->IsInitializationComplete(POLICY_DOMAIN_CHROME));
MockPolicyServiceObserver observer;
local_policy_service->AddObserver(POLICY_DOMAIN_CHROME, &observer);
// Now initialize policy domains on provider0.
// One of our observers destroys the policy service.
// This happens in the wild: https://crbug.com/747817
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME))
.WillOnce([&local_policy_service, &observer](auto) {
local_policy_service->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
local_policy_service.reset();
});
local_policy_service->UnthrottleInitialization();
EXPECT_FALSE(local_policy_service);
Mock::VerifyAndClearExpectations(&observer);
Mock::VerifyAndClearExpectations(&provider0_);
}
// Tests initialization throttling of PolicyServiceImpl.
// This actually tests two cases:
// (1) A domain was initialized before UnthrottleInitialization is called.
// Observers only get notified after calling UnthrottleInitialization.
// This is tested on POLICY_DOMAIN_CHROME.
// (2) A domain becomes initialized after UnthrottleInitialization has already
// been called. Because initialization is not throttled anymore, observers
// get notified immediately when the domain becomes initialized.
// This is tested on POLICY_DOMAIN_EXTENSIONS and
// POLICY_DOMAIN_SIGNIN_EXTENSIONS.
TEST_F(PolicyServiceTest, InitializationThrottled) {
// |provider0_| and |provider1_| has all domains initialized, |provider2_| has
// no domain initialized.
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
providers.push_back(&provider1_);
providers.push_back(&provider2_);
policy_service_ = PolicyServiceImpl::CreateWithThrottledInitialization(
std::move(providers));
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
MockPolicyServiceObserver observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
// Now additionally initialize POLICY_DOMAIN_CHROME on |provider2_|.
// Note: VerifyAndClearExpectations is called to reset the previously set
// action for IsInitializationComplete and IsFirstPolicyLoadComplete on
// |provider_2|.
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_,
IsInitializationComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_,
IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(false));
// Nothing will happen because initialization is still throttled.
EXPECT_CALL(observer, OnPolicyServiceInitialized(_)).Times(0);
EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
const PolicyMap kPolicyMap;
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Unthrottle initialization. This will signal that POLICY_DOMAIN_CHROME is
// initialized, the other domains should still not be initialized because
// |provider2_| is returning false in IsInitializationComplete and
// IsFirstPolicyLoadComplete for them.
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
policy_service_->UnthrottleInitialization();
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Initialize the remaining domains.
// Note: VerifyAndClearExpectations is called to reset the previously set
// action for IsInitializationComplete and IsFirstPolicyLoadComplete on
// |provider_2|.
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer,
OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Cleanup.
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
}
TEST_F(PolicyServiceTest, InitializationThrottledProvidersAlreadyInitialized) {
// All providers have all domains initialized.
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
providers.push_back(&provider1_);
providers.push_back(&provider2_);
policy_service_ = PolicyServiceImpl::CreateWithThrottledInitialization(
std::move(providers));
EXPECT_FALSE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
MockPolicyServiceObserver observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
// Unthrottle initialization. This will signal that all domains are
// initialized.
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_CHROME));
EXPECT_CALL(observer, OnPolicyServiceInitialized(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer,
OnPolicyServiceInitialized(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
policy_service_->UnthrottleInitialization();
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsInitializationComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsInitializationComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Cleanup.
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
}
TEST_F(PolicyServiceTest, IsFirstPolicyLoadComplete) {
// |provider0_| has all domains initialized.
Mock::VerifyAndClearExpectations(&provider1_);
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider1_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(_))
.WillRepeatedly(Return(false));
PolicyServiceImpl::Providers providers;
providers.push_back(&provider0_);
providers.push_back(&provider1_);
providers.push_back(&provider2_);
policy_service_ = std::make_unique<PolicyServiceImpl>(std::move(providers));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// |provider2_| still doesn't have POLICY_DOMAIN_CHROME initialized, so
// the initialization status of that domain won't change.
MockPolicyServiceObserver observer;
policy_service_->AddObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->AddObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
Mock::VerifyAndClearExpectations(&provider1_);
EXPECT_CALL(provider1_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider1_,
IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(false));
const PolicyMap kPolicyMap;
provider1_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Same if |provider1_| doesn't have POLICY_DOMAIN_EXTENSIONS initialized.
EXPECT_CALL(observer, OnFirstPoliciesLoaded(_)).Times(0);
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(false));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_,
IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Now initialize POLICY_DOMAIN_CHROME on all the providers.
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_CHROME));
Mock::VerifyAndClearExpectations(&provider2_);
EXPECT_CALL(provider2_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider2_,
IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider2_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
// Other domains are still not initialized.
EXPECT_FALSE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_FALSE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Initialize the remaining domains.
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_EXTENSIONS));
EXPECT_CALL(observer, OnFirstPoliciesLoaded(POLICY_DOMAIN_SIGNIN_EXTENSIONS));
Mock::VerifyAndClearExpectations(&provider1_);
EXPECT_CALL(provider1_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_, IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS))
.WillRepeatedly(Return(true));
EXPECT_CALL(provider1_,
IsFirstPolicyLoadComplete(POLICY_DOMAIN_SIGNIN_EXTENSIONS))
.WillRepeatedly(Return(true));
provider1_.UpdateChromePolicy(kPolicyMap);
Mock::VerifyAndClearExpectations(&observer);
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_CHROME));
EXPECT_TRUE(
policy_service_->IsFirstPolicyLoadComplete(POLICY_DOMAIN_EXTENSIONS));
EXPECT_TRUE(policy_service_->IsFirstPolicyLoadComplete(
POLICY_DOMAIN_SIGNIN_EXTENSIONS));
// Cleanup.
policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_EXTENSIONS, &observer);
policy_service_->RemoveObserver(POLICY_DOMAIN_SIGNIN_EXTENSIONS, &observer);
}
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PolicyServiceTest, DictionaryPoliciesMerging) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::Dict dict1;
dict1.Set(kUrl3, false);
dict1.Set(kUrl2, true);
base::Value::Dict dict2;
dict2.Set(kUrl1, true);
dict2.Set(kUrl2, false);
base::Value::Dict result;
result.Set(kUrl1, true);
result.Set(kUrl2, true);
result.Set(kUrl3, false);
base::Value::List policy;
policy.Append(key::kExtensionSettings);
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyDictionaryMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kExtensionSettings,
base::Value(std::move(dict1)));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kExtensionSettings,
base::Value(std::move(dict2)));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyDictionaryMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
expected_chrome.Set(key::kExtensionSettings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, DictionaryPoliciesMerging_InvalidType) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::Dict dict_value;
dict_value.Set(kUrl1, true);
base::Value::Dict result;
result.Set(kUrl1, true);
base::Value::List policy;
policy.Append(policy::key::kExtensionSettings);
// policy_bundle_1 is treated as a machine platform bundle.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyDictionaryMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kExtensionSettings,
base::Value(dict_value.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. A string value is set
// instead of the expected dictionary value.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kExtensionSettings, base::Value(kUrl2));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
// The expected_chrome PolicyMap only contains the URLs from policy_bundle_1.
// The string value stored in policy_bundle_2 is ignored during merging since
// its type does not match the expected dictionary type.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyDictionaryMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
expected_chrome.Set(key::kExtensionSettings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
// Policy precedence changes are not supported on Chrome OS.
TEST_F(PolicyServiceTest, DictionaryPoliciesMerging_PrecedenceChange) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs. User and device ID is identical.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
// Initialize dictionaries of URLs used for ExtensionSettings policy values.
base::Value::Dict dict1;
dict1.Set(kUrl2, true);
dict1.Set(kUrl3, false);
base::Value::Dict dict2;
dict2.Set(kUrl1, true);
dict2.Set(kUrl2, false);
base::Value::Dict dict3;
dict3.Set(kUrl3, true);
dict3.Set(kUrl4, false);
base::Value::Dict result;
result.Set(kUrl1, true);
result.Set(kUrl2, false);
result.Set(kUrl3, true);
result.Set(kUrl4, false);
base::Value::List policy;
policy.Append(key::kExtensionSettings);
// policy_bundle_1 is treated as a machine platform bundle. The metapolicies
// are defined here.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyDictionaryMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudPolicyOverridesPlatformPolicy,
base::Value(true));
policies_1.emplace_back(key::kCloudUserPolicyOverridesCloudMachinePolicy,
base::Value(true));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_1.emplace_back(key::kExtensionSettings,
base::Value(std::move(dict1)));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. The device
// affiliation IDs are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kExtensionSettings, std::move(dict2));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kExtensionSettings, std::move(dict3));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(ids);
// The expected_chrome PolicyMap contains the combined URLs from all three
// policy bundles. The affiliation IDs don't need to be added as they're not
// compared in the PolicyMap equality check.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyDictionaryMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set(key::kCloudPolicyOverridesPlatformPolicy,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(true), nullptr);
expected_chrome.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(true), nullptr);
expected_chrome.Set(key::kCloudUserPolicyMerge, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
base::Value(true), nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kExtensionSettings)
->DeepCopy());
expected_chrome.Set(key::kExtensionSettings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#endif // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID) &&
// !BUILDFLAG(IS_IOS)
TEST_F(PolicyServiceTest, ListsPoliciesMerging) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::List list1;
list1.Append(kUrl3);
list1.Append(kUrl2);
base::Value::List list2;
list2.Append(kUrl1);
list2.Append(kUrl2);
base::Value::List result;
result.Append(kUrl3);
result.Append(kUrl2);
result.Append(kUrl1);
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, ListsPoliciesMerging_InvalidType) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::List list_value;
list_value.Append(kUrl1);
base::Value::List result;
result.Append(kUrl1);
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
list_value.Clone());
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. A string value is set
// instead of the expected list value.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(kUrl2));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
// The expected_chrome PolicyMap only contains the URLs from policy_bundle_1.
// The string value stored in policy_bundle_2 is ignored during merging since
// its type does not match the expected list type.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
// The cloud user policy merging metapolicy is not applicable in Chrome OS.
TEST_F(PolicyServiceTest, ListsPoliciesMerging_CloudMetapolicy) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs. User and device ID is identical.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
base::Value::List list1;
list1.Append(kUrl1);
list1.Append(kUrl2);
base::Value::List list2;
list2.Append(kUrl2);
list2.Append(kUrl3);
base::Value::List list3;
list2.Append(kUrl3);
list2.Append(kUrl4);
base::Value::List result;
result.Append(kUrl1);
result.Append(kUrl2);
result.Append(kUrl3);
result.Append(kUrl4);
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. In addition to the
// device affiliation IDs, the metapolicies are also defined here to simulate
// being set through CBCM.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_2.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(ids);
// The expected_chrome PolicyMap contains the combined URLs from all three
// policy bundles. The affiliation IDs don't need to be added as they're not
// compared in the PolicyMap equality check.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_CLOUD, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set(key::kCloudUserPolicyMerge, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
base::Value(true), nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
provider0_.UpdatePolicy(std::move(policy_bundle_3));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_1));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#endif // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
#if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(PolicyServiceTest, GroupPoliciesMergingDisabledForCloudUsers) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::List list1;
list1.Append(kUrl3);
base::Value::List list2;
list2.Append(kUrl1);
base::Value::List list3;
list3.Append(kUrl4);
base::Value::List result;
result.Append(kUrl3);
result.Append(kUrl1);
base::Value::List policy;
policy.Append(policy::key::kExtensionInstallForcelist);
policy.Append(policy::key::kExtensionInstallBlocklist);
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kExtensionInstallForcelist,
base::Value(list1.Clone()));
policies_1.emplace_back(key::kExtensionInstallBlocklist,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// Unlike the rest of the bundle, this policy is set at the cloud user level.
PolicyMap::Entry atomic_policy_enabled(POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
base::Value(true), nullptr);
policy_bundle_1.Get(chrome_namespace)
.Set(key::kPolicyAtomicGroupsEnabled, atomic_policy_enabled.DeepCopy());
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kExtensionInstallForcelist,
base::Value(list2.Clone()));
policies_2.emplace_back(key::kExtensionInstallBlocklist,
base::Value(list2.Clone()));
policies_2.emplace_back(key::kExtensionInstallAllowlist,
base::Value(list3.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kExtensionInstallForcelist)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kExtensionInstallForcelist)
->DeepCopy());
expected_chrome.Set(key::kExtensionInstallForcelist, merged.DeepCopy());
expected_chrome.Set(key::kExtensionInstallBlocklist, std::move(merged));
expected_chrome.Set(key::kExtensionInstallAllowlist,
policy_bundle_2.Get(chrome_namespace)
.Get(key::kExtensionInstallAllowlist)
->DeepCopy());
expected_chrome.Set(key::kPolicyAtomicGroupsEnabled,
atomic_policy_enabled.DeepCopy());
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, GroupPoliciesMergingEnabled) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
base::Value::List list1;
list1.Append(kUrl3);
base::Value::List list2;
list2.Append(kUrl1);
base::Value::List list3;
list3.Append(kUrl4);
base::Value::List result;
result.Append(kUrl3);
result.Append(kUrl1);
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
policy.Append(policy::key::kExtensionInstallBlocklist);
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
policies_1.emplace_back(key::kExtensionInstallBlocklist,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// Unlike the rest of the bundle, this policy is set at the cloud user level.
PolicyMap::Entry atomic_policy_enabled(
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
base::Value(true), nullptr);
policy_bundle_1.Get(chrome_namespace)
.Set(key::kPolicyAtomicGroupsEnabled, atomic_policy_enabled.DeepCopy());
PolicyMap::Entry entry_list_3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_CLOUD, base::Value(list3.Clone()),
nullptr);
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
policies_2.emplace_back(key::kExtensionInstallBlocklist,
base::Value(list2.Clone()));
policies_2.emplace_back(key::kExtensionInstallAllowlist,
entry_list_3.value(base::Value::Type::LIST)->Clone());
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
entry_list_3.SetIgnoredByPolicyAtomicGroup();
expected_chrome.Set(key::kDefaultSearchProviderEncodings, merged.DeepCopy());
expected_chrome.Set(key::kExtensionInstallBlocklist, std::move(merged));
expected_chrome.Set(key::kExtensionInstallAllowlist, std::move(entry_list_3));
expected_chrome.Set(key::kPolicyAtomicGroupsEnabled,
atomic_policy_enabled.DeepCopy());
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
TEST_F(PolicyServiceTest, CloudUserListPolicyMerge_Successful) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs. User and device ID is identical.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
// Initialize lists of URLs used for DefaultSearchProviderEncodings policy
// values.
base::Value::List list1;
list1.Append(kUrl1);
list1.Append(kUrl2);
base::Value::List list2;
list2.Append(kUrl2);
list2.Append(kUrl3);
base::Value::List list3;
list3.Append(kUrl3);
list3.Append(kUrl4);
base::Value::List result;
result.Append(kUrl1);
result.Append(kUrl2);
result.Append(kUrl3);
result.Append(kUrl4);
// Populate separate policy bundles.
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle. The metadata
// policies (PolicyListMultipleSourceMergeList, CloudUserPolicyMerge) are
// defined here.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. The device
// affiliation IDs are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(ids);
// The expected_chrome PolicyMap contains the combined URLs from all three
// policy bundles. The affiliation IDs don't need to be added as they're not
// compared in the PolicyMap equality check.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
expected_chrome.Set(key::kCloudUserPolicyMerge,
policy_bundle_1.Get(chrome_namespace)
.Get(key::kCloudUserPolicyMerge)
->DeepCopy());
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, CloudUserListPolicyMerge_Unaffiliated) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize user and device affiliation IDs with no common ID.
base::flat_set<std::string> user_ids;
user_ids.insert(kAffiliationId1);
base::flat_set<std::string> device_ids;
device_ids.insert(kAffiliationId2);
// Initialize lists of URLs used for DefaultSearchProviderEncodings policy
// values.
base::Value::List list1;
list1.Append(kUrl1);
list1.Append(kUrl2);
base::Value::List list2;
list2.Append(kUrl3);
base::Value::List list3;
list3.Append(kUrl4);
base::Value::List result;
result.Append(kUrl1);
result.Append(kUrl2);
result.Append(kUrl3);
// Populate separate policy bundles.
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle. The metadata
// policies (PolicyListMultipleSourceMergeList, CloudUserPolicyMerge) are
// defined here.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. The device
// affiliation IDs are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(device_ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(user_ids);
// The expected_chrome PolicyMap contains the combined URLs from the non-user
// policy bundles. The policy values from the user cloud bundle aren't merged
// as there is no common affiliation ID between the user and device.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
expected_chrome.Set(key::kCloudUserPolicyMerge,
policy_bundle_1.Get(chrome_namespace)
.Get(key::kCloudUserPolicyMerge)
->DeepCopy());
expected_chrome.GetMutable(key::kCloudUserPolicyMerge)
->AddMessage(PolicyMap::MessageType::kError,
IDS_POLICY_IGNORED_UNAFFILIATED);
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, CloudUserListPolicyMerge_FalsePolicy) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs. User and device ID is identical.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
// Initialize lists of URLs used for DefaultSearchProviderEncodings policy
// values.
base::Value::List list1;
list1.Append(kUrl1);
base::Value::List list2;
list2.Append(kUrl2);
base::Value::List list3;
list3.Append(kUrl3);
base::Value::List result;
result.Append(kUrl1);
result.Append(kUrl2);
// Populate separate policy bundles.
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle. The metadata
// policies (PolicyListMultipleSourceMergeList, CloudUserPolicyMerge) are
// defined here. CloudUserPolicyMerge is set to false, preventing user cloud
// policy values from being merged with values from other sources.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(false));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. The device
// affiliation IDs are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(ids);
// The expected_chrome PolicyMap contains the combined URLs from the non-user
// policy bundles. The policy values from the user cloud bundle aren't merged
// because CloudUserPolicyMerge is set to false.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
expected_chrome.Set(key::kCloudUserPolicyMerge,
policy_bundle_1.Get(chrome_namespace)
.Get(key::kCloudUserPolicyMerge)
->DeepCopy());
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, PlatformUserListPolicyMerge_Affiliated) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs. User and device ID is identical.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
// Initialize lists of URLs used for DefaultSearchProviderEncodings policy
// values.
base::Value::List list1;
list1.Append(kUrl1);
base::Value::List list2;
list2.Append(kUrl2);
base::Value::List list3;
list3.Append(kUrl3);
base::Value::List result;
result.Append(kUrl2);
result.Append(kUrl3);
// Populate separate policy bundles.
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a user platform bundle. The metadata policies
// (PolicyListMultipleSourceMergeList, CloudUserPolicyMerge) are defined here.
// Policy values with a user GPO source are currently not merged with values
// from any other source(s).
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a machine cloud bundle. The device
// affiliation IDs are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies_2), chrome_namespace);
policy_bundle_2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.t,
// entry_list_3.DeepCopy()); policy_map_3.SetUserAffiliationIds(ids);
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(ids);
// The expected_chrome PolicyMap contains the merged values from machine and
// user policy sources. User platform policy values are not merged.
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
expected_chrome.Set(key::kCloudUserPolicyMerge,
policy_bundle_1.Get(chrome_namespace)
.Get(key::kCloudUserPolicyMerge)
->DeepCopy());
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, PlatformUserListPolicyMerge_Unaffiliated) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize user affiliation IDs. This test doesn't contain a machine cloud
// source, so no device affiliation IDs are set.
base::flat_set<std::string> user_ids;
user_ids.insert(kAffiliationId1);
// Initialize lists of URLs used for DefaultSearchProviderEncodings policy
// values.
base::Value::List list1;
list1.Append(kUrl1);
base::Value::List list2;
list2.Append(kUrl2);
base::Value::List list3;
list3.Append(kUrl3);
base::Value::List result;
result.Append(kUrl1);
// Populate separate policy bundles.
base::Value::List policy;
policy.Append(policy::key::kDefaultSearchProviderEncodings);
// policy_bundle_1 is treated as a machine platform bundle. The metadata
// policies (PolicyListMultipleSourceMergeList, CloudUserPolicyMerge) are
// defined here.
std::vector<std::pair<std::string, base::Value>> policies_1;
policies_1.emplace_back(key::kPolicyListMultipleSourceMergeList,
base::Value(policy.Clone()));
policies_1.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
policies_1.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list1.Clone()));
auto policy_bundle_1 =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies_1), chrome_namespace);
// policy_bundle_2 is treated as a user platform bundle. Policy values with a
// user GPO source are currently not merged with values from any other
// source(s).
std::vector<std::pair<std::string, base::Value>> policies_2;
policies_2.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list2.Clone()));
auto policy_bundle_2 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
std::move(policies_2), chrome_namespace);
// policy_bundle_3 is treated as a user cloud bundle. The user affiliation IDs
// are defined here to reflect what would happen in reality.
std::vector<std::pair<std::string, base::Value>> policies_3;
policies_3.emplace_back(key::kDefaultSearchProviderEncodings,
base::Value(list3.Clone()));
auto policy_bundle_3 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies_3), chrome_namespace);
policy_bundle_3.Get(chrome_namespace).SetUserAffiliationIds(user_ids);
// The expected_chrome PolicyMap only contains the URLs from the platform
// machine policy source. Values from the user platform policy are not
// mergeable. Values from the user cloud policy are not merged since the user
// is not affiliated (browser isn't enrolled in CBCM).
PolicyMap expected_chrome;
expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(policy.Clone()),
nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_MERGED, base::Value(std::move(result)),
nullptr);
merged.AddConflictingPolicy(policy_bundle_2.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_3.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
merged.AddConflictingPolicy(policy_bundle_1.Get(chrome_namespace)
.Get(key::kDefaultSearchProviderEncodings)
->DeepCopy());
expected_chrome.Set(key::kDefaultSearchProviderEncodings, std::move(merged));
expected_chrome.Set(key::kCloudUserPolicyMerge,
policy_bundle_1.Get(chrome_namespace)
.Get(key::kCloudUserPolicyMerge)
->DeepCopy());
expected_chrome.GetMutable(key::kCloudUserPolicyMerge)
->AddMessage(PolicyMap::MessageType::kError,
IDS_POLICY_IGNORED_UNAFFILIATED);
provider0_.UpdatePolicy(std::move(policy_bundle_1));
provider1_.UpdatePolicy(std::move(policy_bundle_2));
provider2_.UpdatePolicy(std::move(policy_bundle_3));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
TEST_F(PolicyServiceTest, IgnoreUserCloudPrecedencePolicies) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// The policies are set by a user cloud source.
std::vector<std::pair<std::string, base::Value>> policies;
policies.emplace_back(key::kCloudPolicyOverridesPlatformPolicy,
base::Value(true));
policies.emplace_back(key::kCloudUserPolicyOverridesCloudMachinePolicy,
base::Value(true));
policies.emplace_back(key::kTranslateEnabled, base::Value(true));
auto policy_bundle = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies), chrome_namespace);
provider0_.UpdatePolicy(std::move(policy_bundle));
RunUntilIdle();
// Precedence metapolicies set from a user cloud source are ignored.
EXPECT_EQ(nullptr, policy_service_->GetPolicies(chrome_namespace)
.GetValue(key::kCloudPolicyOverridesPlatformPolicy,
base::Value::Type::BOOLEAN));
EXPECT_EQ(nullptr,
policy_service_->GetPolicies(chrome_namespace)
.GetValue(key::kCloudUserPolicyOverridesCloudMachinePolicy,
base::Value::Type::BOOLEAN));
// Other policies set from a user cloud source are not ignored.
EXPECT_NE(nullptr,
policy_service_->GetPolicies(chrome_namespace)
.GetValue(key::kTranslateEnabled, base::Value::Type::BOOLEAN));
}
TEST_F(PolicyServiceTest, PolicyMessages) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
std::vector<std::pair<std::string, base::Value>> policies;
policies.emplace_back(key::kCloudUserPolicyOverridesCloudMachinePolicy,
base::Value(true));
policies.emplace_back(key::kCloudUserPolicyMerge, base::Value(true));
auto policy_bundle =
CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
std::move(policies), chrome_namespace);
PolicyMap expected_chrome;
expected_chrome.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_PLATFORM, base::Value(true), nullptr);
expected_chrome.Set(key::kCloudUserPolicyMerge, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
base::Value(true), nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
// Error messages should appear because the user is unaffiliated.
expected_chrome.GetMutable(key::kCloudUserPolicyOverridesCloudMachinePolicy)
->AddMessage(PolicyMap::MessageType::kError,
IDS_POLICY_IGNORED_UNAFFILIATED);
expected_chrome.GetMutable(key::kCloudUserPolicyMerge)
->AddMessage(PolicyMap::MessageType::kError,
IDS_POLICY_IGNORED_UNAFFILIATED);
provider0_.UpdatePolicy(std::move(policy_bundle));
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#endif // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
#if !BUILDFLAG(IS_CHROMEOS)
TEST_F(PolicyServiceTest, PrecedencePolicy) {
const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
// Initialize affiliation IDs.
base::flat_set<std::string> ids;
ids.insert(kAffiliationId1);
// Set policy.
std::vector<std::pair<std::string, base::Value>> policies0;
policies0.emplace_back("a", base::Value(true));
auto policy_bundle0 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::move(policies0), chrome_namespace);
policy_bundle0.Get(chrome_namespace).SetUserAffiliationIds(ids);
policy_bundle0.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
provider0_.UpdatePolicy(std::move(policy_bundle0));
std::vector<std::pair<std::string, base::Value>> policies1;
policies1.emplace_back("a", base::Value(false));
auto policy_bundle1 = CreateBundle(POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(policies1), chrome_namespace);
policy_bundle1.Get(chrome_namespace).SetUserAffiliationIds(ids);
policy_bundle1.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
provider1_.UpdatePolicy(std::move(policy_bundle1));
// Set precedence policy.
std::vector<std::pair<std::string, base::Value>> policies2;
policies2.emplace_back(key::kCloudUserPolicyOverridesCloudMachinePolicy,
base::Value(true));
auto policy_bundle2 = CreateBundle(POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
std::move(policies2), chrome_namespace);
policy_bundle2.Get(chrome_namespace).SetUserAffiliationIds(ids);
policy_bundle2.Get(chrome_namespace).SetDeviceAffiliationIds(ids);
provider2_.UpdatePolicy(std::move(policy_bundle2));
// Verify user cloud policy override machine cloud policy.
PolicyMap expected_chrome;
expected_chrome.Set("a", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
expected_chrome.Set(key::kCloudUserPolicyOverridesCloudMachinePolicy,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(true), nullptr);
expected_chrome.Set("migrated", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_PLATFORM, base::Value(15), nullptr);
expected_chrome.GetMutable("a")->AddConflictingPolicy(
PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_CLOUD, base::Value(false), nullptr));
expected_chrome.GetMutable("a")->AddMessage(PolicyMap::MessageType::kWarning,
IDS_POLICY_CONFLICT_DIFF_VALUE);
RunUntilIdle();
EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
}
#endif // !BUILDFLAG(IS_CHROMEOS)
} // namespace policy