blob: 3553c86bb2f7c63c3f6a3b2630804e17a6c0c336 [file] [log] [blame]
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2018, The University of Memphis
4 *
5 * This file is part of PSync.
6 * See AUTHORS.md for complete list of PSync authors and contributors.
7 *
8 * PSync is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * PSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * PSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20#include "full-producer.hpp"
21#include "consumer.hpp"
22#include "unit-test-time-fixture.hpp"
23#include "detail/state.hpp"
24
25#include <boost/test/unit_test.hpp>
26#include <ndn-cxx/name.hpp>
27#include <ndn-cxx/util/dummy-client-face.hpp>
28
29#include <iostream>
30
31namespace psync {
32
33using namespace ndn;
34using namespace std;
35
36class FullSyncFixture : public tests::UnitTestTimeFixture
37{
38public:
39 FullSyncFixture()
40 : syncPrefix("psync")
41 {
42 }
43
44 void
45 addNode(int id)
46 {
47 faces[id] = std::make_shared<util::DummyClientFace>(io, util::DummyClientFace::Options{true, true});
48 userPrefixes[id] = Name("userPrefix" + to_string(id));
49 nodes[id] = make_shared<FullProducer>(40, *faces[id], syncPrefix, userPrefixes[id],
50 [] (const std::vector<MissingDataInfo>& updates) {});
51 }
52
53 Name syncPrefix;
54 shared_ptr<util::DummyClientFace> faces[4];
55 Name userPrefixes[4];
56 shared_ptr<FullProducer> nodes[4];
57};
58
59BOOST_FIXTURE_TEST_SUITE(FullSync, FullSyncFixture)
60
61BOOST_AUTO_TEST_CASE(TwoNodesSimple)
62{
63 addNode(0);
64 addNode(1);
65
66 faces[0]->linkTo(*faces[1]);
67 advanceClocks(ndn::time::milliseconds(10));
68
69 nodes[0]->publishName(userPrefixes[0]);
70 advanceClocks(ndn::time::milliseconds(10), 100);
71
72 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
73 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
74
75 nodes[1]->publishName(userPrefixes[1]);
76 advanceClocks(ndn::time::milliseconds(10), 100);
77 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
78 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
79
80 nodes[1]->publishName(userPrefixes[1]);
81 advanceClocks(ndn::time::milliseconds(10), 100);
82 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
83 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
84}
85
86BOOST_AUTO_TEST_CASE(TwoNodesForceSeqNo)
87{
88 addNode(0);
89 addNode(1);
90
91 faces[0]->linkTo(*faces[1]);
92 advanceClocks(ndn::time::milliseconds(10));
93
94 nodes[0]->publishName(userPrefixes[0], 3);
95 advanceClocks(ndn::time::milliseconds(10), 100);
96
97 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
98 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
99}
100
101BOOST_AUTO_TEST_CASE(TwoNodesWithMultipleUserNodes)
102{
103 addNode(0);
104 addNode(1);
105
106 faces[0]->linkTo(*faces[1]);
107 advanceClocks(ndn::time::milliseconds(10));
108
109 Name nodeZeroExtraUser("userPrefix0-1");
110 Name nodeOneExtraUser("userPrefix1-1");
111
112 nodes[0]->addUserNode(nodeZeroExtraUser);
113 nodes[1]->addUserNode(nodeOneExtraUser);
114
115 nodes[0]->publishName(userPrefixes[0]);
116 advanceClocks(ndn::time::milliseconds(10), 100);
117
118 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
119 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
120
121 nodes[0]->publishName(nodeZeroExtraUser);
122 advanceClocks(ndn::time::milliseconds(10), 100);
123
124 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
125 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
126
127 nodes[1]->publishName(nodeOneExtraUser);
128 advanceClocks(ndn::time::milliseconds(10), 100);
129
130 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
131 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
132}
133
134BOOST_AUTO_TEST_CASE(MultipleNodes)
135{
136 for (int i = 0; i < 4; i++) {
137 addNode(i);
138 }
139
140 for (int i = 0; i < 3; i++) {
141 faces[i]->linkTo(*faces[i + 1]);
142 }
143
144 nodes[0]->publishName(userPrefixes[0]);
145 advanceClocks(ndn::time::milliseconds(10), 100);
146 for (int i = 0; i < 4; i++) {
147 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
148 }
149
150 nodes[1]->publishName(userPrefixes[1]);
151 advanceClocks(ndn::time::milliseconds(10), 100);
152 for (int i = 0; i < 4; i++) {
153 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
154 }
155
156 nodes[1]->publishName(userPrefixes[1]);
157 advanceClocks(ndn::time::milliseconds(10), 100);
158 for (int i = 0; i < 4; i++) {
159 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
160 }
161}
162
163BOOST_AUTO_TEST_CASE(MultipleNodesSimulataneousPublish)
164{
165 for (int i = 0; i < 4; i++) {
166 addNode(i);
167 }
168
169 for (int i = 0; i < 3; i++) {
170 faces[i]->linkTo(*faces[i + 1]);
171 }
172
173 for (int i = 0; i < 4; i++) {
174 nodes[i]->publishName(userPrefixes[i]);
175 }
176
177 advanceClocks(ndn::time::milliseconds(10), 100);
178 for (int i = 0; i < 4; i++) {
179 for (int j = 0; j < 4; j++) {
180 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 1);
181 }
182 }
183
184 for (int i = 0; i < 4; i++) {
185 nodes[i]->publishName(userPrefixes[i], 4);
186 }
187
188 advanceClocks(ndn::time::milliseconds(10), 100);
189 for (int i = 0; i < 4; i++) {
190 for (int j = 0; j < 4; j++) {
191 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 4);
192 }
193 }
194}
195
196BOOST_AUTO_TEST_CASE(NetworkPartition)
197{
198 for (int i = 0; i < 4; i++) {
199 addNode(i);
200 }
201
202 for (int i = 0; i < 3; i++) {
203 faces[i]->linkTo(*faces[i + 1]);
204 }
205
206 nodes[0]->publishName(userPrefixes[0]);
207 advanceClocks(ndn::time::milliseconds(10), 100);
208 for (int i = 0; i < 4; i++) {
209 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
210 }
211
212 for (int i = 0; i < 3; i++) {
213 faces[i]->unlink();
214 }
215
216 faces[0]->linkTo(*faces[1]);
217 faces[2]->linkTo(*faces[3]);
218
219 nodes[0]->publishName(userPrefixes[0]);
220 advanceClocks(ndn::time::milliseconds(10), 100);
221 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 2);
222 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
223 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
224
225 nodes[1]->publishName(userPrefixes[1], 2);
226 advanceClocks(ndn::time::milliseconds(10), 100);
227 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
228
229 nodes[2]->publishName(userPrefixes[2], 2);
230 advanceClocks(ndn::time::milliseconds(10), 100);
231 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[2]).value_or(-1), 2);
232
233 nodes[3]->publishName(userPrefixes[3], 2);
234 advanceClocks(ndn::time::milliseconds(10), 100);
235 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[3]).value_or(-1), 2);
236
237 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
238 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
239
240 for (int i = 0; i < 3; i++) {
241 faces[i]->unlink();
242 }
243
244 for (int i = 0; i < 3; i++) {
245 faces[i]->linkTo(*faces[i + 1]);
246 }
247
248 advanceClocks(ndn::time::milliseconds(10), 100);
249 for (int i = 0; i < 4; i++) {
250 for (int j = 0; j < 4; j++) {
251 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 2);
252 }
253 }
254}
255
256BOOST_AUTO_TEST_CASE(IBFOverflow)
257{
258 addNode(0);
259 addNode(1);
260
261 faces[0]->linkTo(*faces[1]);
262 advanceClocks(ndn::time::milliseconds(10));
263
264 // 50 > 40 (expected number of entries in IBF)
265 for (int i = 0; i < 50; i++) {
266 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
267 }
268
269 for (int i = 0; i < 20; i++) {
270 // Suppose all sync data were lost for these:
271 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
272 }
273 nodes[0]->publishName(Name("userNode0-" + to_string(20)));
274 advanceClocks(ndn::time::milliseconds(10), 100);
275
276 for (int i = 0; i <= 20; i++) {
277 Name userPrefix("userNode0-" + to_string(i));
278 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
279 }
280
281 for (int i = 21; i < 49; i++) {
282 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
283 }
284 nodes[0]->publishName(Name("userNode0-49"));
285 advanceClocks(ndn::time::milliseconds(10), 100);
286
287 for (int i = 21; i < 49; i++) {
288 Name userPrefix("userNode0-" + to_string(i));
289 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
290 }
291}
292
293BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimple)
294{
295 addNode(0);
296 addNode(1);
297
298 faces[0]->linkTo(*faces[1]);
299 advanceClocks(ndn::time::milliseconds(10));
300
301 // Lowest number that triggers a decode failure for IBF size of 40
302 int totalUpdates = 47;
303
304 for (int i = 0; i <= totalUpdates; i++) {
305 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
306 if (i != totalUpdates) {
307 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
308 }
309 }
310 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
311 advanceClocks(ndn::time::milliseconds(10), 100);
312
313 // No mechanism to recover yet
314 for (int i = 0; i <= totalUpdates; i++) {
315 Name userPrefix("userNode0-" + to_string(i));
316 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
317 }
318
319 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
320 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
321
322 nodes[1]->publishName(userPrefixes[1]);
323 advanceClocks(ndn::time::milliseconds(10), 100);
324 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
325
326 nodes[0]->publishName(userPrefixes[0]);
327 advanceClocks(ndn::time::milliseconds(10), 100);
328 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
329}
330
331BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimpleSegmentedRecovery)
332{
333 addNode(0);
334 addNode(1);
335
336 // Simple content store
337 faces[0]->onSendInterest.connect([this] (const Interest& interest) {
338 for (const auto& data : faces[1]->sentData) {
339 if (data.getName() == interest.getName()) {
340 faces[0]->receive(data);
341 return;
342 }
343 }
344 faces[1]->receive(interest);
345 });
346
347 faces[0]->onSendData.connect([this] (const Data& data) {
348 faces[1]->receive(data);
349 });
350
351 faces[1]->onSendInterest.connect([this] (const Interest& interest) {
352 for (const auto& data : faces[0]->sentData) {
353 if (data.getName() == interest.getName()) {
354 faces[1]->receive(data);
355 return;
356 }
357 }
358 faces[0]->receive(interest);
359 });
360
361 faces[1]->onSendData.connect([this] (const Data& data) {
362 faces[0]->receive(data);
363 });
364
365 advanceClocks(ndn::time::milliseconds(10));
366
367 // Lowest number that triggers a decode failure for IBF size of 40
368 int totalUpdates = 270;
369
370 for (int i = 0; i <= totalUpdates; i++) {
371 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
372 if (i != totalUpdates) {
373 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
374 }
375 }
376 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
377 advanceClocks(ndn::time::milliseconds(10), 100);
378
379 // No mechanism to recover yet
380 for (int i = 0; i <= totalUpdates; i++) {
381 Name userPrefix("userNode0-" + to_string(i));
382 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
383 }
384
385 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
386 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
387
388 nodes[1]->publishName(userPrefixes[1]);
389 advanceClocks(ndn::time::milliseconds(10), 100);
390 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
391
392 nodes[0]->publishName(userPrefixes[0]);
393 advanceClocks(ndn::time::milliseconds(10), 100);
394 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
395}
396
397BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureMultipleNodes)
398{
399 for (int i = 0; i < 4; i++) {
400 addNode(i);
401 }
402
403 for (int i = 0; i < 3; i++) {
404 faces[i]->linkTo(*faces[i + 1]);
405 }
406
407 // Lowest number that triggers a decode failure for IBF size of 40
408 int totalUpdates = 47;
409
410 for (int i = 0; i <= totalUpdates; i++) {
411 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
412 if (i != totalUpdates) {
413 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
414 }
415 }
416 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
417 advanceClocks(ndn::time::milliseconds(10), 100);
418
419 // No mechanism to recover yet
420 for (int i = 0; i <= totalUpdates; i++) {
421 Name userPrefix("userNode0-" + to_string(i));
422 for (int j = 0; j < 4; j++) {
423 BOOST_CHECK_EQUAL(nodes[j]->getSeqNo(userPrefix).value_or(-1), 1);
424 }
425 }
426}
427
428BOOST_AUTO_TEST_SUITE_END()
429
430} // namespace psync