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