OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "blimp/helium/syncable.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include <string> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "blimp/common/mandatory_callback.h" | |
15 #include "blimp/helium/result.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h" | |
19 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite
.h" | |
20 | |
21 namespace blimp { | |
22 namespace helium { | |
23 namespace { | |
24 | |
25 // TODO(kmarshall): Re-enable these tests once CompoundSyncable is landed. | |
26 | |
27 /* | |
28 | |
29 // This is a sample implementation that demostrates the implementation | |
30 // of the Syncable and TwoPhaseSyncable | |
31 // For simplicity of this example, the ChangeSet will be an integer. | |
32 class FakeIntSyncable : public Syncable { | |
33 public: | |
34 explicit FakeIntSyncable(RevisionGenerator* clock_gen) | |
35 : clock_gen_(clock_gen), value_(0) { | |
36 last_modified_ = clock_gen_->current(); | |
37 } | |
38 | |
39 bool ModifiedSince(const VersionVector& from) const override { | |
40 return from.local_revision() < last_modified_.local_revision(); | |
41 } | |
42 | |
43 void CreateChangesetToCurrent( | |
44 const VersionVector& from, | |
45 google::protobuf::io::CodedOutputStream* output_stream) override { | |
46 output_stream->WriteVarint32(value_); | |
47 } | |
48 | |
49 void ApplyChangeset( | |
50 const VersionVector& from, | |
51 const VersionVector& to, | |
52 google::protobuf::io::CodedInputStream* input_stream) override { | |
53 input_stream->ReadVarint32(&value_); | |
54 | |
55 // Update our clock to the latest clock | |
56 last_modified_ = to; | |
57 } | |
58 | |
59 void ReleaseCheckpointsBefore(const VersionVector& checkpoint) override { | |
60 last_modified_ = checkpoint; | |
61 } | |
62 | |
63 void SetValue(int value) { | |
64 value_ = value; | |
65 | |
66 // Increment the parent clock and update our last_modified_ value | |
67 clock_gen_->Increment(); | |
68 last_modified_ = clock_gen_->current(); | |
69 } | |
70 | |
71 int value() { return value_; } | |
72 | |
73 private: | |
74 // The last time this object was changed | |
75 RevisionGenerator* clock_gen_; | |
76 VersionVector last_modified_; | |
77 uint32_t value_; | |
78 | |
79 DISALLOW_COPY_AND_ASSIGN(FakeIntSyncable); | |
80 }; | |
81 | |
82 class ParentObjectSyncable : public TwoPhaseSyncable { | |
83 public: | |
84 explicit ParentObjectSyncable(RevisionGenerator* clock_gen) | |
85 : TwoPhaseSyncable(), child1_(clock_gen), child2_(clock_gen) {} | |
86 | |
87 void CreateChangesetToCurrent( | |
88 const VersionVector& from, | |
89 google::protobuf::io::CodedOutputStream* output_stream) override { | |
90 // Low-level serialization. | |
91 // Field format: <field count> (<field id> <varint>)*. | |
92 int count = child1_.ModifiedSince(from) + child2_.ModifiedSince(from); | |
93 output_stream->WriteVarint32(count); | |
94 if (child1_.ModifiedSince(from)) { | |
95 output_stream->WriteTag(1); | |
96 child1_.CreateChangesetToCurrent(from, output_stream); | |
97 } | |
98 | |
99 if (child2_.ModifiedSince(from)) { | |
100 output_stream->WriteTag(2); | |
101 child2_.CreateChangesetToCurrent(from, output_stream); | |
102 } | |
103 } | |
104 | |
105 void ApplyChangeset( | |
106 const VersionVector& from, | |
107 const VersionVector& to, | |
108 google::protobuf::io::CodedInputStream* input_stream) override { | |
109 uint32_t count; | |
110 CHECK(input_stream->ReadVarint32(&count)); | |
111 CHECK_GT(count, 0u); | |
112 | |
113 for (uint32_t i = 0; i < count; ++i) { | |
114 switch (input_stream->ReadTag()) { | |
115 case 1: | |
116 child1_.ApplyChangeset(from, to, input_stream); | |
117 break; | |
118 case 2: | |
119 child2_.ApplyChangeset(from, to, input_stream); | |
120 break; | |
121 } | |
122 } | |
123 } | |
124 | |
125 void ReleaseCheckpointsBefore(const VersionVector& checkpoint) override { | |
126 child1_.ReleaseCheckpointsBefore(checkpoint); | |
127 child2_.ReleaseCheckpointsBefore(checkpoint); | |
128 } | |
129 | |
130 bool ModifiedSince(const VersionVector& from) const override { | |
131 return child1_.ModifiedSince(from) || child2_.ModifiedSince(from); | |
132 } | |
133 | |
134 void PreCreateChangesetToCurrent(const VersionVector& from, | |
135 MandatoryClosure&& done) override { | |
136 done.Run(); | |
137 } | |
138 | |
139 void PostApplyChangeset(const VersionVector& from, | |
140 const VersionVector& to, | |
141 MandatoryClosure&& done) override { | |
142 done.Run(); | |
143 } | |
144 | |
145 FakeIntSyncable* mutable_child1() { return &child1_; } | |
146 FakeIntSyncable* mutable_child2() { return &child2_; } | |
147 | |
148 private: | |
149 FakeIntSyncable child1_; | |
150 FakeIntSyncable child2_; | |
151 | |
152 DISALLOW_COPY_AND_ASSIGN(ParentObjectSyncable); | |
153 }; | |
154 | |
155 class SyncableTest : public testing::Test { | |
156 public: | |
157 SyncableTest() | |
158 : last_sync_master_(master_clock_.current()), | |
159 last_sync_replica_(replica_clock_.current()), | |
160 master_(&master_clock_), | |
161 replica_(&replica_clock_) {} | |
162 | |
163 ~SyncableTest() override {} | |
164 | |
165 protected: | |
166 // Propagates pending changes from |master_| to |replica_|. | |
167 void Synchronize() { | |
168 EXPECT_TRUE(master_.ModifiedSince(last_sync_master_)); | |
169 EXPECT_FALSE(replica_.ModifiedSince(last_sync_replica_)); | |
170 | |
171 // Create the changeset stream from |master_|. | |
172 std::string changeset; | |
173 google::protobuf::io::StringOutputStream raw_output_stream(&changeset); | |
174 google::protobuf::io::CodedOutputStream output_stream(&raw_output_stream); | |
175 | |
176 master_.CreateChangesetToCurrent(last_sync_master_, &output_stream); | |
177 CHECK(!changeset.empty()); | |
178 output_stream.Trim(); | |
179 | |
180 // Apply the changeset stream to |replica_|. | |
181 google::protobuf::io::ArrayInputStream raw_input_stream(changeset.data(), | |
182 changeset.size()); | |
183 google::protobuf::io::CodedInputStream input_stream(&raw_input_stream); | |
184 | |
185 replica_.ApplyChangeset(last_sync_replica_, replica_clock_.current(), | |
186 &input_stream); | |
187 last_sync_master_ = master_clock_.current(); | |
188 master_.ReleaseCheckpointsBefore(last_sync_master_); | |
189 | |
190 // Ensure that the changeset stream was consumed in its entirety. | |
191 EXPECT_FALSE(master_.ModifiedSince(last_sync_master_)); | |
192 EXPECT_FALSE(replica_.ModifiedSince(last_sync_replica_)); | |
193 EXPECT_FALSE(input_stream.Skip(1)); | |
194 } | |
195 | |
196 RevisionGenerator master_clock_; | |
197 RevisionGenerator replica_clock_; | |
198 VersionVector last_sync_master_; | |
199 VersionVector last_sync_replica_; | |
200 ParentObjectSyncable master_; | |
201 ParentObjectSyncable replica_; | |
202 | |
203 private: | |
204 DISALLOW_COPY_AND_ASSIGN(SyncableTest); | |
205 }; | |
206 | |
207 TEST_F(SyncableTest, SequentialMutations) { | |
208 master_.mutable_child1()->SetValue(123); | |
209 Synchronize(); | |
210 EXPECT_EQ(123, replica_.mutable_child1()->value()); | |
211 | |
212 master_.mutable_child1()->SetValue(456); | |
213 Synchronize(); | |
214 EXPECT_EQ(456, replica_.mutable_child1()->value()); | |
215 } | |
216 | |
217 TEST_F(SyncableTest, MutateMultiple) { | |
218 master_.mutable_child1()->SetValue(123); | |
219 master_.mutable_child2()->SetValue(456); | |
220 Synchronize(); | |
221 EXPECT_EQ(123, replica_.mutable_child1()->value()); | |
222 EXPECT_EQ(456, replica_.mutable_child2()->value()); | |
223 } | |
224 | |
225 TEST_F(SyncableTest, MutateMultipleDiscrete) { | |
226 master_.mutable_child1()->SetValue(123); | |
227 Synchronize(); | |
228 EXPECT_EQ(123, replica_.mutable_child1()->value()); | |
229 | |
230 master_.mutable_child2()->SetValue(456); | |
231 Synchronize(); | |
232 EXPECT_EQ(123, replica_.mutable_child1()->value()); | |
233 EXPECT_EQ(456, replica_.mutable_child2()->value()); | |
234 } | |
235 | |
236 */ | |
237 | |
238 } // namespace | |
239 } // namespace helium | |
240 } // namespace blimp | |
OLD | NEW |