blob: 0d2b0ee377481f8787abf67dff968a8572d676bd [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 Gawande78b94ad2018-12-13 15:29:19 -060020#include "PSync/full-producer.hpp"
21#include "PSync/consumer.hpp"
22#include "PSync/detail/state.hpp"
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050023
Davide Pesavento5b3cf762020-04-03 16:20:04 -040024#include "tests/boost-test.hpp"
Davide Pesaventof91d1df2020-11-25 14:50:41 -050025#include "tests/io-fixture.hpp"
Davide Pesavento5b3cf762020-04-03 16:20:04 -040026
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050027#include <ndn-cxx/name.hpp>
28#include <ndn-cxx/util/dummy-client-face.hpp>
29
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050030namespace psync {
31
32using namespace ndn;
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050033
Davide Pesaventof91d1df2020-11-25 14:50:41 -050034class FullSyncFixture : public tests::IoFixture
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050035{
Davide Pesavento5b3cf762020-04-03 16:20:04 -040036protected:
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050037 void
38 addNode(int id)
39 {
Davide Pesavento5b3cf762020-04-03 16:20:04 -040040 BOOST_ASSERT(id >= 0 && id <= 3);
Davide Pesaventof91d1df2020-11-25 14:50:41 -050041
42 faces[id] = std::make_shared<util::DummyClientFace>(m_io, util::DummyClientFace::Options{true, true});
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050043 userPrefixes[id] = Name("userPrefix" + to_string(id));
44 nodes[id] = make_shared<FullProducer>(40, *faces[id], syncPrefix, userPrefixes[id],
Davide Pesavento5b3cf762020-04-03 16:20:04 -040045 [] (const auto&) {});
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050046 }
47
Davide Pesavento5b3cf762020-04-03 16:20:04 -040048protected:
49 const Name syncPrefix = "/psync";
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050050 shared_ptr<util::DummyClientFace> faces[4];
51 Name userPrefixes[4];
52 shared_ptr<FullProducer> nodes[4];
53};
54
Ashlesh Gawande6a5157f2019-12-09 11:49:07 -060055BOOST_FIXTURE_TEST_SUITE(TestFullSync, FullSyncFixture)
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050056
57BOOST_AUTO_TEST_CASE(TwoNodesSimple)
58{
59 addNode(0);
60 addNode(1);
61
62 faces[0]->linkTo(*faces[1]);
63 advanceClocks(ndn::time::milliseconds(10));
64
65 nodes[0]->publishName(userPrefixes[0]);
66 advanceClocks(ndn::time::milliseconds(10), 100);
67
68 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
69 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
70
71 nodes[1]->publishName(userPrefixes[1]);
72 advanceClocks(ndn::time::milliseconds(10), 100);
73 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
74 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
75
76 nodes[1]->publishName(userPrefixes[1]);
77 advanceClocks(ndn::time::milliseconds(10), 100);
78 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
79 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
80}
81
82BOOST_AUTO_TEST_CASE(TwoNodesForceSeqNo)
83{
84 addNode(0);
85 addNode(1);
86
87 faces[0]->linkTo(*faces[1]);
88 advanceClocks(ndn::time::milliseconds(10));
89
90 nodes[0]->publishName(userPrefixes[0], 3);
91 advanceClocks(ndn::time::milliseconds(10), 100);
92
93 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
94 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
95}
96
97BOOST_AUTO_TEST_CASE(TwoNodesWithMultipleUserNodes)
98{
99 addNode(0);
100 addNode(1);
101
102 faces[0]->linkTo(*faces[1]);
103 advanceClocks(ndn::time::milliseconds(10));
104
105 Name nodeZeroExtraUser("userPrefix0-1");
106 Name nodeOneExtraUser("userPrefix1-1");
107
108 nodes[0]->addUserNode(nodeZeroExtraUser);
109 nodes[1]->addUserNode(nodeOneExtraUser);
110
111 nodes[0]->publishName(userPrefixes[0]);
112 advanceClocks(ndn::time::milliseconds(10), 100);
113
114 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
115 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
116
117 nodes[0]->publishName(nodeZeroExtraUser);
118 advanceClocks(ndn::time::milliseconds(10), 100);
119
120 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
121 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
122
123 nodes[1]->publishName(nodeOneExtraUser);
124 advanceClocks(ndn::time::milliseconds(10), 100);
125
126 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
127 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
128}
129
130BOOST_AUTO_TEST_CASE(MultipleNodes)
131{
132 for (int i = 0; i < 4; i++) {
133 addNode(i);
134 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500135 for (int i = 0; i < 3; i++) {
136 faces[i]->linkTo(*faces[i + 1]);
137 }
138
139 nodes[0]->publishName(userPrefixes[0]);
140 advanceClocks(ndn::time::milliseconds(10), 100);
141 for (int i = 0; i < 4; i++) {
142 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
143 }
144
145 nodes[1]->publishName(userPrefixes[1]);
146 advanceClocks(ndn::time::milliseconds(10), 100);
147 for (int i = 0; i < 4; i++) {
148 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
149 }
150
151 nodes[1]->publishName(userPrefixes[1]);
152 advanceClocks(ndn::time::milliseconds(10), 100);
153 for (int i = 0; i < 4; i++) {
154 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
155 }
156}
157
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400158BOOST_AUTO_TEST_CASE(MultipleNodesSimultaneousPublish)
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500159{
160 for (int i = 0; i < 4; i++) {
161 addNode(i);
162 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500163 for (int i = 0; i < 3; i++) {
164 faces[i]->linkTo(*faces[i + 1]);
165 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500166 for (int i = 0; i < 4; i++) {
167 nodes[i]->publishName(userPrefixes[i]);
168 }
169
170 advanceClocks(ndn::time::milliseconds(10), 100);
171 for (int i = 0; i < 4; i++) {
172 for (int j = 0; j < 4; j++) {
173 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 1);
174 }
175 }
176
177 for (int i = 0; i < 4; i++) {
178 nodes[i]->publishName(userPrefixes[i], 4);
179 }
180
181 advanceClocks(ndn::time::milliseconds(10), 100);
182 for (int i = 0; i < 4; i++) {
183 for (int j = 0; j < 4; j++) {
184 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 4);
185 }
186 }
187}
188
189BOOST_AUTO_TEST_CASE(NetworkPartition)
190{
191 for (int i = 0; i < 4; i++) {
192 addNode(i);
193 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500194 for (int i = 0; i < 3; i++) {
195 faces[i]->linkTo(*faces[i + 1]);
196 }
197
198 nodes[0]->publishName(userPrefixes[0]);
199 advanceClocks(ndn::time::milliseconds(10), 100);
200 for (int i = 0; i < 4; i++) {
201 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
202 }
203
204 for (int i = 0; i < 3; i++) {
205 faces[i]->unlink();
206 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500207 faces[0]->linkTo(*faces[1]);
208 faces[2]->linkTo(*faces[3]);
209
210 nodes[0]->publishName(userPrefixes[0]);
211 advanceClocks(ndn::time::milliseconds(10), 100);
212 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 2);
213 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
214 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
215
216 nodes[1]->publishName(userPrefixes[1], 2);
217 advanceClocks(ndn::time::milliseconds(10), 100);
218 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
219
220 nodes[2]->publishName(userPrefixes[2], 2);
221 advanceClocks(ndn::time::milliseconds(10), 100);
222 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[2]).value_or(-1), 2);
223
224 nodes[3]->publishName(userPrefixes[3], 2);
225 advanceClocks(ndn::time::milliseconds(10), 100);
226 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[3]).value_or(-1), 2);
227
228 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
229 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
230
231 for (int i = 0; i < 3; i++) {
232 faces[i]->unlink();
233 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500234 for (int i = 0; i < 3; i++) {
235 faces[i]->linkTo(*faces[i + 1]);
236 }
237
238 advanceClocks(ndn::time::milliseconds(10), 100);
239 for (int i = 0; i < 4; i++) {
240 for (int j = 0; j < 4; j++) {
241 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 2);
242 }
243 }
244}
245
246BOOST_AUTO_TEST_CASE(IBFOverflow)
247{
248 addNode(0);
249 addNode(1);
250
251 faces[0]->linkTo(*faces[1]);
252 advanceClocks(ndn::time::milliseconds(10));
253
254 // 50 > 40 (expected number of entries in IBF)
255 for (int i = 0; i < 50; i++) {
256 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
257 }
258
259 for (int i = 0; i < 20; i++) {
260 // Suppose all sync data were lost for these:
261 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
262 }
263 nodes[0]->publishName(Name("userNode0-" + to_string(20)));
264 advanceClocks(ndn::time::milliseconds(10), 100);
265
266 for (int i = 0; i <= 20; i++) {
267 Name userPrefix("userNode0-" + to_string(i));
268 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
269 }
270
271 for (int i = 21; i < 49; i++) {
272 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
273 }
274 nodes[0]->publishName(Name("userNode0-49"));
275 advanceClocks(ndn::time::milliseconds(10), 100);
276
277 for (int i = 21; i < 49; i++) {
278 Name userPrefix("userNode0-" + to_string(i));
279 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
280 }
281}
282
283BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimple)
284{
285 addNode(0);
286 addNode(1);
287
288 faces[0]->linkTo(*faces[1]);
289 advanceClocks(ndn::time::milliseconds(10));
290
291 // Lowest number that triggers a decode failure for IBF size of 40
292 int totalUpdates = 47;
293
294 for (int i = 0; i <= totalUpdates; i++) {
295 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
296 if (i != totalUpdates) {
297 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
298 }
299 }
300 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
301 advanceClocks(ndn::time::milliseconds(10), 100);
302
303 // No mechanism to recover yet
304 for (int i = 0; i <= totalUpdates; i++) {
305 Name userPrefix("userNode0-" + to_string(i));
306 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
307 }
308
309 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
310 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
311
312 nodes[1]->publishName(userPrefixes[1]);
313 advanceClocks(ndn::time::milliseconds(10), 100);
314 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
315
316 nodes[0]->publishName(userPrefixes[0]);
317 advanceClocks(ndn::time::milliseconds(10), 100);
318 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
319}
320
321BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimpleSegmentedRecovery)
322{
323 addNode(0);
324 addNode(1);
Ashlesh Gawandeec43b362018-08-01 15:15:01 -0500325 faces[0]->linkTo(*faces[1]);
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500326
327 advanceClocks(ndn::time::milliseconds(10));
328
329 // Lowest number that triggers a decode failure for IBF size of 40
330 int totalUpdates = 270;
331
332 for (int i = 0; i <= totalUpdates; i++) {
333 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
334 if (i != totalUpdates) {
335 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
336 }
337 }
338 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
339 advanceClocks(ndn::time::milliseconds(10), 100);
340
341 // No mechanism to recover yet
342 for (int i = 0; i <= totalUpdates; i++) {
343 Name userPrefix("userNode0-" + to_string(i));
344 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
345 }
346
347 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
348 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
349
350 nodes[1]->publishName(userPrefixes[1]);
351 advanceClocks(ndn::time::milliseconds(10), 100);
352 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
353
354 nodes[0]->publishName(userPrefixes[0]);
355 advanceClocks(ndn::time::milliseconds(10), 100);
356 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
357}
358
359BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureMultipleNodes)
360{
361 for (int i = 0; i < 4; i++) {
362 addNode(i);
363 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500364 for (int i = 0; i < 3; i++) {
365 faces[i]->linkTo(*faces[i + 1]);
366 }
367
368 // Lowest number that triggers a decode failure for IBF size of 40
369 int totalUpdates = 47;
370
371 for (int i = 0; i <= totalUpdates; i++) {
372 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
373 if (i != totalUpdates) {
374 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
375 }
376 }
377 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
378 advanceClocks(ndn::time::milliseconds(10), 100);
379
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500380 for (int i = 0; i <= totalUpdates; i++) {
381 Name userPrefix("userNode0-" + to_string(i));
382 for (int j = 0; j < 4; j++) {
383 BOOST_CHECK_EQUAL(nodes[j]->getSeqNo(userPrefix).value_or(-1), 1);
384 }
385 }
386}
387
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600388BOOST_AUTO_TEST_CASE(DelayedSecondSegment)
389{
390 addNode(0);
391
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800392 int i = 0;
393 State state;
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400394 std::shared_ptr<Buffer> compressed;
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800395 do {
396 Name prefixToPublish("userNode0-" + to_string(i++));
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600397 nodes[0]->addUserNode(prefixToPublish);
398 nodes[0]->publishName(prefixToPublish);
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800399
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400400 state.addContent(Name(prefixToPublish).appendNumber(nodes[0]->m_prefixes[prefixToPublish]));
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800401
402 auto block = state.wireEncode();
403 compressed = compress(nodes[0]->m_contentCompression, block.wire(), block.size());
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400404 } while (compressed->size() < (MAX_NDN_PACKET_SIZE >> 1));
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600405
406 advanceClocks(ndn::time::milliseconds(10), 100);
407
408 Name syncInterestName(syncPrefix);
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800409 IBLT iblt(40, nodes[0]->m_ibltCompression);
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600410 iblt.appendToName(syncInterestName);
411
412 nodes[0]->onSyncInterest(syncPrefix, Interest(syncInterestName));
413
414 advanceClocks(ndn::time::milliseconds(10));
415
416 BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 2);
417 // Expire contents from segmentPublisher
418 advanceClocks(ndn::time::milliseconds(10), 100);
419 BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 0);
420
421 // Get data name from face and increase segment number to form next interest
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400422 BOOST_REQUIRE(!faces[0]->sentData.empty());
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600423 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
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400434 BOOST_REQUIRE(!faces[0]->sentData.empty());
435 BOOST_CHECK_EQUAL(faces[0]->sentData.front().getName().at(-1).toSegment(), 1);
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600436}
437
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500438BOOST_AUTO_TEST_SUITE_END()
439
Ashlesh Gawanded51690a2019-11-11 22:51:06 -0600440} // namespace psync