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