| // Copyright 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 "sync/notifier/unacked_invalidation_set.h" |
| |
| #include "base/json/json_string_value_serializer.h" |
| #include "sync/notifier/object_id_invalidation_map.h" |
| #include "sync/notifier/single_object_invalidation_set.h" |
| #include "sync/notifier/unacked_invalidation_set_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace syncer { |
| |
| class UnackedInvalidationSetTest : public testing::Test { |
| public: |
| UnackedInvalidationSetTest() |
| : kObjectId_(10, "ASDF"), |
| unacked_invalidations_(kObjectId_) {} |
| |
| SingleObjectInvalidationSet GetStoredInvalidations() { |
| ObjectIdInvalidationMap map; |
| unacked_invalidations_.ExportInvalidations(WeakHandle<AckHandler>(), &map); |
| ObjectIdSet ids = map.GetObjectIds(); |
| if (ids.find(kObjectId_) != ids.end()) { |
| return map.ForObject(kObjectId_); |
| } else { |
| return SingleObjectInvalidationSet(); |
| } |
| } |
| |
| const invalidation::ObjectId kObjectId_; |
| UnackedInvalidationSet unacked_invalidations_; |
| }; |
| |
| namespace { |
| |
| // Test storage and retrieval of zero invalidations. |
| TEST_F(UnackedInvalidationSetTest, Empty) { |
| EXPECT_EQ(0U, GetStoredInvalidations().GetSize()); |
| } |
| |
| // Test storage and retrieval of a single invalidation. |
| TEST_F(UnackedInvalidationSetTest, OneInvalidation) { |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| unacked_invalidations_.Add(inv1); |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(1U, set.GetSize()); |
| EXPECT_FALSE(set.StartsWithUnknownVersion()); |
| } |
| |
| // Test that calling Clear() returns us to the empty state. |
| TEST_F(UnackedInvalidationSetTest, Clear) { |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| unacked_invalidations_.Add(inv1); |
| unacked_invalidations_.Clear(); |
| |
| EXPECT_EQ(0U, GetStoredInvalidations().GetSize()); |
| } |
| |
| // Test that repeated unknown version invalidations are squashed together. |
| TEST_F(UnackedInvalidationSetTest, UnknownVersions) { |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_); |
| Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_); |
| unacked_invalidations_.Add(inv1); |
| unacked_invalidations_.Add(inv2); |
| unacked_invalidations_.Add(inv3); |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(2U, set.GetSize()); |
| EXPECT_TRUE(set.StartsWithUnknownVersion()); |
| } |
| |
| // Tests that no truncation occurs while we're under the limit. |
| TEST_F(UnackedInvalidationSetTest, NoTruncation) { |
| size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations; |
| |
| for (size_t i = 0; i < kMax; ++i) { |
| Invalidation inv = Invalidation::Init(kObjectId_, i, "payload"); |
| unacked_invalidations_.Add(inv); |
| } |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(kMax, set.GetSize()); |
| EXPECT_FALSE(set.StartsWithUnknownVersion()); |
| EXPECT_EQ(0, set.begin()->version()); |
| EXPECT_EQ(kMax-1, static_cast<size_t>(set.rbegin()->version())); |
| } |
| |
| // Test that truncation happens as we reach the limit. |
| TEST_F(UnackedInvalidationSetTest, Truncation) { |
| size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations; |
| |
| for (size_t i = 0; i < kMax + 1; ++i) { |
| Invalidation inv = Invalidation::Init(kObjectId_, i, "payload"); |
| unacked_invalidations_.Add(inv); |
| } |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(kMax, set.GetSize()); |
| EXPECT_TRUE(set.StartsWithUnknownVersion()); |
| EXPECT_TRUE(set.begin()->is_unknown_version()); |
| EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version())); |
| } |
| |
| // Test that we don't truncate while a handler is registered. |
| TEST_F(UnackedInvalidationSetTest, RegistrationAndTruncation) { |
| unacked_invalidations_.SetHandlerIsRegistered(); |
| |
| size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations; |
| |
| for (size_t i = 0; i < kMax + 1; ++i) { |
| Invalidation inv = Invalidation::Init(kObjectId_, i, "payload"); |
| unacked_invalidations_.Add(inv); |
| } |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(kMax+1, set.GetSize()); |
| EXPECT_FALSE(set.StartsWithUnknownVersion()); |
| EXPECT_EQ(0, set.begin()->version()); |
| EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version())); |
| |
| // Unregistering should re-enable truncation. |
| unacked_invalidations_.SetHandlerIsUnregistered(); |
| SingleObjectInvalidationSet set2 = GetStoredInvalidations(); |
| ASSERT_EQ(kMax, set2.GetSize()); |
| EXPECT_TRUE(set2.StartsWithUnknownVersion()); |
| EXPECT_TRUE(set2.begin()->is_unknown_version()); |
| EXPECT_EQ(kMax, static_cast<size_t>(set2.rbegin()->version())); |
| } |
| |
| // Test acknowledgement. |
| TEST_F(UnackedInvalidationSetTest, Acknowledge) { |
| // inv2 is included in this test just to make sure invalidations that |
| // are supposed to be unaffected by this operation will be unaffected. |
| |
| // We don't expect to be receiving acks or drops unless this flag is set. |
| // Not that it makes much of a difference in behavior. |
| unacked_invalidations_.SetHandlerIsRegistered(); |
| |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_); |
| AckHandle inv1_handle = inv1.ack_handle(); |
| |
| unacked_invalidations_.Add(inv1); |
| unacked_invalidations_.Add(inv2); |
| |
| unacked_invalidations_.Acknowledge(inv1_handle); |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| EXPECT_EQ(1U, set.GetSize()); |
| EXPECT_TRUE(set.StartsWithUnknownVersion()); |
| } |
| |
| // Test drops. |
| TEST_F(UnackedInvalidationSetTest, Drop) { |
| // inv2 is included in this test just to make sure invalidations that |
| // are supposed to be unaffected by this operation will be unaffected. |
| |
| // We don't expect to be receiving acks or drops unless this flag is set. |
| // Not that it makes much of a difference in behavior. |
| unacked_invalidations_.SetHandlerIsRegistered(); |
| |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| Invalidation inv2 = Invalidation::Init(kObjectId_, 15, "payload"); |
| AckHandle inv1_handle = inv1.ack_handle(); |
| |
| unacked_invalidations_.Add(inv1); |
| unacked_invalidations_.Add(inv2); |
| |
| unacked_invalidations_.Drop(inv1_handle); |
| |
| SingleObjectInvalidationSet set = GetStoredInvalidations(); |
| ASSERT_EQ(2U, set.GetSize()); |
| EXPECT_TRUE(set.StartsWithUnknownVersion()); |
| EXPECT_EQ(15, set.rbegin()->version()); |
| } |
| |
| class UnackedInvalidationSetSerializationTest |
| : public UnackedInvalidationSetTest { |
| public: |
| UnackedInvalidationSet SerializeDeserialize() { |
| scoped_ptr<base::DictionaryValue> value = unacked_invalidations_.ToValue(); |
| UnackedInvalidationSet deserialized(kObjectId_); |
| deserialized.ResetFromValue(*value.get()); |
| return deserialized; |
| } |
| }; |
| |
| TEST_F(UnackedInvalidationSetSerializationTest, Empty) { |
| UnackedInvalidationSet deserialized = SerializeDeserialize(); |
| EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized)); |
| } |
| |
| TEST_F(UnackedInvalidationSetSerializationTest, OneInvalidation) { |
| Invalidation inv = Invalidation::Init(kObjectId_, 10, "payload"); |
| unacked_invalidations_.Add(inv); |
| |
| UnackedInvalidationSet deserialized = SerializeDeserialize(); |
| EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized)); |
| } |
| |
| TEST_F(UnackedInvalidationSetSerializationTest, WithUnknownVersion) { |
| Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload"); |
| Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_); |
| Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_); |
| unacked_invalidations_.Add(inv1); |
| unacked_invalidations_.Add(inv2); |
| unacked_invalidations_.Add(inv3); |
| |
| UnackedInvalidationSet deserialized = SerializeDeserialize(); |
| EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized)); |
| } |
| |
| } // namespace |
| |
| } // namespace syncer |