OLD | NEW |
| (Empty) |
1 // Copyright (c) 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 "chrome/browser/policy/component_cloud_policy_service.h" | |
6 | |
7 #include "base/files/scoped_temp_dir.h" | |
8 #include "base/message_loop.h" | |
9 #include "base/pickle.h" | |
10 #include "base/run_loop.h" | |
11 #include "base/sha1.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/policy/cloud_policy_constants.h" | |
16 #include "chrome/browser/policy/mock_cloud_policy_client.h" | |
17 #include "chrome/browser/policy/mock_cloud_policy_store.h" | |
18 #include "chrome/browser/policy/policy_builder.h" | |
19 #include "chrome/browser/policy/policy_map.h" | |
20 #include "chrome/browser/policy/policy_types.h" | |
21 #include "chrome/browser/policy/proto/chrome_extension_policy.pb.h" | |
22 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
23 #include "chrome/browser/policy/resource_cache.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 #include "content/public/test/test_browser_thread.h" | |
26 #include "net/url_request/test_url_fetcher_factory.h" | |
27 #include "net/url_request/url_fetcher_delegate.h" | |
28 #include "net/url_request/url_request_context.h" | |
29 #include "net/url_request/url_request_context_getter.h" | |
30 #include "testing/gmock/include/gmock/gmock.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 | |
33 namespace em = enterprise_management; | |
34 | |
35 using testing::Mock; | |
36 | |
37 namespace policy { | |
38 | |
39 namespace { | |
40 | |
41 const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; | |
42 const char kTestExtension2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; | |
43 const char kTestExtension3[] = "cccccccccccccccccccccccccccccccc"; | |
44 const char kTestDownload[] = "http://example.com/getpolicy?id=123"; | |
45 const char kTestDownload2[] = "http://example.com/getpolicy?id=456"; | |
46 const char kTestPolicy[] = | |
47 "{" | |
48 " \"Name\": {" | |
49 " \"Value\": \"disabled\"" | |
50 " }," | |
51 " \"Second\": {" | |
52 " \"Value\": \"maybe\"," | |
53 " \"Level\": \"Recommended\"" | |
54 " }" | |
55 "}"; | |
56 | |
57 class MockComponentCloudPolicyDelegate | |
58 : public ComponentCloudPolicyService::Delegate { | |
59 public: | |
60 virtual ~MockComponentCloudPolicyDelegate() {} | |
61 | |
62 MOCK_METHOD0(OnComponentCloudPolicyRefreshNeeded, void()); | |
63 MOCK_METHOD0(OnComponentCloudPolicyUpdated, void()); | |
64 }; | |
65 | |
66 class TestURLRequestContextGetter : public net::URLRequestContextGetter { | |
67 public: | |
68 explicit TestURLRequestContextGetter( | |
69 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | |
70 : task_runner_(task_runner) {} | |
71 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { | |
72 return NULL; | |
73 } | |
74 virtual scoped_refptr<base::SingleThreadTaskRunner> | |
75 GetNetworkTaskRunner() const OVERRIDE { | |
76 return task_runner_; | |
77 } | |
78 | |
79 private: | |
80 virtual ~TestURLRequestContextGetter() {} | |
81 | |
82 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
83 }; | |
84 | |
85 } // namespace | |
86 | |
87 class ComponentCloudPolicyServiceTest : public testing::Test { | |
88 protected: | |
89 ComponentCloudPolicyServiceTest() | |
90 : ui_thread_(content::BrowserThread::UI, &loop_), | |
91 file_thread_(content::BrowserThread::FILE, &loop_) {} | |
92 | |
93 virtual void SetUp() OVERRIDE { | |
94 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
95 cache_ = new ResourceCache(temp_dir_.path()); | |
96 ASSERT_TRUE(cache_->IsOpen()); | |
97 service_.reset(new ComponentCloudPolicyService( | |
98 &delegate_, &store_, make_scoped_ptr(cache_))); | |
99 | |
100 builder_.policy_data().set_policy_type( | |
101 dm_protocol::kChromeExtensionPolicyType); | |
102 builder_.policy_data().set_settings_entity_id(kTestExtension); | |
103 builder_.payload().set_download_url(kTestDownload); | |
104 builder_.payload().set_secure_hash(base::SHA1HashString(kTestPolicy)); | |
105 | |
106 expected_policy_.Set("Name", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | |
107 base::Value::CreateStringValue("disabled")); | |
108 expected_policy_.Set("Second", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, | |
109 base::Value::CreateStringValue("maybe")); | |
110 | |
111 // A NULL |request_context_| is enough to construct the updater, but | |
112 // ComponentCloudPolicyService::Backend::LoadStore() tests the pointer when | |
113 // Connect() is called before the store was loaded. | |
114 request_context_ = | |
115 new TestURLRequestContextGetter(loop_.message_loop_proxy()); | |
116 } | |
117 | |
118 virtual void TearDown() OVERRIDE { | |
119 // The service cleans up its backend on the FILE thread. | |
120 service_.reset(); | |
121 RunUntilIdle(); | |
122 } | |
123 | |
124 void RunUntilIdle() { | |
125 base::RunLoop().RunUntilIdle(); | |
126 } | |
127 | |
128 void LoadStore() { | |
129 EXPECT_FALSE(store_.is_initialized()); | |
130 EXPECT_FALSE(service_->is_initialized()); | |
131 | |
132 em::PolicyData* data = new em::PolicyData(); | |
133 data->set_username(ComponentPolicyBuilder::kFakeUsername); | |
134 data->set_request_token(ComponentPolicyBuilder::kFakeToken); | |
135 store_.policy_.reset(data); | |
136 | |
137 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
138 store_.NotifyStoreLoaded(); | |
139 RunUntilIdle(); | |
140 Mock::VerifyAndClearExpectations(&delegate_); | |
141 EXPECT_TRUE(service_->is_initialized()); | |
142 } | |
143 | |
144 void PopulateCache() { | |
145 Pickle pickle; | |
146 pickle.WriteString(kTestExtension); | |
147 pickle.WriteString(kTestExtension2); | |
148 std::string data(reinterpret_cast<const char*>(pickle.data()), | |
149 pickle.size()); | |
150 EXPECT_TRUE( | |
151 cache_->Store(ComponentCloudPolicyService::kComponentNamespaceCache, | |
152 dm_protocol::kChromeExtensionPolicyType, | |
153 data)); | |
154 | |
155 EXPECT_TRUE(cache_->Store( | |
156 "extension-policy", kTestExtension, CreateSerializedResponse())); | |
157 EXPECT_TRUE( | |
158 cache_->Store("extension-policy-data", kTestExtension, kTestPolicy)); | |
159 | |
160 builder_.policy_data().set_settings_entity_id(kTestExtension2); | |
161 EXPECT_TRUE(cache_->Store( | |
162 "extension-policy", kTestExtension2, CreateSerializedResponse())); | |
163 EXPECT_TRUE( | |
164 cache_->Store("extension-policy-data", kTestExtension2, kTestPolicy)); | |
165 | |
166 EXPECT_TRUE(cache_->Store("unrelated", "stuff", "here")); | |
167 } | |
168 | |
169 scoped_ptr<em::PolicyFetchResponse> CreateResponse() { | |
170 builder_.Build(); | |
171 return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy())); | |
172 } | |
173 | |
174 std::string CreateSerializedResponse() { | |
175 builder_.Build(); | |
176 return builder_.GetBlob(); | |
177 } | |
178 | |
179 MessageLoop loop_; | |
180 content::TestBrowserThread ui_thread_; | |
181 content::TestBrowserThread file_thread_; | |
182 base::ScopedTempDir temp_dir_; | |
183 scoped_refptr<TestURLRequestContextGetter> request_context_; | |
184 net::TestURLFetcherFactory fetcher_factory_; | |
185 MockComponentCloudPolicyDelegate delegate_; | |
186 // |cache_| is owned by the |service_| and is invalid once the |service_| | |
187 // is destroyed. | |
188 ResourceCache* cache_; | |
189 MockCloudPolicyClient client_; | |
190 MockCloudPolicyStore store_; | |
191 scoped_ptr<ComponentCloudPolicyService> service_; | |
192 ComponentPolicyBuilder builder_; | |
193 PolicyMap expected_policy_; | |
194 }; | |
195 | |
196 TEST_F(ComponentCloudPolicyServiceTest, InitializeWithoutCredentials) { | |
197 EXPECT_FALSE(service_->is_initialized()); | |
198 // Run the background task to initialize the backend. | |
199 RunUntilIdle(); | |
200 // Still waiting for the |store_|. | |
201 EXPECT_FALSE(service_->is_initialized()); | |
202 | |
203 // Initialize with a store without credentials. | |
204 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
205 store_.NotifyStoreLoaded(); | |
206 RunUntilIdle(); | |
207 EXPECT_TRUE(service_->is_initialized()); | |
208 Mock::VerifyAndClearExpectations(&delegate_); | |
209 const PolicyBundle empty_bundle; | |
210 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); | |
211 } | |
212 | |
213 TEST_F(ComponentCloudPolicyServiceTest, InitializationWithCachedComponents) { | |
214 // Store a previous list of components. | |
215 Pickle pickle; | |
216 pickle.WriteString("aa"); | |
217 pickle.WriteString("bb"); | |
218 pickle.WriteString("cc"); | |
219 std::string data(reinterpret_cast<const char*>(pickle.data()), pickle.size()); | |
220 EXPECT_TRUE( | |
221 cache_->Store(ComponentCloudPolicyService::kComponentNamespaceCache, | |
222 dm_protocol::kChromeExtensionPolicyType, | |
223 data)); | |
224 // Store some garbage in another domain; it won't be fetched. | |
225 EXPECT_TRUE(cache_->Store( | |
226 ComponentCloudPolicyService::kComponentNamespaceCache, "garbage", data)); | |
227 | |
228 // Connect a client before initialization is complete. | |
229 service_->Connect(&client_, request_context_); | |
230 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); | |
231 | |
232 // Now load the backend. | |
233 LoadStore(); | |
234 | |
235 // The cached namespaces were added to the client. | |
236 std::set<PolicyNamespaceKey> set; | |
237 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "aa")); | |
238 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "bb")); | |
239 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "cc")); | |
240 EXPECT_EQ(set, client_.namespaces_to_fetch_); | |
241 | |
242 // And the bad components were wiped from the cache. | |
243 std::map<std::string, std::string> contents; | |
244 cache_->LoadAllSubkeys(ComponentCloudPolicyService::kComponentNamespaceCache, | |
245 &contents); | |
246 ASSERT_EQ(1u, contents.size()); | |
247 EXPECT_EQ(std::string(dm_protocol::kChromeExtensionPolicyType), | |
248 contents.begin()->first); | |
249 } | |
250 | |
251 TEST_F(ComponentCloudPolicyServiceTest, ConnectAfterRegister) { | |
252 // Add some components. | |
253 std::set<std::string> components; | |
254 components.insert(kTestExtension); | |
255 components.insert(kTestExtension2); | |
256 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, components); | |
257 | |
258 // Now connect the client. | |
259 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); | |
260 service_->Connect(&client_, request_context_); | |
261 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); | |
262 | |
263 // It receives the namespaces once the backend is initialized. | |
264 LoadStore(); | |
265 std::set<PolicyNamespaceKey> set; | |
266 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
267 kTestExtension)); | |
268 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
269 kTestExtension2)); | |
270 EXPECT_EQ(set, client_.namespaces_to_fetch_); | |
271 | |
272 // The current components were also persisted to the cache. | |
273 std::map<std::string, std::string> contents; | |
274 cache_->LoadAllSubkeys(ComponentCloudPolicyService::kComponentNamespaceCache, | |
275 &contents); | |
276 ASSERT_EQ(1u, contents.size()); | |
277 EXPECT_EQ(std::string(dm_protocol::kChromeExtensionPolicyType), | |
278 contents.begin()->first); | |
279 const std::string data(contents.begin()->second); | |
280 Pickle pickle(data.data(), data.size()); | |
281 PickleIterator pickit(pickle); | |
282 std::string value0; | |
283 std::string value1; | |
284 std::string tmp; | |
285 ASSERT_TRUE(pickit.ReadString(&value0)); | |
286 ASSERT_TRUE(pickit.ReadString(&value1)); | |
287 EXPECT_FALSE(pickit.ReadString(&tmp)); | |
288 std::set<std::string> unpickled; | |
289 unpickled.insert(value0); | |
290 unpickled.insert(value1); | |
291 EXPECT_EQ(components, unpickled); | |
292 } | |
293 | |
294 TEST_F(ComponentCloudPolicyServiceTest, StoreReadyAfterConnectAndRegister) { | |
295 // Add some previous data to the cache. | |
296 PopulateCache(); | |
297 | |
298 // Add some components. | |
299 std::set<std::string> components; | |
300 components.insert(kTestExtension); | |
301 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, components); | |
302 | |
303 // And connect the client. Make the client have some policies, with a new | |
304 // download_url. | |
305 builder_.payload().set_download_url(kTestDownload2); | |
306 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
307 kTestExtension), | |
308 *CreateResponse()); | |
309 service_->Connect(&client_, request_context_); | |
310 | |
311 // Now make the store ready. | |
312 LoadStore(); | |
313 | |
314 // The components that were registed before have their caches purged. | |
315 std::map<std::string, std::string> contents; | |
316 cache_->LoadAllSubkeys("extension-policy", &contents); | |
317 EXPECT_EQ(1u, contents.size()); // kTestExtension2 was purged. | |
318 EXPECT_TRUE(ContainsKey(contents, kTestExtension)); | |
319 cache_->LoadAllSubkeys("unrelated", &contents); | |
320 EXPECT_EQ(1u, contents.size()); // unrelated keys are not purged. | |
321 EXPECT_TRUE(ContainsKey(contents, "stuff")); | |
322 | |
323 // The policy responses that the client already had start updating. | |
324 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); | |
325 ASSERT_TRUE(fetcher); | |
326 // Expect the URL of the client's PolicyFetchResponse, not the cached URL. | |
327 EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL()); | |
328 } | |
329 | |
330 TEST_F(ComponentCloudPolicyServiceTest, ConnectThenRegisterThenStoreReady) { | |
331 // Connect right after creating the service. | |
332 service_->Connect(&client_, request_context_); | |
333 | |
334 // Now register the current components, before the backend has been | |
335 // initialized. | |
336 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); | |
337 std::set<std::string> components; | |
338 components.insert(kTestExtension); | |
339 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, components); | |
340 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); | |
341 | |
342 // Now load the store. The client gets the namespaces. | |
343 LoadStore(); | |
344 std::set<PolicyNamespaceKey> set; | |
345 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
346 kTestExtension)); | |
347 EXPECT_EQ(set, client_.namespaces_to_fetch_); | |
348 } | |
349 | |
350 TEST_F(ComponentCloudPolicyServiceTest, FetchPolicy) { | |
351 // Initialize the store and create the backend, and connect the client. | |
352 LoadStore(); | |
353 // A refresh is not needed, because no components were found. | |
354 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()).Times(0); | |
355 service_->Connect(&client_, request_context_); | |
356 Mock::VerifyAndClearExpectations(&delegate_); | |
357 | |
358 // Register the components to fetch. | |
359 std::set<std::string> components; | |
360 components.insert(kTestExtension); | |
361 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); | |
362 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, components); | |
363 Mock::VerifyAndClearExpectations(&delegate_); | |
364 | |
365 // Send back a fake policy fetch response. | |
366 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
367 kTestExtension), | |
368 *CreateResponse()); | |
369 service_->OnPolicyFetched(&client_); | |
370 RunUntilIdle(); | |
371 | |
372 // That should have triggered the download fetch. | |
373 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); | |
374 ASSERT_TRUE(fetcher); | |
375 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); | |
376 fetcher->set_response_code(200); | |
377 fetcher->SetResponseString(kTestPolicy); | |
378 fetcher->delegate()->OnURLFetchComplete(fetcher); | |
379 | |
380 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
381 RunUntilIdle(); | |
382 Mock::VerifyAndClearExpectations(&delegate_); | |
383 | |
384 // The policy is now being served. | |
385 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); | |
386 PolicyBundle expected_bundle; | |
387 expected_bundle.Get(ns).CopyFrom(expected_policy_); | |
388 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); | |
389 } | |
390 | |
391 TEST_F(ComponentCloudPolicyServiceTest, LoadAndPurgeCache) { | |
392 // Insert data in the cache. | |
393 PopulateCache(); | |
394 | |
395 // Load the initial cache. | |
396 LoadStore(); | |
397 | |
398 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); | |
399 service_->Connect(&client_, request_context_); | |
400 Mock::VerifyAndClearExpectations(&delegate_); | |
401 | |
402 PolicyBundle expected_bundle; | |
403 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); | |
404 expected_bundle.Get(ns).CopyFrom(expected_policy_); | |
405 ns.component_id = kTestExtension2; | |
406 expected_bundle.Get(ns).CopyFrom(expected_policy_); | |
407 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); | |
408 | |
409 // Now purge one of the extensions. | |
410 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
411 // The service will start updating the components that are registered, which | |
412 // starts by fetching policy for them. | |
413 std::set<std::string> keep; | |
414 keep.insert(kTestExtension2); | |
415 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, keep); | |
416 RunUntilIdle(); | |
417 Mock::VerifyAndClearExpectations(&delegate_); | |
418 | |
419 ns.component_id = kTestExtension; | |
420 expected_bundle.Get(ns).Clear(); | |
421 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); | |
422 | |
423 std::map<std::string, std::string> contents; | |
424 cache_->LoadAllSubkeys("extension-policy", &contents); | |
425 EXPECT_EQ(1u, contents.size()); | |
426 EXPECT_TRUE(ContainsKey(contents, kTestExtension2)); | |
427 cache_->LoadAllSubkeys("unrelated", &contents); | |
428 EXPECT_EQ(1u, contents.size()); | |
429 EXPECT_TRUE(ContainsKey(contents, "stuff")); | |
430 } | |
431 | |
432 TEST_F(ComponentCloudPolicyServiceTest, UpdateCredentials) { | |
433 // Do the same as LoadStore() but without the initial credentials. | |
434 EXPECT_FALSE(store_.is_initialized()); | |
435 EXPECT_FALSE(service_->is_initialized()); | |
436 store_.policy_.reset(new em::PolicyData()); // No credentials. | |
437 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
438 store_.NotifyStoreLoaded(); | |
439 RunUntilIdle(); | |
440 Mock::VerifyAndClearExpectations(&delegate_); | |
441 EXPECT_TRUE(service_->is_initialized()); | |
442 | |
443 // Connect the client and register an extension. | |
444 service_->Connect(&client_, request_context_); | |
445 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); | |
446 std::set<std::string> components; | |
447 components.insert(kTestExtension); | |
448 service_->RegisterPolicyDomain(POLICY_DOMAIN_EXTENSIONS, components); | |
449 Mock::VerifyAndClearExpectations(&delegate_); | |
450 | |
451 // Send the response to the service. The response data will be rejected, | |
452 // because the store doesn't have the updated credentials yet. | |
453 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, | |
454 kTestExtension), | |
455 *CreateResponse()); | |
456 service_->OnPolicyFetched(&client_); | |
457 RunUntilIdle(); | |
458 | |
459 // The policy was not verified, and no download is started. | |
460 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); | |
461 EXPECT_FALSE(fetcher); | |
462 | |
463 // Now update the |store_| with the updated policy, which includes | |
464 // credentials. The responses in the |client_| will be reloaded. | |
465 em::PolicyData* data = new em::PolicyData(); | |
466 data->set_username(ComponentPolicyBuilder::kFakeUsername); | |
467 data->set_request_token(ComponentPolicyBuilder::kFakeToken); | |
468 store_.policy_.reset(data); | |
469 store_.NotifyStoreLoaded(); | |
470 RunUntilIdle(); | |
471 | |
472 // The extension policy was validated this time, and the download is started. | |
473 fetcher = fetcher_factory_.GetFetcherByID(0); | |
474 ASSERT_TRUE(fetcher); | |
475 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); | |
476 fetcher->set_response_code(200); | |
477 fetcher->SetResponseString(kTestPolicy); | |
478 fetcher->delegate()->OnURLFetchComplete(fetcher); | |
479 | |
480 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); | |
481 RunUntilIdle(); | |
482 Mock::VerifyAndClearExpectations(&delegate_); | |
483 | |
484 // The policy is now being served. | |
485 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); | |
486 PolicyBundle expected_bundle; | |
487 expected_bundle.Get(ns).CopyFrom(expected_policy_); | |
488 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); | |
489 } | |
490 | |
491 } // namespace policy | |
OLD | NEW |