xref: /aosp_15_r20/external/libchrome/components/policy/core/common/configuration_policy_provider_test.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/policy/core/common/configuration_policy_provider_test.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/task_scheduler/post_task.h"
12 #include "base/task_scheduler/task_traits.h"
13 #include "base/values.h"
14 #include "components/policy/core/common/configuration_policy_provider.h"
15 #include "components/policy/core/common/external_data_fetcher.h"
16 #include "components/policy/core/common/mock_configuration_policy_provider.h"
17 #include "components/policy/core/common/policy_bundle.h"
18 #include "components/policy/core/common/policy_map.h"
19 #include "components/policy/core/common/policy_namespace.h"
20 #include "components/policy/core/common/policy_types.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 
23 using ::testing::Mock;
24 using ::testing::_;
25 
26 namespace policy {
27 
28 const char kTestChromeSchema[] =
29     "{"
30     "  \"type\": \"object\","
31     "  \"properties\": {"
32     "    \"StringPolicy\": { \"type\": \"string\" },"
33     "    \"BooleanPolicy\": { \"type\": \"boolean\" },"
34     "    \"IntegerPolicy\": { \"type\": \"integer\" },"
35     "    \"StringListPolicy\": {"
36     "      \"type\": \"array\","
37     "      \"items\": { \"type\": \"string\" }"
38     "    },"
39     "    \"DictionaryPolicy\": {"
40     "      \"type\": \"object\","
41     "      \"properties\": {"
42     "        \"bool\": { \"type\": \"boolean\" },"
43     "        \"double\": { \"type\": \"number\" },"
44     "        \"int\": { \"type\": \"integer\" },"
45     "        \"string\": { \"type\": \"string\" },"
46     "        \"array\": {"
47     "          \"type\": \"array\","
48     "          \"items\": { \"type\": \"string\" }"
49     "        },"
50     "        \"dictionary\": {"
51     "          \"type\": \"object\","
52     "          \"properties\": {"
53     "            \"sub\": { \"type\": \"string\" },"
54     "            \"sublist\": {"
55     "              \"type\": \"array\","
56     "              \"items\": {"
57     "                \"type\": \"object\","
58     "                \"properties\": {"
59     "                  \"aaa\": { \"type\": \"integer\" },"
60     "                  \"bbb\": { \"type\": \"integer\" },"
61     "                  \"ccc\": { \"type\": \"string\" },"
62     "                  \"ddd\": { \"type\": \"string\" }"
63     "                }"
64     "              }"
65     "            }"
66     "          }"
67     "        },"
68     "        \"list\": {"
69     "          \"type\": \"array\","
70     "          \"items\": {"
71     "            \"type\": \"object\","
72     "            \"properties\": {"
73     "              \"subdictindex\": { \"type\": \"integer\" },"
74     "              \"subdict\": {"
75     "                \"type\": \"object\","
76     "                \"properties\": {"
77     "                  \"bool\": { \"type\": \"boolean\" },"
78     "                  \"double\": { \"type\": \"number\" },"
79     "                  \"int\": { \"type\": \"integer\" },"
80     "                  \"string\": { \"type\": \"string\" }"
81     "                }"
82     "              }"
83     "            }"
84     "          }"
85     "        },"
86     "        \"dict\": {"
87     "          \"type\": \"object\","
88     "          \"properties\": {"
89     "            \"bool\": { \"type\": \"boolean\" },"
90     "            \"double\": { \"type\": \"number\" },"
91     "            \"int\": { \"type\": \"integer\" },"
92     "            \"string\": { \"type\": \"string\" },"
93     "            \"list\": {"
94     "              \"type\": \"array\","
95     "              \"items\": {"
96     "                \"type\": \"object\","
97     "                \"properties\": {"
98     "                  \"subdictindex\": { \"type\": \"integer\" },"
99     "                  \"subdict\": {"
100     "                    \"type\": \"object\","
101     "                    \"properties\": {"
102     "                      \"bool\": { \"type\": \"boolean\" },"
103     "                      \"double\": { \"type\": \"number\" },"
104     "                      \"int\": { \"type\": \"integer\" },"
105     "                      \"string\": { \"type\": \"string\" }"
106     "                    }"
107     "                  }"
108     "                }"
109     "              }"
110     "            }"
111     "          }"
112     "        }"
113     "      }"
114     "    }"
115     "  }"
116     "}";
117 
118 namespace test_keys {
119 
120 const char kKeyString[] = "StringPolicy";
121 const char kKeyBoolean[] = "BooleanPolicy";
122 const char kKeyInteger[] = "IntegerPolicy";
123 const char kKeyStringList[] = "StringListPolicy";
124 const char kKeyDictionary[] = "DictionaryPolicy";
125 
126 }  // namespace test_keys
127 
PolicyTestBase()128 PolicyTestBase::PolicyTestBase() {}
129 
~PolicyTestBase()130 PolicyTestBase::~PolicyTestBase() {}
131 
SetUp()132 void PolicyTestBase::SetUp() {
133   const PolicyNamespace ns(POLICY_DOMAIN_CHROME, "");
134   ASSERT_TRUE(RegisterSchema(ns, kTestChromeSchema));
135 }
136 
TearDown()137 void PolicyTestBase::TearDown() {
138   scoped_task_environment_.RunUntilIdle();
139 }
140 
RegisterSchema(const PolicyNamespace & ns,const std::string & schema_string)141 bool PolicyTestBase::RegisterSchema(const PolicyNamespace& ns,
142                                     const std::string& schema_string) {
143   std::string error;
144   Schema schema = Schema::Parse(schema_string, &error);
145   if (schema.valid()) {
146     schema_registry_.RegisterComponent(ns, schema);
147     return true;
148   }
149   ADD_FAILURE() << error;
150   return false;
151 }
152 
PolicyProviderTestHarness(PolicyLevel level,PolicyScope scope,PolicySource source)153 PolicyProviderTestHarness::PolicyProviderTestHarness(PolicyLevel level,
154                                                      PolicyScope scope,
155                                                      PolicySource source)
156     : level_(level), scope_(scope), source_(source) {}
157 
~PolicyProviderTestHarness()158 PolicyProviderTestHarness::~PolicyProviderTestHarness() {}
159 
policy_level() const160 PolicyLevel PolicyProviderTestHarness::policy_level() const {
161   return level_;
162 }
163 
policy_scope() const164 PolicyScope PolicyProviderTestHarness::policy_scope() const {
165   return scope_;
166 }
167 
policy_source() const168 PolicySource PolicyProviderTestHarness::policy_source() const {
169   return source_;
170 }
171 
Install3rdPartyPolicy(const base::DictionaryValue * policies)172 void PolicyProviderTestHarness::Install3rdPartyPolicy(
173     const base::DictionaryValue* policies) {
174   FAIL();
175 }
176 
ConfigurationPolicyProviderTest()177 ConfigurationPolicyProviderTest::ConfigurationPolicyProviderTest() {}
178 
~ConfigurationPolicyProviderTest()179 ConfigurationPolicyProviderTest::~ConfigurationPolicyProviderTest() {}
180 
SetUp()181 void ConfigurationPolicyProviderTest::SetUp() {
182   PolicyTestBase::SetUp();
183 
184   test_harness_.reset((*GetParam())());
185   ASSERT_NO_FATAL_FAILURE(test_harness_->SetUp());
186 
187   const PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, "");
188   Schema chrome_schema = *schema_registry_.schema_map()->GetSchema(chrome_ns);
189   Schema extension_schema =
190       chrome_schema.GetKnownProperty(test_keys::kKeyDictionary);
191   ASSERT_TRUE(extension_schema.valid());
192   schema_registry_.RegisterComponent(
193       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
194                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
195       extension_schema);
196   schema_registry_.RegisterComponent(
197       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
198                       "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
199       extension_schema);
200   schema_registry_.RegisterComponent(
201       PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
202                       "cccccccccccccccccccccccccccccccc"),
203       extension_schema);
204 
205   provider_.reset(test_harness_->CreateProvider(
206       &schema_registry_,
207       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})));
208   provider_->Init(&schema_registry_);
209   // Some providers do a reload on init. Make sure any notifications generated
210   // are fired now.
211   scoped_task_environment_.RunUntilIdle();
212 
213   const PolicyBundle kEmptyBundle;
214   EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
215 }
216 
TearDown()217 void ConfigurationPolicyProviderTest::TearDown() {
218   // Give providers the chance to clean up after themselves on the file thread.
219   provider_->Shutdown();
220   provider_.reset();
221 
222   PolicyTestBase::TearDown();
223 }
224 
CheckValue(const char * policy_name,const base::Value & expected_value,base::Closure install_value)225 void ConfigurationPolicyProviderTest::CheckValue(
226     const char* policy_name,
227     const base::Value& expected_value,
228     base::Closure install_value) {
229   // Install the value, reload policy and check the provider for the value.
230   install_value.Run();
231   provider_->RefreshPolicies();
232   scoped_task_environment_.RunUntilIdle();
233   PolicyBundle expected_bundle;
234   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
235       .Set(policy_name, test_harness_->policy_level(),
236            test_harness_->policy_scope(), test_harness_->policy_source(),
237            expected_value.CreateDeepCopy(), nullptr);
238   EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
239   // TODO(joaodasilva): set the policy in the POLICY_DOMAIN_EXTENSIONS too,
240   // and extend the |expected_bundle|, once all providers are ready.
241 }
242 
TEST_P(ConfigurationPolicyProviderTest,Empty)243 TEST_P(ConfigurationPolicyProviderTest, Empty) {
244   provider_->RefreshPolicies();
245   scoped_task_environment_.RunUntilIdle();
246   const PolicyBundle kEmptyBundle;
247   EXPECT_TRUE(provider_->policies().Equals(kEmptyBundle));
248 }
249 
TEST_P(ConfigurationPolicyProviderTest,StringValue)250 TEST_P(ConfigurationPolicyProviderTest, StringValue) {
251   const char kTestString[] = "string_value";
252   base::Value expected_value(kTestString);
253   CheckValue(test_keys::kKeyString,
254              expected_value,
255              base::Bind(&PolicyProviderTestHarness::InstallStringPolicy,
256                         base::Unretained(test_harness_.get()),
257                         test_keys::kKeyString,
258                         kTestString));
259 }
260 
TEST_P(ConfigurationPolicyProviderTest,BooleanValue)261 TEST_P(ConfigurationPolicyProviderTest, BooleanValue) {
262   base::Value expected_value(true);
263   CheckValue(test_keys::kKeyBoolean,
264              expected_value,
265              base::Bind(&PolicyProviderTestHarness::InstallBooleanPolicy,
266                         base::Unretained(test_harness_.get()),
267                         test_keys::kKeyBoolean,
268                         true));
269 }
270 
TEST_P(ConfigurationPolicyProviderTest,IntegerValue)271 TEST_P(ConfigurationPolicyProviderTest, IntegerValue) {
272   base::Value expected_value(42);
273   CheckValue(test_keys::kKeyInteger,
274              expected_value,
275              base::Bind(&PolicyProviderTestHarness::InstallIntegerPolicy,
276                         base::Unretained(test_harness_.get()),
277                         test_keys::kKeyInteger,
278                         42));
279 }
280 
TEST_P(ConfigurationPolicyProviderTest,StringListValue)281 TEST_P(ConfigurationPolicyProviderTest, StringListValue) {
282   base::ListValue expected_value;
283   expected_value.AppendString("first");
284   expected_value.AppendString("second");
285   CheckValue(test_keys::kKeyStringList,
286              expected_value,
287              base::Bind(&PolicyProviderTestHarness::InstallStringListPolicy,
288                         base::Unretained(test_harness_.get()),
289                         test_keys::kKeyStringList,
290                         &expected_value));
291 }
292 
TEST_P(ConfigurationPolicyProviderTest,DictionaryValue)293 TEST_P(ConfigurationPolicyProviderTest, DictionaryValue) {
294   base::DictionaryValue expected_value;
295   expected_value.SetBoolean("bool", true);
296   expected_value.SetDouble("double", 123.456);
297   expected_value.SetInteger("int", 123);
298   expected_value.SetString("string", "omg");
299 
300   auto list = std::make_unique<base::ListValue>();
301   list->AppendString("first");
302   list->AppendString("second");
303   expected_value.Set("array", std::move(list));
304 
305   auto dict = std::make_unique<base::DictionaryValue>();
306   dict->SetString("sub", "value");
307   list = std::make_unique<base::ListValue>();
308   auto sub = std::make_unique<base::DictionaryValue>();
309   sub->SetInteger("aaa", 111);
310   sub->SetInteger("bbb", 222);
311   list->Append(std::move(sub));
312   sub = std::make_unique<base::DictionaryValue>();
313   sub->SetString("ccc", "333");
314   sub->SetString("ddd", "444");
315   list->Append(std::move(sub));
316   dict->Set("sublist", std::move(list));
317   expected_value.Set("dictionary", std::move(dict));
318 
319   CheckValue(test_keys::kKeyDictionary,
320              expected_value,
321              base::Bind(&PolicyProviderTestHarness::InstallDictionaryPolicy,
322                         base::Unretained(test_harness_.get()),
323                         test_keys::kKeyDictionary,
324                         &expected_value));
325 }
326 
TEST_P(ConfigurationPolicyProviderTest,RefreshPolicies)327 TEST_P(ConfigurationPolicyProviderTest, RefreshPolicies) {
328   PolicyBundle bundle;
329   EXPECT_TRUE(provider_->policies().Equals(bundle));
330 
331   // OnUpdatePolicy is called even when there are no changes.
332   MockConfigurationPolicyObserver observer;
333   provider_->AddObserver(&observer);
334   EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
335   provider_->RefreshPolicies();
336   scoped_task_environment_.RunUntilIdle();
337   Mock::VerifyAndClearExpectations(&observer);
338 
339   EXPECT_TRUE(provider_->policies().Equals(bundle));
340 
341   // OnUpdatePolicy is called when there are changes.
342   test_harness_->InstallStringPolicy(test_keys::kKeyString, "value");
343   EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
344   provider_->RefreshPolicies();
345   scoped_task_environment_.RunUntilIdle();
346   Mock::VerifyAndClearExpectations(&observer);
347 
348   bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
349       .Set(test_keys::kKeyString, test_harness_->policy_level(),
350            test_harness_->policy_scope(), test_harness_->policy_source(),
351            std::make_unique<base::Value>("value"), nullptr);
352   EXPECT_TRUE(provider_->policies().Equals(bundle));
353   provider_->RemoveObserver(&observer);
354 }
355 
356 Configuration3rdPartyPolicyProviderTest::
Configuration3rdPartyPolicyProviderTest()357     Configuration3rdPartyPolicyProviderTest() {}
358 
359 Configuration3rdPartyPolicyProviderTest::
~Configuration3rdPartyPolicyProviderTest()360     ~Configuration3rdPartyPolicyProviderTest() {}
361 
TEST_P(Configuration3rdPartyPolicyProviderTest,Load3rdParty)362 TEST_P(Configuration3rdPartyPolicyProviderTest, Load3rdParty) {
363   base::DictionaryValue policy_dict;
364   policy_dict.SetBoolean("bool", true);
365   policy_dict.SetDouble("double", 123.456);
366   policy_dict.SetInteger("int", 789);
367   policy_dict.SetString("string", "string value");
368 
369   auto list = std::make_unique<base::ListValue>();
370   for (int i = 0; i < 2; ++i) {
371     auto dict = std::make_unique<base::DictionaryValue>();
372     dict->SetInteger("subdictindex", i);
373     dict->SetKey("subdict", policy_dict.Clone());
374     list->Append(std::move(dict));
375   }
376   policy_dict.Set("list", std::move(list));
377   policy_dict.SetKey("dict", policy_dict.Clone());
378 
379   // Install these policies as a Chrome policy.
380   test_harness_->InstallDictionaryPolicy(test_keys::kKeyDictionary,
381                                          &policy_dict);
382   // Install them as 3rd party policies too.
383   base::DictionaryValue policy_3rdparty;
384   policy_3rdparty.SetPath({"extensions", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
385                           policy_dict.Clone());
386   policy_3rdparty.SetPath({"extensions", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},
387                           policy_dict.Clone());
388   // Install invalid 3rd party policies that shouldn't be loaded. These also
389   // help detecting memory leaks in the code paths that detect invalid input.
390   policy_3rdparty.SetPath({"invalid-domain", "component"}, policy_dict.Clone());
391   policy_3rdparty.SetString("extensions.cccccccccccccccccccccccccccccccc",
392                             "invalid-value");
393   test_harness_->Install3rdPartyPolicy(&policy_3rdparty);
394 
395   provider_->RefreshPolicies();
396   scoped_task_environment_.RunUntilIdle();
397 
398   PolicyMap expected_policy;
399   expected_policy.Set(test_keys::kKeyDictionary, test_harness_->policy_level(),
400                       test_harness_->policy_scope(),
401                       test_harness_->policy_source(),
402                       policy_dict.CreateDeepCopy(), nullptr);
403   PolicyBundle expected_bundle;
404   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
405       .CopyFrom(expected_policy);
406   expected_policy.Clear();
407   expected_policy.LoadFrom(&policy_dict,
408                            test_harness_->policy_level(),
409                            test_harness_->policy_scope(),
410                            test_harness_->policy_source());
411   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
412                                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
413       .CopyFrom(expected_policy);
414   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
415                                       "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
416       .CopyFrom(expected_policy);
417   EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
418 }
419 
420 }  // namespace policy
421