blob: 38e7bf27dd2d95232d4154fbdc80edd03a30df7a [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"
25#include "tests/unit-test-time-fixture.hpp"
26
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
34class FullSyncFixture : public tests::UnitTestTimeFixture
35{
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);
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050041 faces[id] = std::make_shared<util::DummyClientFace>(io, util::DummyClientFace::Options{true, true});
42 userPrefixes[id] = Name("userPrefix" + to_string(id));
43 nodes[id] = make_shared<FullProducer>(40, *faces[id], syncPrefix, userPrefixes[id],
Davide Pesavento5b3cf762020-04-03 16:20:04 -040044 [] (const auto&) {});
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050045 }
46
Davide Pesavento5b3cf762020-04-03 16:20:04 -040047protected:
48 const Name syncPrefix = "/psync";
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050049 shared_ptr<util::DummyClientFace> faces[4];
50 Name userPrefixes[4];
51 shared_ptr<FullProducer> nodes[4];
52};
53
Ashlesh Gawande6a5157f2019-12-09 11:49:07 -060054BOOST_FIXTURE_TEST_SUITE(TestFullSync, FullSyncFixture)
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -050055
56BOOST_AUTO_TEST_CASE(TwoNodesSimple)
57{
58 addNode(0);
59 addNode(1);
60
61 faces[0]->linkTo(*faces[1]);
62 advanceClocks(ndn::time::milliseconds(10));
63
64 nodes[0]->publishName(userPrefixes[0]);
65 advanceClocks(ndn::time::milliseconds(10), 100);
66
67 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
68 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
69
70 nodes[1]->publishName(userPrefixes[1]);
71 advanceClocks(ndn::time::milliseconds(10), 100);
72 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
73 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).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), 2);
78 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
79}
80
81BOOST_AUTO_TEST_CASE(TwoNodesForceSeqNo)
82{
83 addNode(0);
84 addNode(1);
85
86 faces[0]->linkTo(*faces[1]);
87 advanceClocks(ndn::time::milliseconds(10));
88
89 nodes[0]->publishName(userPrefixes[0], 3);
90 advanceClocks(ndn::time::milliseconds(10), 100);
91
92 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
93 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 3);
94}
95
96BOOST_AUTO_TEST_CASE(TwoNodesWithMultipleUserNodes)
97{
98 addNode(0);
99 addNode(1);
100
101 faces[0]->linkTo(*faces[1]);
102 advanceClocks(ndn::time::milliseconds(10));
103
104 Name nodeZeroExtraUser("userPrefix0-1");
105 Name nodeOneExtraUser("userPrefix1-1");
106
107 nodes[0]->addUserNode(nodeZeroExtraUser);
108 nodes[1]->addUserNode(nodeOneExtraUser);
109
110 nodes[0]->publishName(userPrefixes[0]);
111 advanceClocks(ndn::time::milliseconds(10), 100);
112
113 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
114 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
115
116 nodes[0]->publishName(nodeZeroExtraUser);
117 advanceClocks(ndn::time::milliseconds(10), 100);
118
119 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
120 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeZeroExtraUser).value_or(-1), 1);
121
122 nodes[1]->publishName(nodeOneExtraUser);
123 advanceClocks(ndn::time::milliseconds(10), 100);
124
125 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
126 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(nodeOneExtraUser).value_or(-1), 1);
127}
128
129BOOST_AUTO_TEST_CASE(MultipleNodes)
130{
131 for (int i = 0; i < 4; i++) {
132 addNode(i);
133 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500134 for (int i = 0; i < 3; i++) {
135 faces[i]->linkTo(*faces[i + 1]);
136 }
137
138 nodes[0]->publishName(userPrefixes[0]);
139 advanceClocks(ndn::time::milliseconds(10), 100);
140 for (int i = 0; i < 4; i++) {
141 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
142 }
143
144 nodes[1]->publishName(userPrefixes[1]);
145 advanceClocks(ndn::time::milliseconds(10), 100);
146 for (int i = 0; i < 4; i++) {
147 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[1]).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), 2);
154 }
155}
156
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400157BOOST_AUTO_TEST_CASE(MultipleNodesSimultaneousPublish)
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500158{
159 for (int i = 0; i < 4; i++) {
160 addNode(i);
161 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500162 for (int i = 0; i < 3; i++) {
163 faces[i]->linkTo(*faces[i + 1]);
164 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500165 for (int i = 0; i < 4; i++) {
166 nodes[i]->publishName(userPrefixes[i]);
167 }
168
169 advanceClocks(ndn::time::milliseconds(10), 100);
170 for (int i = 0; i < 4; i++) {
171 for (int j = 0; j < 4; j++) {
172 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 1);
173 }
174 }
175
176 for (int i = 0; i < 4; i++) {
177 nodes[i]->publishName(userPrefixes[i], 4);
178 }
179
180 advanceClocks(ndn::time::milliseconds(10), 100);
181 for (int i = 0; i < 4; i++) {
182 for (int j = 0; j < 4; j++) {
183 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 4);
184 }
185 }
186}
187
188BOOST_AUTO_TEST_CASE(NetworkPartition)
189{
190 for (int i = 0; i < 4; i++) {
191 addNode(i);
192 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500193 for (int i = 0; i < 3; i++) {
194 faces[i]->linkTo(*faces[i + 1]);
195 }
196
197 nodes[0]->publishName(userPrefixes[0]);
198 advanceClocks(ndn::time::milliseconds(10), 100);
199 for (int i = 0; i < 4; i++) {
200 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
201 }
202
203 for (int i = 0; i < 3; i++) {
204 faces[i]->unlink();
205 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500206 faces[0]->linkTo(*faces[1]);
207 faces[2]->linkTo(*faces[3]);
208
209 nodes[0]->publishName(userPrefixes[0]);
210 advanceClocks(ndn::time::milliseconds(10), 100);
211 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 2);
212 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
213 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
214
215 nodes[1]->publishName(userPrefixes[1], 2);
216 advanceClocks(ndn::time::milliseconds(10), 100);
217 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 2);
218
219 nodes[2]->publishName(userPrefixes[2], 2);
220 advanceClocks(ndn::time::milliseconds(10), 100);
221 BOOST_CHECK_EQUAL(nodes[3]->getSeqNo(userPrefixes[2]).value_or(-1), 2);
222
223 nodes[3]->publishName(userPrefixes[3], 2);
224 advanceClocks(ndn::time::milliseconds(10), 100);
225 BOOST_CHECK_EQUAL(nodes[2]->getSeqNo(userPrefixes[3]).value_or(-1), 2);
226
227 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
228 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[3]).value_or(-1), -1);
229
230 for (int i = 0; i < 3; i++) {
231 faces[i]->unlink();
232 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500233 for (int i = 0; i < 3; i++) {
234 faces[i]->linkTo(*faces[i + 1]);
235 }
236
237 advanceClocks(ndn::time::milliseconds(10), 100);
238 for (int i = 0; i < 4; i++) {
239 for (int j = 0; j < 4; j++) {
240 BOOST_CHECK_EQUAL(nodes[i]->getSeqNo(userPrefixes[j]).value_or(-1), 2);
241 }
242 }
243}
244
245BOOST_AUTO_TEST_CASE(IBFOverflow)
246{
247 addNode(0);
248 addNode(1);
249
250 faces[0]->linkTo(*faces[1]);
251 advanceClocks(ndn::time::milliseconds(10));
252
253 // 50 > 40 (expected number of entries in IBF)
254 for (int i = 0; i < 50; i++) {
255 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
256 }
257
258 for (int i = 0; i < 20; i++) {
259 // Suppose all sync data were lost for these:
260 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
261 }
262 nodes[0]->publishName(Name("userNode0-" + to_string(20)));
263 advanceClocks(ndn::time::milliseconds(10), 100);
264
265 for (int i = 0; i <= 20; i++) {
266 Name userPrefix("userNode0-" + to_string(i));
267 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
268 }
269
270 for (int i = 21; i < 49; i++) {
271 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
272 }
273 nodes[0]->publishName(Name("userNode0-49"));
274 advanceClocks(ndn::time::milliseconds(10), 100);
275
276 for (int i = 21; i < 49; i++) {
277 Name userPrefix("userNode0-" + to_string(i));
278 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
279 }
280}
281
282BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimple)
283{
284 addNode(0);
285 addNode(1);
286
287 faces[0]->linkTo(*faces[1]);
288 advanceClocks(ndn::time::milliseconds(10));
289
290 // Lowest number that triggers a decode failure for IBF size of 40
291 int totalUpdates = 47;
292
293 for (int i = 0; i <= totalUpdates; i++) {
294 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
295 if (i != totalUpdates) {
296 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
297 }
298 }
299 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
300 advanceClocks(ndn::time::milliseconds(10), 100);
301
302 // No mechanism to recover yet
303 for (int i = 0; i <= totalUpdates; i++) {
304 Name userPrefix("userNode0-" + to_string(i));
305 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
306 }
307
308 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
309 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
310
311 nodes[1]->publishName(userPrefixes[1]);
312 advanceClocks(ndn::time::milliseconds(10), 100);
313 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
314
315 nodes[0]->publishName(userPrefixes[0]);
316 advanceClocks(ndn::time::milliseconds(10), 100);
317 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
318}
319
320BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureSimpleSegmentedRecovery)
321{
322 addNode(0);
323 addNode(1);
Ashlesh Gawandeec43b362018-08-01 15:15:01 -0500324 faces[0]->linkTo(*faces[1]);
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500325
326 advanceClocks(ndn::time::milliseconds(10));
327
328 // Lowest number that triggers a decode failure for IBF size of 40
329 int totalUpdates = 270;
330
331 for (int i = 0; i <= totalUpdates; i++) {
332 nodes[0]->addUserNode(Name("userNode0-" + to_string(i)));
333 if (i != totalUpdates) {
334 nodes[0]->updateSeqNo(Name("userNode0-" + to_string(i)), 1);
335 }
336 }
337 nodes[0]->publishName(Name("userNode0-" + to_string(totalUpdates)));
338 advanceClocks(ndn::time::milliseconds(10), 100);
339
340 // No mechanism to recover yet
341 for (int i = 0; i <= totalUpdates; i++) {
342 Name userPrefix("userNode0-" + to_string(i));
343 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefix).value_or(-1), 1);
344 }
345
346 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), -1);
347 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), -1);
348
349 nodes[1]->publishName(userPrefixes[1]);
350 advanceClocks(ndn::time::milliseconds(10), 100);
351 BOOST_CHECK_EQUAL(nodes[0]->getSeqNo(userPrefixes[1]).value_or(-1), 1);
352
353 nodes[0]->publishName(userPrefixes[0]);
354 advanceClocks(ndn::time::milliseconds(10), 100);
355 BOOST_CHECK_EQUAL(nodes[1]->getSeqNo(userPrefixes[0]).value_or(-1), 1);
356}
357
358BOOST_AUTO_TEST_CASE(DiffIBFDecodeFailureMultipleNodes)
359{
360 for (int i = 0; i < 4; i++) {
361 addNode(i);
362 }
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500363 for (int i = 0; i < 3; i++) {
364 faces[i]->linkTo(*faces[i + 1]);
365 }
366
367 // Lowest number that triggers a decode failure for IBF size of 40
368 int totalUpdates = 47;
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
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500379 for (int i = 0; i <= totalUpdates; i++) {
380 Name userPrefix("userNode0-" + to_string(i));
381 for (int j = 0; j < 4; j++) {
382 BOOST_CHECK_EQUAL(nodes[j]->getSeqNo(userPrefix).value_or(-1), 1);
383 }
384 }
385}
386
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600387BOOST_AUTO_TEST_CASE(DelayedSecondSegment)
388{
389 addNode(0);
390
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800391 int i = 0;
392 State state;
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400393 std::shared_ptr<Buffer> compressed;
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800394 do {
395 Name prefixToPublish("userNode0-" + to_string(i++));
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600396 nodes[0]->addUserNode(prefixToPublish);
397 nodes[0]->publishName(prefixToPublish);
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800398
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400399 state.addContent(Name(prefixToPublish).appendNumber(nodes[0]->m_prefixes[prefixToPublish]));
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800400
401 auto block = state.wireEncode();
402 compressed = compress(nodes[0]->m_contentCompression, block.wire(), block.size());
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400403 } while (compressed->size() < (MAX_NDN_PACKET_SIZE >> 1));
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600404
405 advanceClocks(ndn::time::milliseconds(10), 100);
406
407 Name syncInterestName(syncPrefix);
Ashlesh Gawandee23b53b2020-02-16 13:47:38 -0800408 IBLT iblt(40, nodes[0]->m_ibltCompression);
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600409 iblt.appendToName(syncInterestName);
410
411 nodes[0]->onSyncInterest(syncPrefix, Interest(syncInterestName));
412
413 advanceClocks(ndn::time::milliseconds(10));
414
415 BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 2);
416 // Expire contents from segmentPublisher
417 advanceClocks(ndn::time::milliseconds(10), 100);
418 BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 0);
419
420 // Get data name from face and increase segment number to form next interest
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400421 BOOST_REQUIRE(!faces[0]->sentData.empty());
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600422 Name dataName = faces[0]->sentData.front().getName();
Ashlesh Gawanded51690a2019-11-11 22:51:06 -0600423 Name interestName = dataName.getSubName(0, dataName.size() - 2);
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600424 interestName.appendSegment(1);
425 faces[0]->sentData.clear();
426
427 nodes[0]->onSyncInterest(syncPrefix, Interest(interestName));
428 advanceClocks(ndn::time::milliseconds(10));
429
430 // Should have repopulated SegmentPublisher
431 BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 2);
432 // Should have received the second data segment this time
Davide Pesavento5b3cf762020-04-03 16:20:04 -0400433 BOOST_REQUIRE(!faces[0]->sentData.empty());
434 BOOST_CHECK_EQUAL(faces[0]->sentData.front().getName().at(-1).toSegment(), 1);
Ashlesh Gawande2e82df12018-12-08 21:42:29 -0600435}
436
Ashlesh Gawande0b2897e2018-06-20 14:40:47 -0500437BOOST_AUTO_TEST_SUITE_END()
438
Ashlesh Gawanded51690a2019-11-11 22:51:06 -0600439} // namespace psync