• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sync/notifier/unacked_invalidation_set.h"
6 
7 #include "base/json/json_string_value_serializer.h"
8 #include "sync/notifier/object_id_invalidation_map.h"
9 #include "sync/notifier/single_object_invalidation_set.h"
10 #include "sync/notifier/unacked_invalidation_set_test_util.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace syncer {
14 
15 class UnackedInvalidationSetTest : public testing::Test {
16  public:
UnackedInvalidationSetTest()17   UnackedInvalidationSetTest()
18       : kObjectId_(10, "ASDF"),
19         unacked_invalidations_(kObjectId_) {}
20 
GetStoredInvalidations()21   SingleObjectInvalidationSet GetStoredInvalidations() {
22     ObjectIdInvalidationMap map;
23     unacked_invalidations_.ExportInvalidations(WeakHandle<AckHandler>(), &map);
24     ObjectIdSet ids = map.GetObjectIds();
25     if (ids.find(kObjectId_) != ids.end()) {
26       return map.ForObject(kObjectId_);
27     } else {
28       return SingleObjectInvalidationSet();
29     }
30   }
31 
32   const invalidation::ObjectId kObjectId_;
33   UnackedInvalidationSet unacked_invalidations_;
34 };
35 
36 namespace {
37 
38 // Test storage and retrieval of zero invalidations.
TEST_F(UnackedInvalidationSetTest,Empty)39 TEST_F(UnackedInvalidationSetTest, Empty) {
40   EXPECT_EQ(0U, GetStoredInvalidations().GetSize());
41 }
42 
43 // Test storage and retrieval of a single invalidation.
TEST_F(UnackedInvalidationSetTest,OneInvalidation)44 TEST_F(UnackedInvalidationSetTest, OneInvalidation) {
45   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
46   unacked_invalidations_.Add(inv1);
47 
48   SingleObjectInvalidationSet set = GetStoredInvalidations();
49   ASSERT_EQ(1U, set.GetSize());
50   EXPECT_FALSE(set.StartsWithUnknownVersion());
51 }
52 
53 // Test that calling Clear() returns us to the empty state.
TEST_F(UnackedInvalidationSetTest,Clear)54 TEST_F(UnackedInvalidationSetTest, Clear) {
55   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
56   unacked_invalidations_.Add(inv1);
57   unacked_invalidations_.Clear();
58 
59   EXPECT_EQ(0U, GetStoredInvalidations().GetSize());
60 }
61 
62 // Test that repeated unknown version invalidations are squashed together.
TEST_F(UnackedInvalidationSetTest,UnknownVersions)63 TEST_F(UnackedInvalidationSetTest, UnknownVersions) {
64   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
65   Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
66   Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_);
67   unacked_invalidations_.Add(inv1);
68   unacked_invalidations_.Add(inv2);
69   unacked_invalidations_.Add(inv3);
70 
71   SingleObjectInvalidationSet set = GetStoredInvalidations();
72   ASSERT_EQ(2U, set.GetSize());
73   EXPECT_TRUE(set.StartsWithUnknownVersion());
74 }
75 
76 // Tests that no truncation occurs while we're under the limit.
TEST_F(UnackedInvalidationSetTest,NoTruncation)77 TEST_F(UnackedInvalidationSetTest, NoTruncation) {
78   size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
79 
80   for (size_t i = 0; i < kMax; ++i) {
81     Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
82     unacked_invalidations_.Add(inv);
83   }
84 
85   SingleObjectInvalidationSet set = GetStoredInvalidations();
86   ASSERT_EQ(kMax, set.GetSize());
87   EXPECT_FALSE(set.StartsWithUnknownVersion());
88   EXPECT_EQ(0, set.begin()->version());
89   EXPECT_EQ(kMax-1, static_cast<size_t>(set.rbegin()->version()));
90 }
91 
92 // Test that truncation happens as we reach the limit.
TEST_F(UnackedInvalidationSetTest,Truncation)93 TEST_F(UnackedInvalidationSetTest, Truncation) {
94   size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
95 
96   for (size_t i = 0; i < kMax + 1; ++i) {
97     Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
98     unacked_invalidations_.Add(inv);
99   }
100 
101   SingleObjectInvalidationSet set = GetStoredInvalidations();
102   ASSERT_EQ(kMax, set.GetSize());
103   EXPECT_TRUE(set.StartsWithUnknownVersion());
104   EXPECT_TRUE(set.begin()->is_unknown_version());
105   EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version()));
106 }
107 
108 // Test that we don't truncate while a handler is registered.
TEST_F(UnackedInvalidationSetTest,RegistrationAndTruncation)109 TEST_F(UnackedInvalidationSetTest, RegistrationAndTruncation) {
110   unacked_invalidations_.SetHandlerIsRegistered();
111 
112   size_t kMax = UnackedInvalidationSet::kMaxBufferedInvalidations;
113 
114   for (size_t i = 0; i < kMax + 1; ++i) {
115     Invalidation inv = Invalidation::Init(kObjectId_, i, "payload");
116     unacked_invalidations_.Add(inv);
117   }
118 
119   SingleObjectInvalidationSet set = GetStoredInvalidations();
120   ASSERT_EQ(kMax+1, set.GetSize());
121   EXPECT_FALSE(set.StartsWithUnknownVersion());
122   EXPECT_EQ(0, set.begin()->version());
123   EXPECT_EQ(kMax, static_cast<size_t>(set.rbegin()->version()));
124 
125   // Unregistering should re-enable truncation.
126   unacked_invalidations_.SetHandlerIsUnregistered();
127   SingleObjectInvalidationSet set2 = GetStoredInvalidations();
128   ASSERT_EQ(kMax, set2.GetSize());
129   EXPECT_TRUE(set2.StartsWithUnknownVersion());
130   EXPECT_TRUE(set2.begin()->is_unknown_version());
131   EXPECT_EQ(kMax, static_cast<size_t>(set2.rbegin()->version()));
132 }
133 
134 // Test acknowledgement.
TEST_F(UnackedInvalidationSetTest,Acknowledge)135 TEST_F(UnackedInvalidationSetTest, Acknowledge) {
136   // inv2 is included in this test just to make sure invalidations that
137   // are supposed to be unaffected by this operation will be unaffected.
138 
139   // We don't expect to be receiving acks or drops unless this flag is set.
140   // Not that it makes much of a difference in behavior.
141   unacked_invalidations_.SetHandlerIsRegistered();
142 
143   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
144   Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
145   AckHandle inv1_handle = inv1.ack_handle();
146 
147   unacked_invalidations_.Add(inv1);
148   unacked_invalidations_.Add(inv2);
149 
150   unacked_invalidations_.Acknowledge(inv1_handle);
151 
152   SingleObjectInvalidationSet set = GetStoredInvalidations();
153   EXPECT_EQ(1U, set.GetSize());
154   EXPECT_TRUE(set.StartsWithUnknownVersion());
155 }
156 
157 // Test drops.
TEST_F(UnackedInvalidationSetTest,Drop)158 TEST_F(UnackedInvalidationSetTest, Drop) {
159   // inv2 is included in this test just to make sure invalidations that
160   // are supposed to be unaffected by this operation will be unaffected.
161 
162   // We don't expect to be receiving acks or drops unless this flag is set.
163   // Not that it makes much of a difference in behavior.
164   unacked_invalidations_.SetHandlerIsRegistered();
165 
166   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
167   Invalidation inv2 = Invalidation::Init(kObjectId_, 15, "payload");
168   AckHandle inv1_handle = inv1.ack_handle();
169 
170   unacked_invalidations_.Add(inv1);
171   unacked_invalidations_.Add(inv2);
172 
173   unacked_invalidations_.Drop(inv1_handle);
174 
175   SingleObjectInvalidationSet set = GetStoredInvalidations();
176   ASSERT_EQ(2U, set.GetSize());
177   EXPECT_TRUE(set.StartsWithUnknownVersion());
178   EXPECT_EQ(15, set.rbegin()->version());
179 }
180 
181 class UnackedInvalidationSetSerializationTest
182     : public UnackedInvalidationSetTest {
183  public:
SerializeDeserialize()184   UnackedInvalidationSet SerializeDeserialize() {
185     scoped_ptr<base::DictionaryValue> value = unacked_invalidations_.ToValue();
186     UnackedInvalidationSet deserialized(kObjectId_);
187     deserialized.ResetFromValue(*value.get());
188     return deserialized;
189   }
190 };
191 
TEST_F(UnackedInvalidationSetSerializationTest,Empty)192 TEST_F(UnackedInvalidationSetSerializationTest, Empty) {
193   UnackedInvalidationSet deserialized = SerializeDeserialize();
194   EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized));
195 }
196 
TEST_F(UnackedInvalidationSetSerializationTest,OneInvalidation)197 TEST_F(UnackedInvalidationSetSerializationTest, OneInvalidation) {
198   Invalidation inv = Invalidation::Init(kObjectId_, 10, "payload");
199   unacked_invalidations_.Add(inv);
200 
201   UnackedInvalidationSet deserialized = SerializeDeserialize();
202   EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized));
203 }
204 
TEST_F(UnackedInvalidationSetSerializationTest,WithUnknownVersion)205 TEST_F(UnackedInvalidationSetSerializationTest, WithUnknownVersion) {
206   Invalidation inv1 = Invalidation::Init(kObjectId_, 10, "payload");
207   Invalidation inv2 = Invalidation::InitUnknownVersion(kObjectId_);
208   Invalidation inv3 = Invalidation::InitUnknownVersion(kObjectId_);
209   unacked_invalidations_.Add(inv1);
210   unacked_invalidations_.Add(inv2);
211   unacked_invalidations_.Add(inv3);
212 
213   UnackedInvalidationSet deserialized = SerializeDeserialize();
214   EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized));
215 }
216 
217 }  // namespace
218 
219 }  // namespace syncer
220