Home | History | Annotate | Download | only in cloud
      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 <string>
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/metrics/histogram_samples.h"
     14 #include "base/metrics/sample_map.h"
     15 #include "base/metrics/statistics_recorder.h"
     16 #include "base/run_loop.h"
     17 #include "base/test/simple_test_clock.h"
     18 #include "base/test/test_simple_task_runner.h"
     19 #include "base/time/time.h"
     20 #include "base/values.h"
     21 #include "chrome/browser/invalidation/fake_invalidation_service.h"
     22 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
     23 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     24 #include "components/policy/core/common/cloud/cloud_policy_core.h"
     25 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
     26 #include "components/policy/core/common/cloud/enterprise_metrics.h"
     27 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
     28 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
     29 #include "components/policy/core/common/policy_types.h"
     30 #include "policy/policy_constants.h"
     31 #include "policy/proto/device_management_backend.pb.h"
     32 #include "sync/notifier/invalidation_util.h"
     33 #include "testing/gmock/include/gmock/gmock.h"
     34 #include "testing/gtest/include/gtest/gtest.h"
     35 
     36 namespace policy {
     37 
     38 class CloudPolicyInvalidatorTest : public testing::Test {
     39  protected:
     40   // Policy objects which can be used in tests.
     41   enum PolicyObject {
     42     POLICY_OBJECT_NONE,
     43     POLICY_OBJECT_A,
     44     POLICY_OBJECT_B
     45   };
     46 
     47   CloudPolicyInvalidatorTest();
     48 
     49   virtual void SetUp() OVERRIDE;
     50 
     51   virtual void TearDown() OVERRIDE;
     52 
     53   // Starts the invalidator which will be tested.
     54   // |initialize| determines if the invalidator should be initialized.
     55   // |start_refresh_scheduler| determines if the refresh scheduler should start.
     56   void StartInvalidator(bool initialize, bool start_refresh_scheduler);
     57   void StartInvalidator() {
     58     StartInvalidator(true /* initialize */, true /* start_refresh_scheduler */);
     59   }
     60 
     61   // Calls Initialize on the invalidator.
     62   void InitializeInvalidator();
     63 
     64   // Calls Shutdown on the invalidator. Test must call DestroyInvalidator
     65   // afterwards to prevent Shutdown from being called twice.
     66   void ShutdownInvalidator();
     67 
     68   // Destroys the invalidator.
     69   void DestroyInvalidator();
     70 
     71   // Connects the cloud policy core.
     72   void ConnectCore();
     73 
     74   // Starts the refresh scheduler.
     75   void StartRefreshScheduler();
     76 
     77   // Disconnects the cloud policy core.
     78   void DisconnectCore();
     79 
     80   // Simulates storing a new policy to the policy store.
     81   // |object| determines which policy object the store will report the
     82   // invalidator should register for. May be POLICY_OBJECT_NONE for no object.
     83   // |invalidation_version| determines what invalidation the store will report.
     84   // |policy_changed| determines whether a policy value different from the
     85   // current value will be stored.
     86   // |time| determines the timestamp the store will report.
     87   void StorePolicy(
     88       PolicyObject object,
     89       int64 invalidation_version,
     90       bool policy_changed,
     91       const base::Time& time);
     92   void StorePolicy(
     93       PolicyObject object,
     94       int64 invalidation_version,
     95       bool policy_changed) {
     96     StorePolicy(object,
     97                 invalidation_version,
     98                 policy_changed,
     99                 Now() - base::TimeDelta::FromMinutes(5));
    100   }
    101   void StorePolicy(PolicyObject object, int64 invalidation_version) {
    102     StorePolicy(object, invalidation_version, false);
    103   }
    104   void StorePolicy(PolicyObject object) {
    105     StorePolicy(object, 0);
    106   }
    107 
    108   // Disables the invalidation service. It is enabled by default.
    109   void DisableInvalidationService();
    110 
    111   // Enables the invalidation service. It is enabled by default.
    112   void EnableInvalidationService();
    113 
    114   // Causes the invalidation service to fire an invalidation.
    115   syncer::Invalidation FireInvalidation(
    116       PolicyObject object,
    117       int64 version,
    118       const std::string& payload);
    119 
    120   // Causes the invalidation service to fire an invalidation with unknown
    121   // version.
    122   syncer::Invalidation FireUnknownVersionInvalidation(PolicyObject object);
    123 
    124   // Checks the expected value of the currently set invalidation info.
    125   bool CheckInvalidationInfo(int64 version, const std::string& payload);
    126 
    127   // Checks that the policy was not refreshed due to an invalidation.
    128   bool CheckPolicyNotRefreshed();
    129 
    130   // Checks that the policy was refreshed due to an invalidation within an
    131   // appropriate timeframe depending on whether the invalidation had unknown
    132   // version.
    133   bool CheckPolicyRefreshed();
    134   bool CheckPolicyRefreshedWithUnknownVersion();
    135 
    136   bool IsUnsent(const syncer::Invalidation& invalidation);
    137 
    138   // Returns the invalidations enabled state set by the invalidator on the
    139   // refresh scheduler.
    140   bool InvalidationsEnabled();
    141 
    142   // Determines if the invalidation with the given ack handle has been
    143   // acknowledged.
    144   bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation);
    145 
    146   // Determines if the invalidator has registered for an object with the
    147   // invalidation service.
    148   bool IsInvalidatorRegistered();
    149 
    150   // Get the current count for the given metric.
    151   base::HistogramBase::Count GetCount(MetricPolicyRefresh metric);
    152   base::HistogramBase::Count GetInvalidationCount(PolicyInvalidationType type);
    153 
    154   // Advance the test clock.
    155   void AdvanceClock(base::TimeDelta delta);
    156 
    157   // Get the current time on the test clock.
    158   base::Time Now();
    159 
    160   // Translate a version number into an appropriate invalidation version (which
    161   // is based on the current time).
    162   int64 V(int version);
    163 
    164   // Get an invalidation version for the given time.
    165   int64 GetVersion(base::Time time);
    166 
    167  private:
    168   // Checks that the policy was refreshed due to an invalidation with the given
    169   // base delay.
    170   bool CheckPolicyRefreshed(base::TimeDelta delay);
    171 
    172   // Checks that the policy was refreshed the given number of times.
    173   bool CheckPolicyRefreshCount(int count);
    174 
    175   // Returns the object id of the given policy object.
    176   const invalidation::ObjectId& GetPolicyObjectId(PolicyObject object) const;
    177 
    178   // Get histogram samples for the given histogram.
    179   scoped_ptr<base::HistogramSamples> GetHistogramSamples(
    180       const std::string& name) const;
    181 
    182   base::MessageLoop loop_;
    183 
    184   // Objects the invalidator depends on.
    185   invalidation::FakeInvalidationService invalidation_service_;
    186   MockCloudPolicyStore store_;
    187   CloudPolicyCore core_;
    188   MockCloudPolicyClient* client_;
    189   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
    190   base::SimpleTestClock* clock_;
    191 
    192   // The invalidator which will be tested.
    193   scoped_ptr<CloudPolicyInvalidator> invalidator_;
    194 
    195   // Object ids for the test policy objects.
    196   invalidation::ObjectId object_id_a_;
    197   invalidation::ObjectId object_id_b_;
    198 
    199   // Fake policy values which are alternated to cause the store to report a
    200   // changed policy.
    201   const char* policy_value_a_;
    202   const char* policy_value_b_;
    203 
    204   // The currently used policy value.
    205   const char* policy_value_cur_;
    206 
    207   // Stores starting histogram counts for kMetricPolicyRefresh.
    208   scoped_ptr<base::HistogramSamples> refresh_samples_;
    209 
    210   // Stores starting histogram counts for kMetricPolicyInvalidations.
    211   scoped_ptr<base::HistogramSamples> invalidations_samples_;
    212 };
    213 
    214 CloudPolicyInvalidatorTest::CloudPolicyInvalidatorTest()
    215     : core_(PolicyNamespaceKey(dm_protocol::kChromeUserPolicyType,
    216                                std::string()),
    217             &store_,
    218             loop_.message_loop_proxy()),
    219       client_(NULL),
    220       task_runner_(new base::TestSimpleTaskRunner()),
    221       clock_(new base::SimpleTestClock()),
    222       object_id_a_(135, "asdf"),
    223       object_id_b_(246, "zxcv"),
    224       policy_value_a_("asdf"),
    225       policy_value_b_("zxcv"),
    226       policy_value_cur_(policy_value_a_) {
    227   clock_->SetNow(
    228       base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(987654321));
    229 }
    230 
    231 void CloudPolicyInvalidatorTest::SetUp() {
    232   base::StatisticsRecorder::Initialize();
    233   refresh_samples_ = GetHistogramSamples(kMetricPolicyRefresh);
    234   invalidations_samples_ = GetHistogramSamples(kMetricPolicyInvalidations);
    235 }
    236 
    237 void CloudPolicyInvalidatorTest::TearDown() {
    238   if (invalidator_)
    239     invalidator_->Shutdown();
    240   core_.Disconnect();
    241 }
    242 
    243 void CloudPolicyInvalidatorTest::StartInvalidator(
    244     bool initialize,
    245     bool start_refresh_scheduler) {
    246   invalidator_.reset(new CloudPolicyInvalidator(
    247       &core_,
    248       task_runner_,
    249       scoped_ptr<base::Clock>(clock_)));
    250   if (start_refresh_scheduler) {
    251     ConnectCore();
    252     StartRefreshScheduler();
    253   }
    254   if (initialize)
    255     InitializeInvalidator();
    256 }
    257 
    258 void CloudPolicyInvalidatorTest::InitializeInvalidator() {
    259   invalidator_->Initialize(&invalidation_service_);
    260 }
    261 
    262 void CloudPolicyInvalidatorTest::ShutdownInvalidator() {
    263   invalidator_->Shutdown();
    264 }
    265 
    266 void CloudPolicyInvalidatorTest::DestroyInvalidator() {
    267   invalidator_.reset();
    268 }
    269 
    270 void CloudPolicyInvalidatorTest::ConnectCore() {
    271   client_ = new MockCloudPolicyClient();
    272   client_->SetDMToken("dm");
    273   core_.Connect(scoped_ptr<CloudPolicyClient>(client_));
    274 }
    275 
    276 void CloudPolicyInvalidatorTest::StartRefreshScheduler() {
    277   core_.StartRefreshScheduler();
    278 }
    279 
    280 void CloudPolicyInvalidatorTest::DisconnectCore() {
    281   client_ = NULL;
    282   core_.Disconnect();
    283 }
    284 
    285 void CloudPolicyInvalidatorTest::StorePolicy(
    286     PolicyObject object,
    287     int64 invalidation_version,
    288     bool policy_changed,
    289     const base::Time& time) {
    290   enterprise_management::PolicyData* data =
    291       new enterprise_management::PolicyData();
    292   if (object != POLICY_OBJECT_NONE) {
    293     data->set_invalidation_source(GetPolicyObjectId(object).source());
    294     data->set_invalidation_name(GetPolicyObjectId(object).name());
    295   }
    296   data->set_timestamp((time - base::Time::UnixEpoch()).InMilliseconds());
    297   // Swap the policy value if a policy change is desired.
    298   if (policy_changed)
    299     policy_value_cur_ = policy_value_cur_ == policy_value_a_ ?
    300         policy_value_b_ : policy_value_a_;
    301   data->set_policy_value(policy_value_cur_);
    302   store_.invalidation_version_ = invalidation_version;
    303   store_.policy_.reset(data);
    304   base::DictionaryValue policies;
    305   policies.SetInteger(
    306       key::kMaxInvalidationFetchDelay,
    307       CloudPolicyInvalidator::kMaxFetchDelayMin);
    308   store_.policy_map_.LoadFrom(
    309       &policies,
    310       POLICY_LEVEL_MANDATORY,
    311       POLICY_SCOPE_MACHINE);
    312   store_.NotifyStoreLoaded();
    313 }
    314 
    315 void CloudPolicyInvalidatorTest::DisableInvalidationService() {
    316   invalidation_service_.SetInvalidatorState(
    317       syncer::TRANSIENT_INVALIDATION_ERROR);
    318 }
    319 
    320 void CloudPolicyInvalidatorTest::EnableInvalidationService() {
    321   invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED);
    322 }
    323 
    324 syncer::Invalidation CloudPolicyInvalidatorTest::FireInvalidation(
    325     PolicyObject object,
    326     int64 version,
    327     const std::string& payload) {
    328   syncer::Invalidation invalidation = syncer::Invalidation::Init(
    329       GetPolicyObjectId(object),
    330       version,
    331       payload);
    332   invalidation_service_.EmitInvalidationForTest(invalidation);
    333   return invalidation;
    334 }
    335 
    336 syncer::Invalidation CloudPolicyInvalidatorTest::FireUnknownVersionInvalidation(
    337     PolicyObject object) {
    338   syncer::Invalidation invalidation = syncer::Invalidation::InitUnknownVersion(
    339       GetPolicyObjectId(object));
    340   invalidation_service_.EmitInvalidationForTest(invalidation);
    341   return invalidation;
    342 }
    343 
    344 bool CloudPolicyInvalidatorTest::CheckInvalidationInfo(
    345     int64 version,
    346     const std::string& payload) {
    347   MockCloudPolicyClient* client =
    348       static_cast<MockCloudPolicyClient*>(core_.client());
    349   return version == client->invalidation_version_ &&
    350       payload == client->invalidation_payload_;
    351 }
    352 
    353 bool CloudPolicyInvalidatorTest::CheckPolicyNotRefreshed() {
    354   return CheckPolicyRefreshCount(0);
    355 }
    356 
    357 bool CloudPolicyInvalidatorTest::CheckPolicyRefreshed() {
    358   return CheckPolicyRefreshed(base::TimeDelta());
    359 }
    360 
    361 bool CloudPolicyInvalidatorTest::IsUnsent(
    362     const syncer::Invalidation& invalidation) {
    363   return invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation);
    364 }
    365 
    366 bool CloudPolicyInvalidatorTest::CheckPolicyRefreshedWithUnknownVersion() {
    367   return CheckPolicyRefreshed(base::TimeDelta::FromMinutes(
    368         CloudPolicyInvalidator::kMissingPayloadDelay));
    369 }
    370 
    371 bool CloudPolicyInvalidatorTest::InvalidationsEnabled() {
    372   return core_.refresh_scheduler()->invalidations_available();
    373 }
    374 
    375 bool CloudPolicyInvalidatorTest::IsInvalidationAcknowledged(
    376     const syncer::Invalidation& invalidation) {
    377   // The acknowledgement task is run through a WeakHandle that posts back to our
    378   // own thread.  We need to run any posted tasks before we can check
    379   // acknowledgement status.
    380   loop_.RunUntilIdle();
    381 
    382   EXPECT_FALSE(IsUnsent(invalidation));
    383   return !invalidation_service_.GetMockAckHandler()->IsUnacked(invalidation);
    384 }
    385 
    386 bool CloudPolicyInvalidatorTest::IsInvalidatorRegistered() {
    387   return !invalidation_service_.invalidator_registrar()
    388       .GetRegisteredIds(invalidator_.get()).empty();
    389 }
    390 
    391 base::HistogramBase::Count CloudPolicyInvalidatorTest::GetCount(
    392     MetricPolicyRefresh metric) {
    393   return GetHistogramSamples(kMetricPolicyRefresh)->GetCount(metric) -
    394       refresh_samples_->GetCount(metric);
    395 }
    396 
    397 base::HistogramBase::Count CloudPolicyInvalidatorTest::GetInvalidationCount(
    398     PolicyInvalidationType type) {
    399   return GetHistogramSamples(kMetricPolicyInvalidations)->GetCount(type) -
    400       invalidations_samples_->GetCount(type);
    401 }
    402 
    403 void CloudPolicyInvalidatorTest::AdvanceClock(base::TimeDelta delta) {
    404   clock_->Advance(delta);
    405 }
    406 
    407 base::Time CloudPolicyInvalidatorTest::Now() {
    408   return clock_->Now();
    409 }
    410 
    411 int64 CloudPolicyInvalidatorTest::V(int version) {
    412   return GetVersion(Now()) + version;
    413 }
    414 
    415 int64 CloudPolicyInvalidatorTest::GetVersion(base::Time time) {
    416   return (time - base::Time::UnixEpoch()).InMicroseconds();
    417 }
    418 
    419 bool CloudPolicyInvalidatorTest::CheckPolicyRefreshed(base::TimeDelta delay) {
    420   base::TimeDelta max_delay = delay + base::TimeDelta::FromMilliseconds(
    421       CloudPolicyInvalidator::kMaxFetchDelayMin);
    422 
    423   if (task_runner_->GetPendingTasks().empty())
    424     return false;
    425   base::TimeDelta actual_delay = task_runner_->GetPendingTasks().back().delay;
    426   EXPECT_GE(actual_delay, delay);
    427   EXPECT_LE(actual_delay, max_delay);
    428 
    429   return CheckPolicyRefreshCount(1);
    430 }
    431 
    432 bool CloudPolicyInvalidatorTest::CheckPolicyRefreshCount(int count) {
    433   if (!client_) {
    434     task_runner_->RunUntilIdle();
    435     return count == 0;
    436   }
    437 
    438   // Clear any non-invalidation refreshes which may be pending.
    439   EXPECT_CALL(*client_, FetchPolicy()).Times(testing::AnyNumber());
    440   base::RunLoop().RunUntilIdle();
    441   testing::Mock::VerifyAndClearExpectations(client_);
    442 
    443   // Run the invalidator tasks then check for invalidation refreshes.
    444   EXPECT_CALL(*client_, FetchPolicy()).Times(count);
    445   task_runner_->RunUntilIdle();
    446   base::RunLoop().RunUntilIdle();
    447   return testing::Mock::VerifyAndClearExpectations(client_);
    448 }
    449 
    450 const invalidation::ObjectId& CloudPolicyInvalidatorTest::GetPolicyObjectId(
    451     PolicyObject object) const {
    452   EXPECT_TRUE(object == POLICY_OBJECT_A || object == POLICY_OBJECT_B);
    453   return object == POLICY_OBJECT_A ? object_id_a_ : object_id_b_;
    454 }
    455 
    456 scoped_ptr<base::HistogramSamples>
    457     CloudPolicyInvalidatorTest::GetHistogramSamples(
    458         const std::string& name) const {
    459   base::HistogramBase* histogram =
    460       base::StatisticsRecorder::FindHistogram(name);
    461   if (!histogram)
    462     return scoped_ptr<base::HistogramSamples>(new base::SampleMap());
    463   return histogram->SnapshotSamples();
    464 }
    465 
    466 TEST_F(CloudPolicyInvalidatorTest, Uninitialized) {
    467   // No invalidations should be processed if the invalidator is not initialized.
    468   StartInvalidator(false /* initialize */, true /* start_refresh_scheduler */);
    469   StorePolicy(POLICY_OBJECT_A);
    470   EXPECT_FALSE(IsInvalidatorRegistered());
    471   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    472   EXPECT_TRUE(CheckPolicyNotRefreshed());
    473 }
    474 
    475 TEST_F(CloudPolicyInvalidatorTest, RefreshSchedulerNotStarted) {
    476   // No invalidations should be processed if the refresh scheduler is not
    477   // started.
    478   StartInvalidator(true /* initialize */, false /* start_refresh_scheduler */);
    479   StorePolicy(POLICY_OBJECT_A);
    480   EXPECT_FALSE(IsInvalidatorRegistered());
    481   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    482   EXPECT_TRUE(CheckPolicyNotRefreshed());
    483 }
    484 
    485 TEST_F(CloudPolicyInvalidatorTest, DisconnectCoreThenInitialize) {
    486   // No invalidations should be processed if the core is disconnected before
    487   // initialization.
    488   StartInvalidator(false /* initialize */, true /* start_refresh_scheduler */);
    489   DisconnectCore();
    490   InitializeInvalidator();
    491   StorePolicy(POLICY_OBJECT_A);
    492   EXPECT_FALSE(IsInvalidatorRegistered());
    493   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    494   EXPECT_TRUE(CheckPolicyNotRefreshed());
    495 }
    496 
    497 TEST_F(CloudPolicyInvalidatorTest, InitializeThenStartRefreshScheduler) {
    498   // Make sure registration occurs and invalidations are processed when
    499   // Initialize is called before starting the refresh scheduler.
    500   // Note that the reverse case (start refresh scheduler then initialize) is
    501   // the default behavior for the test fixture, so will be tested in most other
    502   // tests.
    503   StartInvalidator(true /* initialize */, false /* start_refresh_scheduler */);
    504   ConnectCore();
    505   StartRefreshScheduler();
    506   StorePolicy(POLICY_OBJECT_A);
    507   EXPECT_TRUE(IsInvalidatorRegistered());
    508   FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    509   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    510 }
    511 
    512 TEST_F(CloudPolicyInvalidatorTest, RegisterOnStoreLoaded) {
    513   // No registration when store is not loaded.
    514   StartInvalidator();
    515   EXPECT_FALSE(IsInvalidatorRegistered());
    516   EXPECT_FALSE(InvalidationsEnabled());
    517   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    518   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
    519   EXPECT_TRUE(CheckPolicyNotRefreshed());
    520 
    521   // No registration when store is loaded with no invalidation object id.
    522   StorePolicy(POLICY_OBJECT_NONE);
    523   EXPECT_FALSE(IsInvalidatorRegistered());
    524   EXPECT_FALSE(InvalidationsEnabled());
    525   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    526   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
    527   EXPECT_TRUE(CheckPolicyNotRefreshed());
    528 
    529   // Check registration when store is loaded for object A.
    530   StorePolicy(POLICY_OBJECT_A);
    531   EXPECT_TRUE(IsInvalidatorRegistered());
    532   EXPECT_TRUE(InvalidationsEnabled());
    533   FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    534   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    535   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
    536   EXPECT_TRUE(CheckPolicyNotRefreshed());
    537 }
    538 
    539 TEST_F(CloudPolicyInvalidatorTest, ChangeRegistration) {
    540   // Register for object A.
    541   StartInvalidator();
    542   StorePolicy(POLICY_OBJECT_A);
    543   EXPECT_TRUE(IsInvalidatorRegistered());
    544   EXPECT_TRUE(InvalidationsEnabled());
    545   FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    546   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    547   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
    548   EXPECT_TRUE(CheckPolicyNotRefreshed());
    549   syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    550 
    551   // Check re-registration for object B. Make sure the pending invalidation for
    552   // object A is acknowledged without making the callback.
    553   StorePolicy(POLICY_OBJECT_B);
    554   EXPECT_TRUE(IsInvalidatorRegistered());
    555   EXPECT_TRUE(InvalidationsEnabled());
    556   EXPECT_TRUE(IsInvalidationAcknowledged(inv));
    557   EXPECT_TRUE(CheckPolicyNotRefreshed());
    558 
    559   // Make sure future invalidations for object A are ignored and for object B
    560   // are processed.
    561   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    562   EXPECT_TRUE(CheckPolicyNotRefreshed());
    563   FireUnknownVersionInvalidation(POLICY_OBJECT_B);
    564   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    565 }
    566 
    567 TEST_F(CloudPolicyInvalidatorTest, UnregisterOnStoreLoaded) {
    568   // Register for object A.
    569   StartInvalidator();
    570   StorePolicy(POLICY_OBJECT_A);
    571   EXPECT_TRUE(IsInvalidatorRegistered());
    572   EXPECT_TRUE(InvalidationsEnabled());
    573   FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    574   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    575 
    576   // Check unregistration when store is loaded with no invalidation object id.
    577   syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    578   EXPECT_FALSE(IsInvalidationAcknowledged(inv));
    579   StorePolicy(POLICY_OBJECT_NONE);
    580   EXPECT_FALSE(IsInvalidatorRegistered());
    581   EXPECT_TRUE(IsInvalidationAcknowledged(inv));
    582   EXPECT_FALSE(InvalidationsEnabled());
    583   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_A)));
    584   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
    585   EXPECT_TRUE(CheckPolicyNotRefreshed());
    586 
    587   // Check re-registration for object B.
    588   StorePolicy(POLICY_OBJECT_B);
    589   EXPECT_TRUE(IsInvalidatorRegistered());
    590   EXPECT_TRUE(InvalidationsEnabled());
    591   FireUnknownVersionInvalidation(POLICY_OBJECT_B);
    592   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    593 }
    594 
    595 TEST_F(CloudPolicyInvalidatorTest, HandleInvalidation) {
    596   // Register and fire invalidation
    597   StorePolicy(POLICY_OBJECT_A);
    598   StartInvalidator();
    599   EXPECT_TRUE(InvalidationsEnabled());
    600   syncer::Invalidation inv =
    601       FireInvalidation(POLICY_OBJECT_A, V(12), "test_payload");
    602 
    603   // Make sure client info is set as soon as the invalidation is received.
    604   EXPECT_TRUE(CheckInvalidationInfo(V(12), "test_payload"));
    605   EXPECT_TRUE(CheckPolicyRefreshed());
    606 
    607   // Make sure invalidation is not acknowledged until the store is loaded.
    608   EXPECT_FALSE(IsInvalidationAcknowledged(inv));
    609   EXPECT_TRUE(CheckInvalidationInfo(V(12), "test_payload"));
    610   StorePolicy(POLICY_OBJECT_A, V(12));
    611   EXPECT_TRUE(IsInvalidationAcknowledged(inv));
    612   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    613 }
    614 
    615 TEST_F(CloudPolicyInvalidatorTest, HandleInvalidationWithUnknownVersion) {
    616   // Register and fire invalidation with unknown version.
    617   StorePolicy(POLICY_OBJECT_A);
    618   StartInvalidator();
    619   syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    620 
    621   // Make sure client info is not set until after the invalidation callback is
    622   // made.
    623   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    624   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    625   EXPECT_TRUE(CheckInvalidationInfo(-1, std::string()));
    626 
    627   // Make sure invalidation is not acknowledged until the store is loaded.
    628   EXPECT_FALSE(IsInvalidationAcknowledged(inv));
    629   StorePolicy(POLICY_OBJECT_A, -1);
    630   EXPECT_TRUE(IsInvalidationAcknowledged(inv));
    631   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    632 }
    633 
    634 TEST_F(CloudPolicyInvalidatorTest, HandleMultipleInvalidations) {
    635   // Generate multiple invalidations.
    636   StorePolicy(POLICY_OBJECT_A);
    637   StartInvalidator();
    638   syncer::Invalidation inv1 = FireInvalidation(POLICY_OBJECT_A, V(1), "test1");
    639   EXPECT_TRUE(CheckInvalidationInfo(V(1), "test1"));
    640   syncer::Invalidation inv2 = FireInvalidation(POLICY_OBJECT_A, V(2), "test2");
    641   EXPECT_TRUE(CheckInvalidationInfo(V(2), "test2"));
    642   syncer::Invalidation inv3 = FireInvalidation(POLICY_OBJECT_A, V(3), "test3");
    643   EXPECT_TRUE(CheckInvalidationInfo(V(3), "test3"));
    644 
    645   // Make sure the replaced invalidations are acknowledged.
    646   EXPECT_TRUE(IsInvalidationAcknowledged(inv1));
    647   EXPECT_TRUE(IsInvalidationAcknowledged(inv2));
    648 
    649   // Make sure the policy is refreshed once.
    650   EXPECT_TRUE(CheckPolicyRefreshed());
    651 
    652   // Make sure that the last invalidation is only acknowledged after the store
    653   // is loaded with the latest version.
    654   StorePolicy(POLICY_OBJECT_A, V(1));
    655   EXPECT_FALSE(IsInvalidationAcknowledged(inv3));
    656   StorePolicy(POLICY_OBJECT_A, V(2));
    657   EXPECT_FALSE(IsInvalidationAcknowledged(inv3));
    658   StorePolicy(POLICY_OBJECT_A, V(3));
    659   EXPECT_TRUE(IsInvalidationAcknowledged(inv3));
    660 }
    661 
    662 TEST_F(CloudPolicyInvalidatorTest,
    663        HandleMultipleInvalidationsWithUnknownVersion) {
    664   // Validate that multiple invalidations with unknown version each generate
    665   // unique invalidation version numbers.
    666   StorePolicy(POLICY_OBJECT_A);
    667   StartInvalidator();
    668   syncer::Invalidation inv1 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    669   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    670   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    671   EXPECT_TRUE(CheckInvalidationInfo(-1, std::string()));
    672   syncer::Invalidation inv2 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    673   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    674   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    675   EXPECT_TRUE(CheckInvalidationInfo(-2, std::string()));
    676   syncer::Invalidation inv3 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    677   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
    678   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    679   EXPECT_TRUE(CheckInvalidationInfo(-3, std::string()));
    680 
    681   // Make sure the replaced invalidations are acknowledged.
    682   EXPECT_TRUE(IsInvalidationAcknowledged(inv1));
    683   EXPECT_TRUE(IsInvalidationAcknowledged(inv2));
    684 
    685   // Make sure that the last invalidation is only acknowledged after the store
    686   // is loaded with the last unknown version.
    687   StorePolicy(POLICY_OBJECT_A, -1);
    688   EXPECT_FALSE(IsInvalidationAcknowledged(inv3));
    689   StorePolicy(POLICY_OBJECT_A, -2);
    690   EXPECT_FALSE(IsInvalidationAcknowledged(inv3));
    691   StorePolicy(POLICY_OBJECT_A, -3);
    692   EXPECT_TRUE(IsInvalidationAcknowledged(inv3));
    693 }
    694 
    695 TEST_F(CloudPolicyInvalidatorTest, AcknowledgeBeforeRefresh) {
    696   // Generate an invalidation.
    697   StorePolicy(POLICY_OBJECT_A);
    698   StartInvalidator();
    699   syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(3), "test");
    700 
    701   // Ensure that the policy is not refreshed and the invalidation is
    702   // acknowledged if the store is loaded with the latest version before the
    703   // refresh can occur.
    704   StorePolicy(POLICY_OBJECT_A, V(3));
    705   EXPECT_TRUE(IsInvalidationAcknowledged(inv));
    706   EXPECT_TRUE(CheckPolicyNotRefreshed());
    707 }
    708 
    709 TEST_F(CloudPolicyInvalidatorTest, NoCallbackAfterShutdown) {
    710   // Generate an invalidation.
    711   StorePolicy(POLICY_OBJECT_A);
    712   StartInvalidator();
    713   syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(3), "test");
    714 
    715   // Ensure that the policy refresh is not made after the invalidator is shut
    716   // down.
    717   ShutdownInvalidator();
    718   EXPECT_TRUE(CheckPolicyNotRefreshed());
    719   DestroyInvalidator();
    720 }
    721 
    722 TEST_F(CloudPolicyInvalidatorTest, StateChanged) {
    723   // Test invalidation service state changes while not registered.
    724   StartInvalidator();
    725   DisableInvalidationService();
    726   EnableInvalidationService();
    727   EXPECT_FALSE(InvalidationsEnabled());
    728 
    729   // Test invalidation service state changes while registered.
    730   StorePolicy(POLICY_OBJECT_A);
    731   EXPECT_TRUE(InvalidationsEnabled());
    732   DisableInvalidationService();
    733   EXPECT_FALSE(InvalidationsEnabled());
    734   DisableInvalidationService();
    735   EXPECT_FALSE(InvalidationsEnabled());
    736   EnableInvalidationService();
    737   EXPECT_TRUE(InvalidationsEnabled());
    738   EnableInvalidationService();
    739   EXPECT_TRUE(InvalidationsEnabled());
    740 
    741   // Test registration changes with invalidation service enabled.
    742   StorePolicy(POLICY_OBJECT_NONE);
    743   EXPECT_FALSE(InvalidationsEnabled());
    744   StorePolicy(POLICY_OBJECT_NONE);
    745   EXPECT_FALSE(InvalidationsEnabled());
    746   StorePolicy(POLICY_OBJECT_A);
    747   EXPECT_TRUE(InvalidationsEnabled());
    748   StorePolicy(POLICY_OBJECT_A);
    749   EXPECT_TRUE(InvalidationsEnabled());
    750 
    751   // Test registration changes with invalidation service disabled.
    752   DisableInvalidationService();
    753   EXPECT_FALSE(InvalidationsEnabled());
    754   StorePolicy(POLICY_OBJECT_NONE);
    755   StorePolicy(POLICY_OBJECT_A);
    756   EXPECT_FALSE(InvalidationsEnabled());
    757 }
    758 
    759 TEST_F(CloudPolicyInvalidatorTest, Disconnect) {
    760   // Generate an invalidation.
    761   StorePolicy(POLICY_OBJECT_A);
    762   StartInvalidator();
    763   syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(1), "test");
    764   EXPECT_TRUE(InvalidationsEnabled());
    765 
    766   // Ensure that the policy is not refreshed after disconnecting the core, but
    767   // a call to indicate that invalidations are disabled is made.
    768   DisconnectCore();
    769   EXPECT_TRUE(CheckPolicyNotRefreshed());
    770 
    771   // Ensure that invalidation service events do not cause refreshes while the
    772   // invalidator is stopped.
    773   EXPECT_TRUE(IsUnsent(FireInvalidation(POLICY_OBJECT_A, V(2), "test")));
    774   EXPECT_TRUE(CheckPolicyNotRefreshed());
    775   DisableInvalidationService();
    776   EnableInvalidationService();
    777 
    778   // Connect and disconnect without starting the refresh scheduler.
    779   ConnectCore();
    780   EXPECT_TRUE(IsUnsent(FireInvalidation(POLICY_OBJECT_A, V(3), "test")));
    781   EXPECT_TRUE(CheckPolicyNotRefreshed());
    782   DisconnectCore();
    783   EXPECT_TRUE(IsUnsent(FireInvalidation(POLICY_OBJECT_A, V(4), "test")));
    784   EXPECT_TRUE(CheckPolicyNotRefreshed());
    785 
    786   // Ensure that the invalidator returns to normal after reconnecting.
    787   ConnectCore();
    788   StartRefreshScheduler();
    789   EXPECT_TRUE(CheckPolicyNotRefreshed());
    790   EXPECT_TRUE(InvalidationsEnabled());
    791   FireInvalidation(POLICY_OBJECT_A, V(5), "test");
    792   EXPECT_TRUE(CheckInvalidationInfo(V(5), "test"));
    793   EXPECT_TRUE(CheckPolicyRefreshed());
    794   DisableInvalidationService();
    795   EXPECT_FALSE(InvalidationsEnabled());
    796 }
    797 
    798 TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsUnregistered) {
    799   // Store loads occurring before invalidation registration are not counted.
    800   StartInvalidator();
    801   StorePolicy(POLICY_OBJECT_NONE, 0, false /* policy_changed */);
    802   StorePolicy(POLICY_OBJECT_NONE, 0, true /* policy_changed */);
    803   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_CHANGED));
    804   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    805   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_UNCHANGED));
    806   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_CHANGED));
    807   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED));
    808 }
    809 
    810 TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsNoInvalidations) {
    811   // Store loads occurring while registered should be differentiated depending
    812   // on whether the invalidation service was enabled or not.
    813   StorePolicy(POLICY_OBJECT_A);
    814   StartInvalidator();
    815 
    816   // Initially, invalidations have not been enabled past the grace period, so
    817   // invalidations are OFF.
    818   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    819   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    820   EXPECT_EQ(1, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    821 
    822   // If the clock advances less than the grace period, invalidations are OFF.
    823   AdvanceClock(base::TimeDelta::FromSeconds(1));
    824   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    825   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    826   EXPECT_EQ(2, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    827 
    828   // After the grace period elapses, invalidations are ON.
    829   AdvanceClock(base::TimeDelta::FromSeconds(
    830       CloudPolicyInvalidator::kInvalidationGracePeriod));
    831   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    832   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    833   EXPECT_EQ(1, GetCount(METRIC_POLICY_REFRESH_CHANGED));
    834 
    835   // After the invalidation service is disabled, invalidations are OFF.
    836   DisableInvalidationService();
    837   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    838   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    839   EXPECT_EQ(3, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    840 
    841   // Enabling the invalidation service results in a new grace period, so
    842   // invalidations are OFF.
    843   EnableInvalidationService();
    844   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    845   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    846   EXPECT_EQ(4, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    847 
    848   // After the grace period elapses, invalidations are ON.
    849   AdvanceClock(base::TimeDelta::FromSeconds(
    850       CloudPolicyInvalidator::kInvalidationGracePeriod));
    851   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    852   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    853 
    854   EXPECT_EQ(2, GetCount(METRIC_POLICY_REFRESH_CHANGED));
    855   EXPECT_EQ(4, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    856   EXPECT_EQ(6, GetCount(METRIC_POLICY_REFRESH_UNCHANGED));
    857   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_CHANGED));
    858   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED));
    859 }
    860 
    861 TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsInvalidation) {
    862   // Store loads after an invalidation are counted as invalidated, even if
    863   // the loads do not result in the invalidation being acknowledged.
    864   StartInvalidator();
    865   StorePolicy(POLICY_OBJECT_A);
    866   AdvanceClock(base::TimeDelta::FromSeconds(
    867       CloudPolicyInvalidator::kInvalidationGracePeriod));
    868   FireInvalidation(POLICY_OBJECT_A, V(5), "test");
    869   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    870   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    871   StorePolicy(POLICY_OBJECT_A, V(5), true /* policy_changed */);
    872 
    873   // Store loads after the invalidation is complete are not counted as
    874   // invalidated.
    875   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    876   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    877   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    878   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    879   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    880   StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */);
    881   StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */);
    882 
    883   EXPECT_EQ(3, GetCount(METRIC_POLICY_REFRESH_CHANGED));
    884   EXPECT_EQ(0, GetCount(METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS));
    885   EXPECT_EQ(4, GetCount(METRIC_POLICY_REFRESH_UNCHANGED));
    886   EXPECT_EQ(2, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_CHANGED));
    887   EXPECT_EQ(1, GetCount(METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED));
    888 }
    889 
    890 TEST_F(CloudPolicyInvalidatorTest, ExpiredInvalidations) {
    891   StorePolicy(POLICY_OBJECT_A, 0, false, Now());
    892   StartInvalidator();
    893 
    894   // Invalidations fired before the last fetch time (adjusted by max time delta)
    895   // should be ignored.
    896   base::Time time = Now() - base::TimeDelta::FromSeconds(
    897       CloudPolicyInvalidator::kMaxInvalidationTimeDelta + 300);
    898   syncer::Invalidation inv =
    899       FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
    900   ASSERT_TRUE(IsInvalidationAcknowledged(inv));
    901   ASSERT_TRUE(CheckPolicyNotRefreshed());
    902 
    903   time += base::TimeDelta::FromMinutes(5) - base::TimeDelta::FromSeconds(1);
    904   inv = FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
    905   ASSERT_TRUE(IsInvalidationAcknowledged(inv));
    906   ASSERT_TRUE(CheckPolicyNotRefreshed());
    907 
    908   // Invalidations fired after the last fetch should not be ignored.
    909   time += base::TimeDelta::FromSeconds(1);
    910   inv = FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
    911   ASSERT_FALSE(IsInvalidationAcknowledged(inv));
    912   ASSERT_TRUE(CheckPolicyRefreshed());
    913 
    914   time += base::TimeDelta::FromMinutes(10);
    915   inv = FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
    916   ASSERT_FALSE(IsInvalidationAcknowledged(inv));
    917   ASSERT_TRUE(CheckPolicyRefreshed());
    918 
    919   time += base::TimeDelta::FromMinutes(10);
    920   inv = FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
    921   ASSERT_FALSE(IsInvalidationAcknowledged(inv));
    922   ASSERT_TRUE(CheckPolicyRefreshed());
    923 
    924   // Unknown version invalidations fired just after the last fetch time should
    925   // be ignored.
    926   inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    927   ASSERT_TRUE(IsInvalidationAcknowledged(inv));
    928   ASSERT_TRUE(CheckPolicyNotRefreshed());
    929 
    930   AdvanceClock(base::TimeDelta::FromSeconds(
    931       CloudPolicyInvalidator::kUnknownVersionIgnorePeriod - 1));
    932   inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    933   ASSERT_TRUE(IsInvalidationAcknowledged(inv));
    934   ASSERT_TRUE(CheckPolicyNotRefreshed());
    935 
    936   // Unknown version invalidations fired past the ignore period should not be
    937   // ignored.
    938   AdvanceClock(base::TimeDelta::FromSeconds(1));
    939   inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
    940   ASSERT_FALSE(IsInvalidationAcknowledged(inv));
    941   ASSERT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
    942 
    943   // Verify that received invalidations metrics are correct.
    944   EXPECT_EQ(1, GetInvalidationCount(POLICY_INVALIDATION_TYPE_NO_PAYLOAD));
    945   EXPECT_EQ(3, GetInvalidationCount(POLICY_INVALIDATION_TYPE_NORMAL));
    946   EXPECT_EQ(2,
    947             GetInvalidationCount(POLICY_INVALIDATION_TYPE_NO_PAYLOAD_EXPIRED));
    948   EXPECT_EQ(2, GetInvalidationCount(POLICY_INVALIDATION_TYPE_EXPIRED));
    949 }
    950 
    951 }  // namespace policy
    952