Chromium Code Reviews| Index: chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc |
| diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0c7c5d93cbac4b393650c498291124cf43420a60 |
| --- /dev/null |
| +++ b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc |
| @@ -0,0 +1,891 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <string> |
| + |
| +#include "base/basictypes.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/metrics/histogram.h" |
| +#include "base/metrics/histogram_samples.h" |
| +#include "base/metrics/sample_map.h" |
| +#include "base/metrics/statistics_recorder.h" |
| +#include "base/test/test_simple_task_runner.h" |
| +#include "base/time/time.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/invalidation/fake_invalidation_service.h" |
| +#include "chrome/browser/policy/cloud/cloud_policy_core.h" |
| +#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h" |
| +#include "chrome/browser/policy/cloud/cloud_policy_service.h" |
| +#include "chrome/browser/policy/cloud/enterprise_metrics.h" |
| +#include "chrome/browser/policy/cloud/mock_cloud_policy_client.h" |
| +#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" |
| +#include "chrome/browser/policy/policy_types.h" |
| +#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" |
| +#include "policy/policy_constants.h" |
| +#include "sync/notifier/invalidation_util.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace policy { |
| + |
| +class CloudPolicyInvalidatorTest : public testing::Test, |
| + public CloudPolicyInvalidationHandler { |
| + protected: |
| + // Policy objects which can be used in tests. |
| + enum PolicyObject { |
| + POLICY_OBJECT_NONE, |
| + POLICY_OBJECT_A, |
| + POLICY_OBJECT_B |
| + }; |
| + |
| + CloudPolicyInvalidatorTest(); |
| + |
| + virtual void SetUp() OVERRIDE; |
| + |
| + virtual void TearDown() OVERRIDE; |
| + |
| + // Starts the invalidator which will be tested. |
| + void StartInvalidator(); |
| + |
| + // Simulates storing a new policy to the policy store. |
| + // |object| determines which policy object the store will report the |
| + // invalidator should register for. May be POLICY_OBJECT_NONE for no object. |
| + // |invalidation_version| determines what invalidation the store will report. |
| + // |policy_changed| determines whether the store will report that the |
| + // policy changed. |
| + // |timestamp| determines the response timestamp the store will report. |
| + void StorePolicy( |
| + PolicyObject object, |
| + int64 invalidation_version, |
| + bool policy_changed, |
| + int64 timestamp); |
| + void StorePolicy( |
| + PolicyObject object, |
| + int64 invalidation_version, |
| + bool policy_changed) { |
| + StorePolicy(object, invalidation_version, policy_changed, ++timestamp_); |
| + } |
| + void StorePolicy(PolicyObject object, int64 invalidation_version) { |
| + StorePolicy(object, invalidation_version, false); |
| + } |
| + void StorePolicy(PolicyObject object) { |
| + StorePolicy(object, 0); |
| + } |
| + |
| + // Disables the invalidation service. It is enabled by default. |
| + void DisableInvalidationService(); |
| + |
| + // Enables the invalidation service. It is enabled by default. |
| + void EnableInvalidationService(); |
| + |
| + // Causes the invalidation service to fire an invalidation. Returns an ack |
| + // handle which be used to verify that the invalidation was acknowledged. |
| + syncer::AckHandle FireInvalidation( |
| + PolicyObject object, |
| + int64 version, |
| + const std::string& payload); |
| + |
| + // Causes the invalidation service to fire an invalidation with unknown |
| + // version. Returns an ack handle which be used to verify that the |
| + // invalidation was acknowledged. |
| + syncer::AckHandle FireInvalidation(PolicyObject object); |
| + |
| + // Verifies expectations for the currently set invalidation info. |
| + void ExpectInvalidationInfo(int64 version, const std::string& payload); |
| + |
| + // Verifies expectation that the invalidate callback was not called. |
| + void ExpectInvalidateNotCalled(); |
| + |
| + // Verifies the expectation that the invalidate callback of the invalidation |
| + // handler was called within an appropriate timeframe depending on whether the |
| + // invalidation had unknown version. |
| + void ExpectInvalidateCalled(bool unknown_version); |
| + void ExpectInvalidateCalled() { |
| + ExpectInvalidateCalled(true); |
| + } |
| + |
| + // Verifies the expectation that the state changed callback of the |
| + // invalidation handler was not called. |
| + void ExpectStateChangedNotCalled(); |
| + |
| + // Verifies the expectation that the state changed callback of the |
| + // invalidation handler was called with the given state. |
| + void ExpectStateChangedCalled(bool invalidations_enabled); |
| + |
| + // Determines if the invalidation with the given ack handle has been |
| + // acknowledged. |
| + bool IsInvalidationAcknowledged(const syncer::AckHandle& ack_handle); |
| + |
| + // Get the current count for the given metric. |
| + base::HistogramBase::Count GetCount(MetricPolicyRefresh metric); |
| + base::HistogramBase::Count GetCount(MetricPolicyInvalidations metric); |
| + |
| + // CloudPolicyInvalidationHandler: |
| + virtual void SetInvalidationInfo( |
| + int64 version, |
| + const std::string& payload) OVERRIDE; |
| + virtual void InvalidatePolicy() OVERRIDE; |
| + virtual void OnInvalidatorStateChanged(bool invalidations_enabled) OVERRIDE; |
| + |
| + private: |
| + // Returns the object id of the given policy object. |
| + const invalidation::ObjectId& GetPolicyObjectId(PolicyObject object) const; |
| + |
| + // Get histogram samples for the given histogram. |
| + scoped_ptr<base::HistogramSamples> GetHistogramSamples( |
| + const std::string& name) const; |
| + |
| + // Objects the invalidator depends on. |
| + invalidation::FakeInvalidationService invalidation_service_; |
| + MockCloudPolicyStore store_; |
| + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| + |
| + // The invalidator which will be tested. |
| + scoped_ptr<CloudPolicyInvalidator> invalidator_; |
| + |
| + // The latest invalidation info set by the invalidator. |
| + int64 invalidation_version_; |
| + std::string invalidation_payload_; |
| + |
| + // Object ids for the test policy objects. |
| + invalidation::ObjectId object_id_a_; |
| + invalidation::ObjectId object_id_b_; |
| + |
| + // Increasing policy timestamp. |
| + int64 timestamp_; |
| + |
| + // Fake policy values which are alternated to cause the store to report a |
| + // changed policy. |
| + const char* policy_value_a_; |
| + const char* policy_value_b_; |
| + |
| + // The currently used policy value. |
| + const char* policy_value_cur_; |
| + |
| + // Stores how many times the invalidate callback was called. |
| + int invalidate_callback_count_; |
| + |
| + // Stores how many times the state change callback was called for each state. |
| + int state_change_enabled_callback_count_; |
| + int state_change_disabled_callback_count_; |
| + |
| + // Stores starting histogram counts for kMetricPolicyRefresh. |
| + scoped_ptr<base::HistogramSamples> refresh_samples_; |
| + |
| + // Stores starting histogram counts for kMetricPolicyInvalidations. |
| + scoped_ptr<base::HistogramSamples> invalidations_samples_; |
| +}; |
| + |
| +CloudPolicyInvalidatorTest::CloudPolicyInvalidatorTest() |
| + : task_runner_(new base::TestSimpleTaskRunner()), |
| + invalidation_version_(0), |
| + object_id_a_(135, "asdf"), |
| + object_id_b_(246, "zxcv"), |
| + timestamp_(123456), |
| + policy_value_a_("asdf"), |
| + policy_value_b_("zxcv"), |
| + policy_value_cur_(policy_value_a_), |
| + invalidate_callback_count_(0), |
| + state_change_enabled_callback_count_(0), |
| + state_change_disabled_callback_count_(0) {} |
| + |
| +void CloudPolicyInvalidatorTest::SetUp() { |
| + base::StatisticsRecorder::Initialize(); |
| + refresh_samples_ = GetHistogramSamples(kMetricPolicyRefresh); |
| + invalidations_samples_ = GetHistogramSamples(kMetricPolicyInvalidations); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::TearDown() { |
| + EXPECT_FALSE(invalidation_service_.ReceivedInvalidAcknowledgement()); |
| + if (invalidator_) |
| + invalidator_->Shutdown(); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::StartInvalidator() { |
| + invalidator_.reset(new CloudPolicyInvalidator( |
| + &invalidation_service_, |
| + &store_, |
| + task_runner_, |
| + this /* invalidation_handler */)); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::StorePolicy( |
| + PolicyObject object, |
| + int64 invalidation_version, |
| + bool policy_changed, |
| + int64 timestamp) { |
| + enterprise_management::PolicyData* data = |
| + new enterprise_management::PolicyData(); |
| + if (object != POLICY_OBJECT_NONE) { |
| + data->set_invalidation_source(GetPolicyObjectId(object).source()); |
| + data->set_invalidation_name(GetPolicyObjectId(object).name()); |
| + } |
| + data->set_timestamp(timestamp); |
| + // Swap the policy value if a policy change is desired. |
| + if (policy_changed) |
| + policy_value_cur_ = policy_value_cur_ == policy_value_a_ ? |
| + policy_value_b_ : policy_value_a_; |
| + data->set_policy_value(policy_value_cur_); |
| + store_.invalidation_version_ = invalidation_version; |
| + store_.policy_.reset(data); |
| + base::DictionaryValue policies; |
| + policies.SetInteger( |
| + key::kMaxInvalidationFetchDelay, |
| + CloudPolicyInvalidator::kMaxFetchDelayMin); |
| + store_.policy_map_.LoadFrom( |
| + &policies, |
| + POLICY_LEVEL_MANDATORY, |
| + POLICY_SCOPE_MACHINE); |
| + store_.NotifyStoreLoaded(); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::DisableInvalidationService() { |
| + invalidation_service_.SetInvalidatorState( |
| + syncer::TRANSIENT_INVALIDATION_ERROR); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::EnableInvalidationService() { |
| + invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED); |
| +} |
| + |
| +syncer::AckHandle CloudPolicyInvalidatorTest::FireInvalidation( |
| + PolicyObject object, |
| + int64 version, |
| + const std::string& payload) { |
| + return invalidation_service_.EmitInvalidationForTest( |
| + GetPolicyObjectId(object), |
| + version, |
| + payload); |
| +} |
| + |
| +syncer::AckHandle CloudPolicyInvalidatorTest::FireInvalidation( |
| + PolicyObject object) { |
| + return invalidation_service_.EmitInvalidationForTest( |
| + GetPolicyObjectId(object), |
| + syncer::Invalidation::kUnknownVersion, |
| + std::string()); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::ExpectInvalidationInfo( |
| + int64 version, |
| + const std::string& payload) { |
| + EXPECT_EQ(version, invalidation_version_); |
| + EXPECT_EQ(payload, invalidation_payload_); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::ExpectInvalidateNotCalled() { |
| + EXPECT_EQ(0, invalidate_callback_count_); |
| + task_runner_->RunUntilIdle(); |
| + EXPECT_EQ(0, invalidate_callback_count_); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::ExpectInvalidateCalled(bool unknown_version) { |
| + base::TimeDelta min_delay; |
| + base::TimeDelta max_delay = base::TimeDelta::FromMilliseconds( |
| + CloudPolicyInvalidator::kMaxFetchDelayMin); |
| + if (unknown_version) { |
| + base::TimeDelta additional_delay = base::TimeDelta::FromMinutes( |
| + CloudPolicyInvalidator::kMissingPayloadDelay); |
| + min_delay += additional_delay; |
| + max_delay += additional_delay; |
| + } |
| + |
| + ASSERT_FALSE(task_runner_->GetPendingTasks().empty()); |
| + base::TimeDelta actual_delay = task_runner_->GetPendingTasks().back().delay; |
| + EXPECT_GE(actual_delay, min_delay); |
| + EXPECT_LE(actual_delay, max_delay); |
| + |
| + EXPECT_EQ(0, invalidate_callback_count_); |
| + task_runner_->RunUntilIdle(); |
| + EXPECT_EQ(1, invalidate_callback_count_); |
| + invalidate_callback_count_ = 0; |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::ExpectStateChangedNotCalled() { |
| + EXPECT_EQ(0, state_change_enabled_callback_count_); |
| + EXPECT_EQ(0, state_change_disabled_callback_count_); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::ExpectStateChangedCalled( |
| + bool invalidations_enabled) { |
| + if (invalidations_enabled) { |
| + EXPECT_EQ(1, state_change_enabled_callback_count_); |
| + EXPECT_EQ(0, state_change_disabled_callback_count_); |
| + } else { |
| + EXPECT_EQ(0, state_change_enabled_callback_count_); |
| + EXPECT_EQ(1, state_change_disabled_callback_count_); |
| + } |
| + state_change_enabled_callback_count_ = 0; |
| + state_change_disabled_callback_count_ = 0; |
| +} |
| + |
| +bool CloudPolicyInvalidatorTest::IsInvalidationAcknowledged( |
| + const syncer::AckHandle& ack_handle) { |
| + return invalidation_service_.IsInvalidationAcknowledged(ack_handle); |
| +} |
| + |
| +base::HistogramBase::Count CloudPolicyInvalidatorTest::GetCount( |
| + MetricPolicyRefresh metric) { |
| + return GetHistogramSamples(kMetricPolicyRefresh)->GetCount(metric) - |
| + refresh_samples_->GetCount(metric); |
| +} |
| + |
| +base::HistogramBase::Count CloudPolicyInvalidatorTest::GetCount( |
| + MetricPolicyInvalidations metric) { |
| + return GetHistogramSamples(kMetricPolicyInvalidations)->GetCount(metric) - |
| + invalidations_samples_->GetCount(metric); |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::SetInvalidationInfo( |
| + int64 version, |
| + const std::string& payload) { |
| + invalidation_version_ = version; |
| + invalidation_payload_ = payload; |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::InvalidatePolicy() { |
| + ++invalidate_callback_count_; |
| +} |
| + |
| +void CloudPolicyInvalidatorTest::OnInvalidatorStateChanged( |
| + bool invalidations_enabled) { |
| + if (invalidator_.get()) |
| + EXPECT_EQ(invalidations_enabled, invalidator_->invalidations_enabled()); |
| + if (invalidations_enabled) |
| + ++state_change_enabled_callback_count_; |
| + else |
| + ++state_change_disabled_callback_count_; |
| +} |
| + |
| +const invalidation::ObjectId& CloudPolicyInvalidatorTest::GetPolicyObjectId( |
| + PolicyObject object) const { |
| + EXPECT_TRUE(object == POLICY_OBJECT_A || object == POLICY_OBJECT_B); |
| + return object == POLICY_OBJECT_A ? object_id_a_ : object_id_b_; |
| +} |
| + |
| +scoped_ptr<base::HistogramSamples> |
| + CloudPolicyInvalidatorTest::GetHistogramSamples( |
| + const std::string& name) const { |
| + base::HistogramBase* histogram = |
| + base::StatisticsRecorder::FindHistogram(name); |
| + if (!histogram) |
| + return scoped_ptr<base::HistogramSamples>(new base::SampleMap()); |
| + return histogram->SnapshotSamples(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, RegisterOnStoreLoaded) { |
| + // No registration when store is not loaded. |
| + StartInvalidator(); |
| + ExpectStateChangedNotCalled(); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateNotCalled(); |
| + |
| + // No registration when store is loaded with no invalidation object id. |
| + StorePolicy(POLICY_OBJECT_NONE); |
| + ExpectStateChangedNotCalled(); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateNotCalled(); |
| + |
| + // Check registration when store is loaded for object A. |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedCalled(true); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidateCalled(); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateNotCalled(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, ChangeRegistration) { |
| + // Register for object A. |
| + StartInvalidator(); |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedCalled(true); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidateCalled(); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateNotCalled(); |
| + syncer::AckHandle ack = FireInvalidation(POLICY_OBJECT_A); |
| + |
| + // Check re-registration for object B. Make sure the pending invalidation for |
| + // object A is acknowledged without making the callback. |
| + StorePolicy(POLICY_OBJECT_B); |
| + ExpectStateChangedNotCalled(); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack)); |
| + ExpectInvalidateNotCalled(); |
| + |
| + // Make sure future invalidations for object A are ignored and for object B |
| + // are processed. |
| + FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidateNotCalled(); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateCalled(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, UnregisterOnStoreLoaded) { |
| + // Register for object A. |
| + StartInvalidator(); |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedCalled(true); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidateCalled(); |
| + |
| + // Check unregistration when store is loaded with no invalidation object id. |
| + syncer::AckHandle ack = FireInvalidation(POLICY_OBJECT_A); |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack)); |
| + StorePolicy(POLICY_OBJECT_NONE); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack)); |
| + ExpectStateChangedCalled(false); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateNotCalled(); |
| + |
| + // Check re-registration for object B. |
| + StorePolicy(POLICY_OBJECT_B); |
| + ExpectStateChangedCalled(true); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + ExpectInvalidateCalled(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, HandleInvalidation) { |
| + // Register and fire invalidation |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + ExpectStateChangedCalled(true); |
| + syncer::AckHandle ack = FireInvalidation(POLICY_OBJECT_A, 12, "test_payload"); |
| + |
| + // Make sure client info is set as soon as the invalidation is received. |
| + ExpectInvalidationInfo(12, "test_payload"); |
|
rlarocque
2013/07/25 19:23:40
When you wrap your expectations in functions, the
Steve Condie
2013/07/26 01:39:25
Thanks for the suggestion. For the most part, thes
rlarocque
2013/07/29 18:29:54
You've gained better line numbers, but now the tes
Steve Condie
2013/07/29 18:53:07
I actually think seeing the name of the function i
|
| + ExpectInvalidateCalled(false /* unknown_version */); |
| + |
| + // Make sure invalidation is not acknowledged until the store is loaded. |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack)); |
| + ExpectInvalidationInfo(12, "test_payload"); |
| + StorePolicy(POLICY_OBJECT_A, 12); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack)); |
| + ExpectInvalidationInfo(0, std::string()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, HandleInvalidationWithUnknownVersion) { |
| + // Register and fire invalidation with unknown version. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + syncer::AckHandle ack = FireInvalidation(POLICY_OBJECT_A); |
| + |
| + // Make sure client info is not set until after the invalidation callback is |
| + // made. |
| + ExpectInvalidationInfo(0, std::string()); |
| + ExpectInvalidateCalled(); |
| + ExpectInvalidationInfo(-1, std::string()); |
| + |
| + // Make sure invalidation is not acknowledged until the store is loaded. |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack)); |
| + StorePolicy(POLICY_OBJECT_A, -1); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack)); |
| + ExpectInvalidationInfo(0, std::string()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, HandleMultipleInvalidations) { |
| + // Generate multiple invalidations. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + syncer::AckHandle ack1 = FireInvalidation(POLICY_OBJECT_A, 1, "test1"); |
| + ExpectInvalidationInfo(1, "test1"); |
| + syncer::AckHandle ack2 = FireInvalidation(POLICY_OBJECT_A, 2, "test2"); |
| + ExpectInvalidationInfo(2, "test2"); |
| + syncer::AckHandle ack3= FireInvalidation(POLICY_OBJECT_A, 3, "test3"); |
| + ExpectInvalidationInfo(3, "test3"); |
| + |
| + // Make sure the replaced invalidations are acknowledged. |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack1)); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack2)); |
| + |
| + // Make sure the invalidate callback is called once. |
| + ExpectInvalidateCalled(false /* unknown_version */); |
| + |
| + // Make sure that the last invalidation is only acknowledged after the store |
| + // is loaded with the latest version. |
| + StorePolicy(POLICY_OBJECT_A, 1); |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack3)); |
| + StorePolicy(POLICY_OBJECT_A, 2); |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack3)); |
| + StorePolicy(POLICY_OBJECT_A, 3); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack3)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, |
| + HandleMultipleInvalidationsWithUnknownVersion) { |
| + // Validate that multiple invalidations with unknown version each generate |
| + // unique invalidation version numbers. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + syncer::AckHandle ack1 = FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidationInfo(0, std::string()); |
| + ExpectInvalidateCalled(); |
| + ExpectInvalidationInfo(-1, std::string()); |
| + syncer::AckHandle ack2 = FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidationInfo(0, std::string()); |
| + ExpectInvalidateCalled(); |
| + ExpectInvalidationInfo(-2, std::string()); |
| + syncer::AckHandle ack3 = FireInvalidation(POLICY_OBJECT_A); |
| + ExpectInvalidationInfo(0, std::string()); |
| + ExpectInvalidateCalled(); |
| + ExpectInvalidationInfo(-3, std::string()); |
| + |
| + // Make sure the replaced invalidations are acknowledged. |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack1)); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack2)); |
| + |
| + // Make sure that the last invalidation is only acknowledged after the store |
| + // is loaded with the last unknown version. |
| + StorePolicy(POLICY_OBJECT_A, -1); |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack3)); |
| + StorePolicy(POLICY_OBJECT_A, -2); |
| + EXPECT_FALSE(IsInvalidationAcknowledged(ack3)); |
| + StorePolicy(POLICY_OBJECT_A, -3); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack3)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, AcknowledgeBeforeInvalidateCallback) { |
| + // Generate an invalidation. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + syncer::AckHandle ack = FireInvalidation(POLICY_OBJECT_A, 3, "test"); |
| + |
| + // Ensure that the invalidate callback is not made and the invalidation is |
| + // acknowledged if the store is loaded with the latest version before the |
| + // callback is invoked. |
| + StorePolicy(POLICY_OBJECT_A, 3); |
| + EXPECT_TRUE(IsInvalidationAcknowledged(ack)); |
| + ExpectInvalidateNotCalled(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, StateChanged) { |
| + // Before registration, changes to the invalidation service state should not |
| + // generate change state notifications. |
| + StartInvalidator(); |
| + DisableInvalidationService(); |
| + EnableInvalidationService(); |
| + ExpectStateChangedNotCalled(); |
| + |
| + // After registration, changes to the invalidation service state should |
| + // generate notifications. |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedCalled(true); |
| + DisableInvalidationService(); |
| + ExpectStateChangedCalled(false); |
| + DisableInvalidationService(); |
| + ExpectStateChangedNotCalled(); |
| + EnableInvalidationService(); |
| + ExpectStateChangedCalled(true); |
| + EnableInvalidationService(); |
| + ExpectStateChangedNotCalled(); |
| + |
| + // When the invalidation service is enabled, changes to the registration |
| + // state should generate notifications. |
| + StorePolicy(POLICY_OBJECT_NONE); |
| + ExpectStateChangedCalled(false); |
| + StorePolicy(POLICY_OBJECT_NONE); |
| + ExpectStateChangedNotCalled(); |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedCalled(true); |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedNotCalled(); |
| + |
| + // When the invalidation service is disabled, changes to the registration |
| + // state should not generate notifications. |
| + DisableInvalidationService(); |
| + ExpectStateChangedCalled(false); |
| + StorePolicy(POLICY_OBJECT_NONE); |
| + StorePolicy(POLICY_OBJECT_A); |
| + ExpectStateChangedNotCalled(); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsUnregistered) { |
| + // Store loads occurring before invalidation registration are not counted. |
| + StartInvalidator(); |
| + StorePolicy(POLICY_OBJECT_NONE, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_NONE, 0, true /* policy_changed */); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshChangedNoInvalidations)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshUnchanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedUnchanged)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsNoInvalidations) { |
| + // Store loads occurring while registered should be differentiated depending |
| + // on whether the invalidation service was enabled or not. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + DisableInvalidationService(); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + EXPECT_EQ(1, GetCount(kMetricPolicyRefreshChanged)); |
| + EXPECT_EQ(2, GetCount(kMetricPolicyRefreshChangedNoInvalidations)); |
| + EXPECT_EQ(3, GetCount(kMetricPolicyRefreshUnchanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedUnchanged)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsStoreSameTimestamp) { |
| + // Store loads with the same timestamp as the load which causes registration |
| + // are not counted. |
| + StartInvalidator(); |
| + StorePolicy( |
| + POLICY_OBJECT_A, 0, false /* policy_changed */, 12 /* timestamp */); |
| + StorePolicy( |
| + POLICY_OBJECT_A, 0, false /* policy_changed */, 12 /* timestamp */); |
| + StorePolicy( |
| + POLICY_OBJECT_A, 0, true /* policy_changed */, 12 /* timestamp */); |
| + |
| + // The next load with a different timestamp counts. |
| + StorePolicy( |
| + POLICY_OBJECT_A, 0, true /* policy_changed */, 13 /* timestamp */); |
| + |
| + EXPECT_EQ(1, GetCount(kMetricPolicyRefreshChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshChangedNoInvalidations)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshUnchanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshInvalidatedUnchanged)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, RefreshMetricsInvalidation) { |
| + // Store loads after an invalidation are counted as invalidated, even if |
| + // the loads do not result in the invalidation being acknowledged. |
| + StartInvalidator(); |
| + StorePolicy(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_A, 5, "test"); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 5, true /* policy_changed */); |
| + |
| + // Store loads after the invalidation is complete are not counted as |
| + // invalidated. |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, true /* policy_changed */); |
| + StorePolicy(POLICY_OBJECT_A, 0, false /* policy_changed */); |
| + |
| + EXPECT_EQ(3, GetCount(kMetricPolicyRefreshChanged)); |
| + EXPECT_EQ(0, GetCount(kMetricPolicyRefreshChangedNoInvalidations)); |
| + EXPECT_EQ(4, GetCount(kMetricPolicyRefreshUnchanged)); |
| + EXPECT_EQ(2, GetCount(kMetricPolicyRefreshInvalidatedChanged)); |
| + EXPECT_EQ(1, GetCount(kMetricPolicyRefreshInvalidatedUnchanged)); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidatorTest, InvalidationMetrics) { |
| + // Generate a mix of versioned and unknown-version invalidations. |
| + StorePolicy(POLICY_OBJECT_A); |
| + StartInvalidator(); |
| + FireInvalidation(POLICY_OBJECT_B); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_B, 1, "test"); |
| + FireInvalidation(POLICY_OBJECT_A, 1, "test"); |
| + FireInvalidation(POLICY_OBJECT_A, 2, "test"); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_A); |
| + FireInvalidation(POLICY_OBJECT_A, 3, "test"); |
| + FireInvalidation(POLICY_OBJECT_A, 4, "test"); |
| + |
| + // Verify that received invalidations metrics are correct. |
| + EXPECT_EQ(3, GetCount(kMetricPolicyInvalidationsNoPayload)); |
| + EXPECT_EQ(4, GetCount(kMetricPolicyInvalidationsPayload)); |
| +} |
| + |
| +class CloudPolicyInvalidationReplayerTest |
| + : public testing::Test, |
| + public CloudPolicyInvalidationHandler { |
| + protected: |
| + CloudPolicyInvalidationReplayerTest(); |
| + |
| + // Enable or disable the invalidation service for the replayer. |
| + void EnableInvalidationService(); |
| + void DisableInvalidationService(); |
| + |
| + // Fire an invalidation for the replayer. |
| + void FireInvalidation(int64 version, const std::string& payload); |
| + |
| + // Fire an "incomplete" invalidation for the replayer. In this context, |
| + // incomplete means that SetInvalidationInfo is called, but InvalidatePolicy |
| + // is not called. |
| + void FireIncompleteInvalidation(int64 version, const std::string& payload); |
| + |
| + // Replay, so that expectations can be verified. |
| + void Replay(); |
| + |
| + // Returns whether SetInvalidationInfo was called and checks the parameters. |
| + bool SetInvalidationInfoCalled(int64 version, const std::string& payload); |
| + |
| + // Returns whether InvalidatePolicy was called. |
| + bool InvalidatePolicyCalled(); |
| + |
| + // Returns whether OnInvalidatorStateChanged was called. |
| + bool OnInvalidatorStateChangedCalled(); |
| + |
| + // CloudPolicyInvalidationHandler: |
| + virtual void SetInvalidationInfo( |
| + int64 version, |
| + const std::string& payload) OVERRIDE; |
| + virtual void InvalidatePolicy() OVERRIDE; |
| + virtual void OnInvalidatorStateChanged(bool invalidations_enabled) OVERRIDE; |
| + |
| + private: |
| + // The replayer object to test. |
| + CloudPolicyInvalidationReplayer replayer_; |
| + |
| + // State of CloudPolicyInvalidationHandler methods called during replay. |
| + bool set_invalidation_info_called_; |
| + int64 invalidation_version_; |
| + std::string invalidation_payload_; |
| + bool invalidate_policy_called_; |
| + bool on_invalidator_state_changed_called_; |
| +}; |
| + |
| +CloudPolicyInvalidationReplayerTest::CloudPolicyInvalidationReplayerTest() |
| + : set_invalidation_info_called_(false), |
| + invalidation_version_(0), |
| + invalidate_policy_called_(false), |
| + on_invalidator_state_changed_called_(false) {} |
| + |
| +void CloudPolicyInvalidationReplayerTest::EnableInvalidationService() { |
| + replayer_.OnInvalidatorStateChanged(true); |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::DisableInvalidationService() { |
| + replayer_.OnInvalidatorStateChanged(false); |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::FireInvalidation( |
| + int64 version, |
| + const std::string& payload) { |
| + replayer_.SetInvalidationInfo(version, payload); |
| + replayer_.InvalidatePolicy(); |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::FireIncompleteInvalidation( |
| + int64 version, |
| + const std::string& payload) { |
| + replayer_.SetInvalidationInfo(version, payload); |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::Replay() { |
| + replayer_.Replay(this); |
| +} |
| + |
| +bool CloudPolicyInvalidationReplayerTest::SetInvalidationInfoCalled( |
| + int64 version, const std::string& payload) { |
| + EXPECT_EQ(version, invalidation_version_); |
| + EXPECT_EQ(payload, invalidation_payload_); |
| + return set_invalidation_info_called_; |
| +} |
| + |
| +bool CloudPolicyInvalidationReplayerTest::InvalidatePolicyCalled() { |
| + return invalidate_policy_called_; |
| +} |
| + |
| +bool CloudPolicyInvalidationReplayerTest::OnInvalidatorStateChangedCalled() { |
| + return on_invalidator_state_changed_called_; |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::SetInvalidationInfo( |
| + int64 version, |
| + const std::string& payload) { |
| + EXPECT_FALSE(set_invalidation_info_called_); |
| + EXPECT_FALSE(invalidate_policy_called_); |
| + set_invalidation_info_called_ = true; |
| + invalidation_version_ = version; |
| + invalidation_payload_ = payload; |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::InvalidatePolicy() { |
| + invalidate_policy_called_ = true; |
| +} |
| + |
| +void CloudPolicyInvalidationReplayerTest::OnInvalidatorStateChanged( |
| + bool invalidations_enabled) { |
| + EXPECT_FALSE(on_invalidator_state_changed_called_); |
| + EXPECT_FALSE(set_invalidation_info_called_); |
| + EXPECT_FALSE(invalidate_policy_called_); |
| + EXPECT_TRUE(invalidations_enabled); |
| + on_invalidator_state_changed_called_ = true; |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, NoCalls) { |
| + Replay(); |
| + EXPECT_FALSE(SetInvalidationInfoCalled(0, std::string())); |
| + EXPECT_FALSE(InvalidatePolicyCalled()); |
| + EXPECT_FALSE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, InvalidationsDisabled) { |
| + EnableInvalidationService(); |
| + DisableInvalidationService(); |
| + Replay(); |
| + EXPECT_FALSE(SetInvalidationInfoCalled(0, std::string())); |
| + EXPECT_FALSE(InvalidatePolicyCalled()); |
| + EXPECT_FALSE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, InvalidationsEnabled) { |
| + EnableInvalidationService(); |
| + DisableInvalidationService(); |
| + EnableInvalidationService(); |
| + Replay(); |
| + EXPECT_FALSE(SetInvalidationInfoCalled(0, std::string())); |
| + EXPECT_FALSE(InvalidatePolicyCalled()); |
| + EXPECT_TRUE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, Invalidation) { |
| + EnableInvalidationService(); |
| + FireInvalidation(1, "test"); |
| + Replay(); |
| + EXPECT_TRUE(SetInvalidationInfoCalled(1, "test")); |
| + EXPECT_TRUE(InvalidatePolicyCalled()); |
| + EXPECT_TRUE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, MultipleInvalidations) { |
| + EnableInvalidationService(); |
| + FireInvalidation(1, "test1"); |
| + FireInvalidation(2, "test2"); |
| + FireInvalidation(3, "test3"); |
| + Replay(); |
| + EXPECT_TRUE(SetInvalidationInfoCalled(3, "test3")); |
| + EXPECT_TRUE(InvalidatePolicyCalled()); |
| + EXPECT_TRUE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, IncompleteInvalidation) { |
| + EnableInvalidationService(); |
| + FireInvalidation(1, "test1"); |
| + FireInvalidation(2, "test2"); |
| + FireIncompleteInvalidation(3, "test3"); |
| + Replay(); |
| + EXPECT_TRUE(SetInvalidationInfoCalled(3, "test3")); |
| + EXPECT_FALSE(InvalidatePolicyCalled()); |
| + EXPECT_TRUE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +TEST_F(CloudPolicyInvalidationReplayerTest, InvalidationThenServiceDisabled) { |
| + EnableInvalidationService(); |
| + FireInvalidation(1, "test"); |
| + DisableInvalidationService(); |
| + Replay(); |
| + EXPECT_TRUE(SetInvalidationInfoCalled(1, "test")); |
| + EXPECT_TRUE(InvalidatePolicyCalled()); |
| + EXPECT_FALSE(OnInvalidatorStateChangedCalled()); |
| +} |
| + |
| +} // namespace policy |