Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7215)

Unified Diff: chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc

Issue 19733003: Implement cloud policy invalidations using the invalidation service framework. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698