Home | History | Annotate | Download | only in notifier
      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:
     17   UnackedInvalidationSetTest()
     18       : kObjectId_(10, "ASDF"),
     19         unacked_invalidations_(kObjectId_) {}
     20 
     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.
     39 TEST_F(UnackedInvalidationSetTest, Empty) {
     40   EXPECT_EQ(0U, GetStoredInvalidations().GetSize());
     41 }
     42 
     43 // Test storage and retrieval of a single invalidation.
     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.
     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.
     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.
     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.
     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.
    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.
    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.
    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:
    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 
    192 TEST_F(UnackedInvalidationSetSerializationTest, Empty) {
    193   UnackedInvalidationSet deserialized = SerializeDeserialize();
    194   EXPECT_THAT(unacked_invalidations_, test_util::Eq(deserialized));
    195 }
    196 
    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 
    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