1 // Copyright 2015 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.
5 #include "base/basictypes.h"
7 #include "base/json/json_writer.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "components/policy/core/common/fake_async_policy_loader.h"
12 #include "policy/policy_constants.h"
13 #include "remoting/host/dns_blackhole_checker.h"
14 #include "remoting/host/policy_watcher.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
20 MATCHER_P(IsPolicies
, dict
, "") {
21 bool equal
= arg
->Equals(dict
);
23 std::string actual_value
;
24 base::JSONWriter::WriteWithOptions(
25 arg
, base::JSONWriter::OPTIONS_PRETTY_PRINT
, &actual_value
);
27 std::string expected_value
;
28 base::JSONWriter::WriteWithOptions(
29 dict
, base::JSONWriter::OPTIONS_PRETTY_PRINT
, &expected_value
);
31 *result_listener
<< "Policies are not equal. ";
32 *result_listener
<< "Expected policy: " << expected_value
<< ". ";
33 *result_listener
<< "Actual policy: " << actual_value
<< ".";
38 class MockPolicyCallback
{
40 MockPolicyCallback(){};
42 // TODO(lukasza): gmock cannot mock a method taking scoped_ptr<T>...
43 MOCK_METHOD1(OnPolicyUpdatePtr
, void(const base::DictionaryValue
* policies
));
44 void OnPolicyUpdate(scoped_ptr
<base::DictionaryValue
> policies
) {
45 OnPolicyUpdatePtr(policies
.get());
48 MOCK_METHOD0(OnPolicyError
, void());
51 DISALLOW_COPY_AND_ASSIGN(MockPolicyCallback
);
54 class PolicyWatcherTest
: public testing::Test
{
56 PolicyWatcherTest() : message_loop_(base::MessageLoop::TYPE_IO
) {}
58 void SetUp() override
{
59 message_loop_proxy_
= base::MessageLoopProxy::current();
61 // Retaining a raw pointer to keep control over policy contents.
62 policy_loader_
= new policy::FakeAsyncPolicyLoader(message_loop_proxy_
);
64 PolicyWatcher::CreateFromPolicyLoader(make_scoped_ptr(policy_loader_
));
66 schema_
= policy::Schema::Wrap(policy::GetChromeSchemaData());
68 nat_true_
.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal
, true);
69 nat_false_
.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal
,
71 nat_one_
.SetInteger(policy::key::kRemoteAccessHostFirewallTraversal
, 1);
72 domain_empty_
.SetString(policy::key::kRemoteAccessHostDomain
,
74 domain_full_
.SetString(policy::key::kRemoteAccessHostDomain
, kHostDomain
);
75 SetDefaults(nat_true_others_default_
);
76 nat_true_others_default_
.SetBoolean(
77 policy::key::kRemoteAccessHostFirewallTraversal
, true);
78 SetDefaults(nat_false_others_default_
);
79 nat_false_others_default_
.SetBoolean(
80 policy::key::kRemoteAccessHostFirewallTraversal
, false);
81 SetDefaults(domain_empty_others_default_
);
82 domain_empty_others_default_
.SetString(policy::key::kRemoteAccessHostDomain
,
84 SetDefaults(domain_full_others_default_
);
85 domain_full_others_default_
.SetString(policy::key::kRemoteAccessHostDomain
,
87 nat_true_domain_empty_
.SetBoolean(
88 policy::key::kRemoteAccessHostFirewallTraversal
, true);
89 nat_true_domain_empty_
.SetString(policy::key::kRemoteAccessHostDomain
,
91 nat_true_domain_full_
.SetBoolean(
92 policy::key::kRemoteAccessHostFirewallTraversal
, true);
93 nat_true_domain_full_
.SetString(policy::key::kRemoteAccessHostDomain
,
95 nat_false_domain_empty_
.SetBoolean(
96 policy::key::kRemoteAccessHostFirewallTraversal
, false);
97 nat_false_domain_empty_
.SetString(policy::key::kRemoteAccessHostDomain
,
99 nat_false_domain_full_
.SetBoolean(
100 policy::key::kRemoteAccessHostFirewallTraversal
, false);
101 nat_false_domain_full_
.SetString(policy::key::kRemoteAccessHostDomain
,
103 SetDefaults(nat_true_domain_empty_others_default_
);
104 nat_true_domain_empty_others_default_
.SetBoolean(
105 policy::key::kRemoteAccessHostFirewallTraversal
, true);
106 nat_true_domain_empty_others_default_
.SetString(
107 policy::key::kRemoteAccessHostDomain
, std::string());
108 unknown_policies_
.SetString("UnknownPolicyOne", std::string());
109 unknown_policies_
.SetString("UnknownPolicyTwo", std::string());
111 const char kOverrideNatTraversalToFalse
[] =
112 "{ \"RemoteAccessHostFirewallTraversal\": false }";
113 nat_true_and_overridden_
.SetBoolean(
114 policy::key::kRemoteAccessHostFirewallTraversal
, true);
115 nat_true_and_overridden_
.SetString(
116 policy::key::kRemoteAccessHostDebugOverridePolicies
,
117 kOverrideNatTraversalToFalse
);
118 pairing_true_
.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing
,
120 pairing_false_
.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing
,
122 gnubby_auth_true_
.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth
,
124 gnubby_auth_false_
.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth
,
126 relay_true_
.SetBoolean(policy::key::kRemoteAccessHostAllowRelayedConnection
,
128 relay_false_
.SetBoolean(
129 policy::key::kRemoteAccessHostAllowRelayedConnection
, false);
130 port_range_full_
.SetString(policy::key::kRemoteAccessHostUdpPortRange
,
132 port_range_empty_
.SetString(policy::key::kRemoteAccessHostUdpPortRange
,
136 SetDefaults(nat_false_overridden_others_default_
);
137 nat_false_overridden_others_default_
.SetBoolean(
138 policy::key::kRemoteAccessHostFirewallTraversal
, false);
139 nat_false_overridden_others_default_
.SetString(
140 policy::key::kRemoteAccessHostDebugOverridePolicies
,
141 kOverrideNatTraversalToFalse
);
145 void TearDown() override
{
146 policy_watcher_
.reset();
147 policy_loader_
= nullptr;
148 base::RunLoop().RunUntilIdle();
152 void StartWatching() {
153 policy_watcher_
->StartWatching(
154 base::Bind(&MockPolicyCallback::OnPolicyUpdate
,
155 base::Unretained(&mock_policy_callback_
)),
156 base::Bind(&MockPolicyCallback::OnPolicyError
,
157 base::Unretained(&mock_policy_callback_
)));
158 base::RunLoop().RunUntilIdle();
161 void SetPolicies(const base::DictionaryValue
& dict
) {
162 // Copy |dict| into |policy_bundle|.
163 policy::PolicyNamespace policy_namespace
=
164 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME
, std::string());
165 policy::PolicyBundle policy_bundle
;
166 policy::PolicyMap
& policy_map
= policy_bundle
.Get(policy_namespace
);
167 policy_map
.LoadFrom(&dict
, policy::POLICY_LEVEL_MANDATORY
,
168 policy::POLICY_SCOPE_MACHINE
);
170 // Simulate a policy file/registry/preference update.
171 policy_loader_
->SetPolicies(policy_bundle
);
172 policy_loader_
->PostReloadOnBackgroundThread(true /* force reload asap */);
173 base::RunLoop().RunUntilIdle();
176 void SignalTransientErrorForTest() {
177 policy_watcher_
->SignalTransientPolicyError();
180 const policy::Schema
* GetPolicySchema() { return &schema_
; }
182 const base::DictionaryValue
& GetDefaultValues() {
183 return *(policy_watcher_
->default_values_
);
186 MOCK_METHOD0(PostPolicyWatcherShutdown
, void());
188 static const char* kHostDomain
;
189 static const char* kPortRange
;
190 base::MessageLoop message_loop_
;
191 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
192 MockPolicyCallback mock_policy_callback_
;
194 // |policy_loader_| is owned by |policy_watcher_|. PolicyWatcherTest retains
195 // a raw pointer to |policy_loader_| in order to control the simulated / faked
197 policy::FakeAsyncPolicyLoader
* policy_loader_
;
198 scoped_ptr
<PolicyWatcher
> policy_watcher_
;
200 base::DictionaryValue empty_
;
201 base::DictionaryValue nat_true_
;
202 base::DictionaryValue nat_false_
;
203 base::DictionaryValue nat_one_
;
204 base::DictionaryValue domain_empty_
;
205 base::DictionaryValue domain_full_
;
206 base::DictionaryValue nat_true_others_default_
;
207 base::DictionaryValue nat_false_others_default_
;
208 base::DictionaryValue domain_empty_others_default_
;
209 base::DictionaryValue domain_full_others_default_
;
210 base::DictionaryValue nat_true_domain_empty_
;
211 base::DictionaryValue nat_true_domain_full_
;
212 base::DictionaryValue nat_false_domain_empty_
;
213 base::DictionaryValue nat_false_domain_full_
;
214 base::DictionaryValue nat_true_domain_empty_others_default_
;
215 base::DictionaryValue unknown_policies_
;
216 base::DictionaryValue nat_true_and_overridden_
;
217 base::DictionaryValue nat_false_overridden_others_default_
;
218 base::DictionaryValue pairing_true_
;
219 base::DictionaryValue pairing_false_
;
220 base::DictionaryValue gnubby_auth_true_
;
221 base::DictionaryValue gnubby_auth_false_
;
222 base::DictionaryValue relay_true_
;
223 base::DictionaryValue relay_false_
;
224 base::DictionaryValue port_range_full_
;
225 base::DictionaryValue port_range_empty_
;
227 policy::Schema schema_
;
230 void SetDefaults(base::DictionaryValue
& dict
) {
231 dict
.SetBoolean(policy::key::kRemoteAccessHostFirewallTraversal
, true);
232 dict
.SetBoolean(policy::key::kRemoteAccessHostAllowRelayedConnection
, true);
233 dict
.SetString(policy::key::kRemoteAccessHostUdpPortRange
, "");
234 dict
.SetString(policy::key::kRemoteAccessHostDomain
, std::string());
235 dict
.SetBoolean(policy::key::kRemoteAccessHostMatchUsername
, false);
236 dict
.SetString(policy::key::kRemoteAccessHostTalkGadgetPrefix
,
237 kDefaultHostTalkGadgetPrefix
);
238 dict
.SetBoolean(policy::key::kRemoteAccessHostRequireCurtain
, false);
239 dict
.SetString(policy::key::kRemoteAccessHostTokenUrl
, std::string());
240 dict
.SetString(policy::key::kRemoteAccessHostTokenValidationUrl
,
243 policy::key::kRemoteAccessHostTokenValidationCertificateIssuer
,
245 dict
.SetBoolean(policy::key::kRemoteAccessHostAllowClientPairing
, true);
246 dict
.SetBoolean(policy::key::kRemoteAccessHostAllowGnubbyAuth
, true);
248 dict
.SetString(policy::key::kRemoteAccessHostDebugOverridePolicies
, "");
251 ASSERT_THAT(&dict
, IsPolicies(&GetDefaultValues()))
252 << "Sanity check that defaults expected by the test code "
253 << "match what is stored in PolicyWatcher::default_values_";
257 const char* PolicyWatcherTest::kHostDomain
= "google.com";
258 const char* PolicyWatcherTest::kPortRange
= "12400-12409";
260 TEST_F(PolicyWatcherTest
, None
) {
261 EXPECT_CALL(mock_policy_callback_
,
262 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
268 TEST_F(PolicyWatcherTest
, NatTrue
) {
269 EXPECT_CALL(mock_policy_callback_
,
270 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
272 SetPolicies(nat_true_
);
276 TEST_F(PolicyWatcherTest
, NatFalse
) {
277 EXPECT_CALL(mock_policy_callback_
,
278 OnPolicyUpdatePtr(IsPolicies(&nat_false_others_default_
)));
280 SetPolicies(nat_false_
);
284 TEST_F(PolicyWatcherTest
, NatOne
) {
285 EXPECT_CALL(mock_policy_callback_
,
286 OnPolicyUpdatePtr(IsPolicies(&nat_false_others_default_
)));
288 SetPolicies(nat_one_
);
292 TEST_F(PolicyWatcherTest
, DomainEmpty
) {
293 EXPECT_CALL(mock_policy_callback_
,
294 OnPolicyUpdatePtr(IsPolicies(&domain_empty_others_default_
)));
296 SetPolicies(domain_empty_
);
300 TEST_F(PolicyWatcherTest
, DomainFull
) {
301 EXPECT_CALL(mock_policy_callback_
,
302 OnPolicyUpdatePtr(IsPolicies(&domain_full_others_default_
)));
304 SetPolicies(domain_full_
);
308 TEST_F(PolicyWatcherTest
, NatNoneThenTrue
) {
309 EXPECT_CALL(mock_policy_callback_
,
310 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
314 SetPolicies(nat_true_
);
317 TEST_F(PolicyWatcherTest
, NatNoneThenTrueThenTrue
) {
318 EXPECT_CALL(mock_policy_callback_
,
319 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
323 SetPolicies(nat_true_
);
324 SetPolicies(nat_true_
);
327 TEST_F(PolicyWatcherTest
, NatNoneThenTrueThenTrueThenFalse
) {
328 testing::InSequence sequence
;
329 EXPECT_CALL(mock_policy_callback_
,
330 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
331 EXPECT_CALL(mock_policy_callback_
,
332 OnPolicyUpdatePtr(IsPolicies(&nat_false_
)));
336 SetPolicies(nat_true_
);
337 SetPolicies(nat_true_
);
338 SetPolicies(nat_false_
);
341 TEST_F(PolicyWatcherTest
, NatNoneThenFalse
) {
342 testing::InSequence sequence
;
343 EXPECT_CALL(mock_policy_callback_
,
344 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
345 EXPECT_CALL(mock_policy_callback_
,
346 OnPolicyUpdatePtr(IsPolicies(&nat_false_
)));
350 SetPolicies(nat_false_
);
353 TEST_F(PolicyWatcherTest
, NatNoneThenFalseThenTrue
) {
354 testing::InSequence sequence
;
355 EXPECT_CALL(mock_policy_callback_
,
356 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
357 EXPECT_CALL(mock_policy_callback_
,
358 OnPolicyUpdatePtr(IsPolicies(&nat_false_
)));
359 EXPECT_CALL(mock_policy_callback_
, OnPolicyUpdatePtr(IsPolicies(&nat_true_
)));
363 SetPolicies(nat_false_
);
364 SetPolicies(nat_true_
);
367 TEST_F(PolicyWatcherTest
, ChangeOneRepeatedlyThenTwo
) {
368 testing::InSequence sequence
;
370 mock_policy_callback_
,
371 OnPolicyUpdatePtr(IsPolicies(&nat_true_domain_empty_others_default_
)));
372 EXPECT_CALL(mock_policy_callback_
,
373 OnPolicyUpdatePtr(IsPolicies(&domain_full_
)));
374 EXPECT_CALL(mock_policy_callback_
,
375 OnPolicyUpdatePtr(IsPolicies(&nat_false_
)));
376 EXPECT_CALL(mock_policy_callback_
,
377 OnPolicyUpdatePtr(IsPolicies(&domain_empty_
)));
378 EXPECT_CALL(mock_policy_callback_
,
379 OnPolicyUpdatePtr(IsPolicies(&nat_true_domain_full_
)));
381 SetPolicies(nat_true_domain_empty_
);
383 SetPolicies(nat_true_domain_full_
);
384 SetPolicies(nat_false_domain_full_
);
385 SetPolicies(nat_false_domain_empty_
);
386 SetPolicies(nat_true_domain_full_
);
389 TEST_F(PolicyWatcherTest
, FilterUnknownPolicies
) {
390 testing::InSequence sequence
;
391 EXPECT_CALL(mock_policy_callback_
,
392 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
396 SetPolicies(unknown_policies_
);
400 TEST_F(PolicyWatcherTest
, DebugOverrideNatPolicy
) {
403 mock_policy_callback_
,
404 OnPolicyUpdatePtr(IsPolicies(&nat_false_overridden_others_default_
)));
406 EXPECT_CALL(mock_policy_callback_
,
407 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
410 SetPolicies(nat_true_and_overridden_
);
414 TEST_F(PolicyWatcherTest
, PairingFalseThenTrue
) {
415 testing::InSequence sequence
;
416 EXPECT_CALL(mock_policy_callback_
,
417 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
418 EXPECT_CALL(mock_policy_callback_
,
419 OnPolicyUpdatePtr(IsPolicies(&pairing_false_
)));
420 EXPECT_CALL(mock_policy_callback_
,
421 OnPolicyUpdatePtr(IsPolicies(&pairing_true_
)));
425 SetPolicies(pairing_false_
);
426 SetPolicies(pairing_true_
);
429 TEST_F(PolicyWatcherTest
, GnubbyAuth
) {
430 testing::InSequence sequence
;
431 EXPECT_CALL(mock_policy_callback_
,
432 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
433 EXPECT_CALL(mock_policy_callback_
,
434 OnPolicyUpdatePtr(IsPolicies(&gnubby_auth_false_
)));
435 EXPECT_CALL(mock_policy_callback_
,
436 OnPolicyUpdatePtr(IsPolicies(&gnubby_auth_true_
)));
440 SetPolicies(gnubby_auth_false_
);
441 SetPolicies(gnubby_auth_true_
);
444 TEST_F(PolicyWatcherTest
, Relay
) {
445 testing::InSequence sequence
;
446 EXPECT_CALL(mock_policy_callback_
,
447 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
448 EXPECT_CALL(mock_policy_callback_
,
449 OnPolicyUpdatePtr(IsPolicies(&relay_false_
)));
450 EXPECT_CALL(mock_policy_callback_
,
451 OnPolicyUpdatePtr(IsPolicies(&relay_true_
)));
455 SetPolicies(relay_false_
);
456 SetPolicies(relay_true_
);
459 TEST_F(PolicyWatcherTest
, UdpPortRange
) {
460 testing::InSequence sequence
;
461 EXPECT_CALL(mock_policy_callback_
,
462 OnPolicyUpdatePtr(IsPolicies(&nat_true_others_default_
)));
463 EXPECT_CALL(mock_policy_callback_
,
464 OnPolicyUpdatePtr(IsPolicies(&port_range_full_
)));
465 EXPECT_CALL(mock_policy_callback_
,
466 OnPolicyUpdatePtr(IsPolicies(&port_range_empty_
)));
470 SetPolicies(port_range_full_
);
471 SetPolicies(port_range_empty_
);
474 const int kMaxTransientErrorRetries
= 5;
476 TEST_F(PolicyWatcherTest
, SingleTransientErrorDoesntTriggerErrorCallback
) {
477 EXPECT_CALL(mock_policy_callback_
, OnPolicyError()).Times(0);
480 SignalTransientErrorForTest();
483 TEST_F(PolicyWatcherTest
, MultipleTransientErrorsTriggerErrorCallback
) {
484 EXPECT_CALL(mock_policy_callback_
, OnPolicyError());
487 for (int i
= 0; i
< kMaxTransientErrorRetries
; i
++) {
488 SignalTransientErrorForTest();
492 TEST_F(PolicyWatcherTest
, PolicyUpdateResetsTransientErrorsCounter
) {
493 testing::InSequence s
;
494 EXPECT_CALL(mock_policy_callback_
, OnPolicyUpdatePtr(testing::_
));
495 EXPECT_CALL(mock_policy_callback_
, OnPolicyError()).Times(0);
498 for (int i
= 0; i
< (kMaxTransientErrorRetries
- 1); i
++) {
499 SignalTransientErrorForTest();
501 SetPolicies(nat_true_
);
502 for (int i
= 0; i
< (kMaxTransientErrorRetries
- 1); i
++) {
503 SignalTransientErrorForTest();
507 TEST_F(PolicyWatcherTest
, PolicySchemaAndPolicyWatcherShouldBeInSync
) {
508 // This test verifies that
509 // 1) policy schema (generated out of policy_templates.json)
511 // 2) PolicyWatcher's code (i.e. contents of the |default_values_| field)
514 std::set
<std::string
> expected_schema_keys
;
515 for (base::DictionaryValue::Iterator
i(GetDefaultValues()); !i
.IsAtEnd();
517 expected_schema_keys
.insert(i
.key());
520 // RemoteAccessHostMatchUsername is marked in policy_templates.json as not
521 // supported on Windows and therefore is (by design) excluded from the schema.
522 expected_schema_keys
.erase(policy::key::kRemoteAccessHostMatchUsername
);
525 // Policy schema / policy_templates.json cannot differ between debug and
526 // release builds so we compensate below to account for the fact that
527 // PolicyWatcher::default_values_ does differ between debug and release.
528 expected_schema_keys
.insert(
529 policy::key::kRemoteAccessHostDebugOverridePolicies
);
532 std::set
<std::string
> actual_schema_keys
;
533 const policy::Schema
* schema
= GetPolicySchema();
534 ASSERT_TRUE(schema
->valid());
535 for (auto it
= schema
->GetPropertiesIterator(); !it
.IsAtEnd(); it
.Advance()) {
536 std::string key
= it
.key();
537 if (key
.find("RemoteAccessHost") == std::string::npos
) {
538 // For now PolicyWatcher::GetPolicySchema() mixes Chrome and Chromoting
539 // policies, so we have to skip them here.
542 actual_schema_keys
.insert(key
);
545 EXPECT_THAT(actual_schema_keys
, testing::ContainerEq(expected_schema_keys
));
548 // Unit tests cannot instantiate PolicyWatcher on ChromeOS
549 // (as this requires running inside a browser process).
554 void OnPolicyUpdatedDumpPolicy(scoped_ptr
<base::DictionaryValue
> policies
) {
555 VLOG(1) << "OnPolicyUpdated callback received the following policies:";
557 for (base::DictionaryValue::Iterator
iter(*policies
); !iter
.IsAtEnd();
559 switch (iter
.value().GetType()) {
560 case base::Value::Type::TYPE_STRING
: {
562 CHECK(iter
.value().GetAsString(&value
));
563 VLOG(1) << iter
.key() << " = "
564 << "string: " << '"' << value
<< '"';
567 case base::Value::Type::TYPE_BOOLEAN
: {
569 CHECK(iter
.value().GetAsBoolean(&value
));
570 VLOG(1) << iter
.key() << " = "
571 << "boolean: " << (value
? "True" : "False");
575 VLOG(1) << iter
.key() << " = "
576 << "unrecognized type";
583 } // anonymous namespace
585 // To dump policy contents, run unit tests with the following flags:
586 // out/Debug/remoting_unittests --gtest_filter=*TestRealChromotingPolicy* -v=1
587 TEST_F(PolicyWatcherTest
, TestRealChromotingPolicy
) {
588 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
=
589 base::MessageLoop::current()->task_runner();
590 scoped_ptr
<PolicyWatcher
> policy_watcher(
591 PolicyWatcher::Create(nullptr, task_runner
));
594 base::RunLoop run_loop
;
595 policy_watcher
->StartWatching(base::Bind(OnPolicyUpdatedDumpPolicy
),
596 base::Bind(base::DoNothing
));
597 run_loop
.RunUntilIdle();
600 // Today, the only verification offered by this test is:
601 // - Manual verification of policy values dumped by OnPolicyUpdatedDumpPolicy
602 // - Automated verification that nothing crashed
607 } // namespace remoting