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/policy_bundle.h"
6
7#include "base/callback.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/values.h"
10#include "components/policy/core/common/external_data_fetcher.h"
11#include "components/policy/core/common/policy_map.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace policy {
15
16namespace {
17
18const char kPolicyClashing0[] = "policy-clashing-0";
19const char kPolicyClashing1[] = "policy-clashing-1";
20const char kPolicy0[] = "policy-0";
21const char kPolicy1[] = "policy-1";
22const char kPolicy2[] = "policy-2";
23const char kExtension0[] = "extension-0";
24const char kExtension1[] = "extension-1";
25const char kExtension2[] = "extension-2";
26const char kExtension3[] = "extension-3";
27
28// Adds test policies to |policy|.
29void AddTestPolicies(PolicyMap* policy) {
30  policy->Set("mandatory-user",
31              POLICY_LEVEL_MANDATORY,
32              POLICY_SCOPE_USER,
33              new base::FundamentalValue(123),
34              NULL);
35  policy->Set("mandatory-machine",
36              POLICY_LEVEL_MANDATORY,
37              POLICY_SCOPE_MACHINE,
38              new base::StringValue("omg"),
39              NULL);
40  policy->Set("recommended-user",
41              POLICY_LEVEL_RECOMMENDED,
42              POLICY_SCOPE_USER,
43              new base::FundamentalValue(true),
44              NULL);
45  base::DictionaryValue* dict = new base::DictionaryValue();
46  dict->SetBoolean("false", false);
47  dict->SetInteger("int", 456);
48  dict->SetString("str", "bbq");
49  policy->Set("recommended-machine", POLICY_LEVEL_RECOMMENDED,
50              POLICY_SCOPE_MACHINE, dict, NULL);
51}
52
53// Adds test policies to |policy| based on the parameters:
54// - kPolicyClashing0 mapped to |value|, user mandatory
55// - kPolicyClashing1 mapped to |value|, with |level| and |scope|
56// - |name| mapped to |value|, user mandatory
57void AddTestPoliciesWithParams(PolicyMap *policy,
58                               const char* name,
59                               int value,
60                               PolicyLevel level,
61                               PolicyScope scope) {
62  policy->Set(kPolicyClashing0,
63              POLICY_LEVEL_MANDATORY,
64              POLICY_SCOPE_USER,
65              new base::FundamentalValue(value),
66              NULL);
67  policy->Set(
68      kPolicyClashing1, level, scope, new base::FundamentalValue(value), NULL);
69  policy->Set(name,
70              POLICY_LEVEL_MANDATORY,
71              POLICY_SCOPE_USER,
72              new base::FundamentalValue(value),
73              NULL);
74}
75
76// Returns true if |bundle| is empty.
77bool IsEmpty(const PolicyBundle& bundle) {
78  return bundle.begin() == bundle.end();
79}
80
81}  // namespace
82
83TEST(PolicyBundleTest, Get) {
84  PolicyBundle bundle;
85  EXPECT_TRUE(IsEmpty(bundle));
86
87  AddTestPolicies(&bundle.Get(
88      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
89  EXPECT_FALSE(IsEmpty(bundle));
90
91  PolicyMap policy;
92  AddTestPolicies(&policy);
93  EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
94                                         std::string())).Equals(policy));
95
96  PolicyBundle::const_iterator it = bundle.begin();
97  ASSERT_TRUE(it != bundle.end());
98  EXPECT_EQ(POLICY_DOMAIN_CHROME, it->first.domain);
99  EXPECT_EQ("", it->first.component_id);
100  ASSERT_TRUE(it->second);
101  EXPECT_TRUE(it->second->Equals(policy));
102  ++it;
103  EXPECT_TRUE(it == bundle.end());
104  EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
105                                         kExtension0)).empty());
106
107  EXPECT_FALSE(IsEmpty(bundle));
108  bundle.Clear();
109  EXPECT_TRUE(IsEmpty(bundle));
110}
111
112TEST(PolicyBundleTest, SwapAndCopy) {
113  PolicyBundle bundle0;
114  PolicyBundle bundle1;
115
116  AddTestPolicies(&bundle0.Get(
117      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
118  AddTestPolicies(&bundle0.Get(
119      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
120  EXPECT_FALSE(IsEmpty(bundle0));
121  EXPECT_TRUE(IsEmpty(bundle1));
122
123  PolicyMap policy;
124  AddTestPolicies(&policy);
125  EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
126                                          std::string())).Equals(policy));
127  EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
128                                          kExtension0)).Equals(policy));
129
130  bundle0.Swap(&bundle1);
131  EXPECT_TRUE(IsEmpty(bundle0));
132  EXPECT_FALSE(IsEmpty(bundle1));
133
134  EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
135                                          std::string())).Equals(policy));
136  EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
137                                          kExtension0)).Equals(policy));
138
139  bundle0.CopyFrom(bundle1);
140  EXPECT_FALSE(IsEmpty(bundle0));
141  EXPECT_FALSE(IsEmpty(bundle1));
142  EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
143                                          std::string())).Equals(policy));
144  EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
145                                          kExtension0)).Equals(policy));
146}
147
148TEST(PolicyBundleTest, MergeFrom) {
149  // Each bundleN has kExtensionN. Each bundle also has policy for
150  // chrome and kExtension3.
151  // |bundle0| has the highest priority, |bundle2| the lowest.
152  PolicyBundle bundle0;
153  PolicyBundle bundle1;
154  PolicyBundle bundle2;
155
156  PolicyMap policy0;
157  AddTestPoliciesWithParams(
158      &policy0, kPolicy0, 0u, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER);
159  bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
160      .CopyFrom(policy0);
161  bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0))
162      .CopyFrom(policy0);
163  bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
164      .CopyFrom(policy0);
165
166  PolicyMap policy1;
167  AddTestPoliciesWithParams(
168      &policy1, kPolicy1, 1u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
169  bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
170      .CopyFrom(policy1);
171  bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1))
172      .CopyFrom(policy1);
173  bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
174      .CopyFrom(policy1);
175
176  PolicyMap policy2;
177  AddTestPoliciesWithParams(
178      &policy2, kPolicy2, 2u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
179  bundle2.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
180      .CopyFrom(policy2);
181  bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2))
182      .CopyFrom(policy2);
183  bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
184      .CopyFrom(policy2);
185
186  // Merge in order of decreasing priority.
187  PolicyBundle merged;
188  merged.MergeFrom(bundle0);
189  merged.MergeFrom(bundle1);
190  merged.MergeFrom(bundle2);
191  PolicyBundle empty_bundle;
192  merged.MergeFrom(empty_bundle);
193
194  // chrome and kExtension3 policies are merged:
195  // - kPolicyClashing0 comes from bundle0, which has the highest priority;
196  // - kPolicyClashing1 comes from bundle1, which has the highest level/scope
197  //   combination;
198  // - kPolicyN are merged from each bundle.
199  PolicyMap expected;
200  expected.Set(kPolicyClashing0,
201               POLICY_LEVEL_MANDATORY,
202               POLICY_SCOPE_USER,
203               new base::FundamentalValue(0),
204               NULL);
205  expected.Set(kPolicyClashing1,
206               POLICY_LEVEL_MANDATORY,
207               POLICY_SCOPE_MACHINE,
208               new base::FundamentalValue(1),
209               NULL);
210  expected.Set(kPolicy0,
211               POLICY_LEVEL_MANDATORY,
212               POLICY_SCOPE_USER,
213               new base::FundamentalValue(0),
214               NULL);
215  expected.Set(kPolicy1,
216               POLICY_LEVEL_MANDATORY,
217               POLICY_SCOPE_USER,
218               new base::FundamentalValue(1),
219               NULL);
220  expected.Set(kPolicy2,
221               POLICY_LEVEL_MANDATORY,
222               POLICY_SCOPE_USER,
223               new base::FundamentalValue(2),
224               NULL);
225  EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
226                                         std::string())).Equals(expected));
227  EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
228                                         kExtension3)).Equals(expected));
229  // extension0 comes only from bundle0.
230  EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
231                                         kExtension0)).Equals(policy0));
232  // extension1 comes only from bundle1.
233  EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
234                                         kExtension1)).Equals(policy1));
235  // extension2 comes only from bundle2.
236  EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
237                                         kExtension2)).Equals(policy2));
238}
239
240TEST(PolicyBundleTest, Equals) {
241  PolicyBundle bundle;
242  AddTestPolicies(&bundle.Get(
243      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
244  AddTestPolicies(&bundle.Get(
245      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
246
247  PolicyBundle other;
248  EXPECT_FALSE(bundle.Equals(other));
249  other.CopyFrom(bundle);
250  EXPECT_TRUE(bundle.Equals(other));
251
252  AddTestPolicies(&bundle.Get(
253      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)));
254  EXPECT_FALSE(bundle.Equals(other));
255  other.CopyFrom(bundle);
256  EXPECT_TRUE(bundle.Equals(other));
257  AddTestPolicies(&other.Get(
258      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2)));
259  EXPECT_FALSE(bundle.Equals(other));
260
261  other.CopyFrom(bundle);
262  bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
263      .Set(kPolicy0,
264           POLICY_LEVEL_MANDATORY,
265           POLICY_SCOPE_USER,
266           new base::FundamentalValue(123),
267           NULL);
268  EXPECT_FALSE(bundle.Equals(other));
269  other.CopyFrom(bundle);
270  EXPECT_TRUE(bundle.Equals(other));
271  bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
272      .Set(kPolicy0,
273           POLICY_LEVEL_MANDATORY,
274           POLICY_SCOPE_MACHINE,
275           new base::FundamentalValue(123),
276           NULL);
277  EXPECT_FALSE(bundle.Equals(other));
278
279  // Test non-const Get().
280  bundle.Clear();
281  other.Clear();
282  PolicyMap& policy_map =
283      bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
284  EXPECT_TRUE(bundle.Equals(other));
285  policy_map.Set(kPolicy0,
286                 POLICY_LEVEL_MANDATORY,
287                 POLICY_SCOPE_USER,
288                 new base::FundamentalValue(123),
289                 NULL);
290  EXPECT_FALSE(bundle.Equals(other));
291}
292
293}  // namespace policy
294