blob: 3cde914b14098229b992ea8014ba6b4448211ccd [file] [log] [blame]
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
Davide Pesavento48dbab62023-08-12 16:06:52 -04003 * Copyright (c) 2012-2023 University of California, Los Angeles
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -08004 *
5 * This file is part of ChronoSync, synchronization library for distributed realtime
6 * applications for NDN.
7 *
8 * ChronoSync 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, either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * ChronoSync 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 * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "socket.hpp"
Ashlesh Gawande08784d42017-09-06 23:40:21 -050021
Davide Pesaventofae9def2019-01-29 14:34:33 -050022#include "tests/boost-test.hpp"
23#include "tests/unit-test-time-fixture.hpp"
Ashlesh Gawande08784d42017-09-06 23:40:21 -050024
25#include <ndn-cxx/util/dummy-client-face.hpp>
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080026
27namespace chronosync {
28namespace test {
29
30using std::string;
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080031
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080032/**
33 * @brief Emulate an app that use the Socket class
34 *
35 * The app has two types of data set: one is simply string while the other is integer array.
36 * For each type of data set, the app has a specific fetching strategy.
37 */
38class SocketTestApp : noncopyable
39{
40public:
41 SocketTestApp(const Name& syncPrefix,
42 const Name& userPrefix,
Davide Pesavento48dbab62023-08-12 16:06:52 -040043 ndn::DummyClientFace& face,
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080044 bool isNum)
45 : sum(0)
46 , socket(syncPrefix,
47 userPrefix,
48 face,
49 isNum ? bind(&SocketTestApp::fetchNumbers, this, _1) :
Davide Pesavento8663ed12022-07-23 03:04:27 -040050 bind(&SocketTestApp::fetchAll, this, _1),
Alexander Afanasyevbf5bc6c2018-02-19 11:26:09 -050051 Logic::DEFAULT_NAME,
52 Logic::DEFAULT_VALIDATOR,
53 Logic::DEFAULT_SYNC_INTEREST_LIFETIME,
54 name::Component::fromEscapedString("override"))
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080055 {
56 }
57
58 void
Ashlesh Gawande08784d42017-09-06 23:40:21 -050059 set(const Data& dataPacket)
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080060 {
61 // std::cerr << "set Data" << std::endl;
Ashlesh Gawande08784d42017-09-06 23:40:21 -050062 Name dataName(dataPacket.getName());
63 string str2(reinterpret_cast<const char*>(dataPacket.getContent().value()),
64 dataPacket.getContent().value_size());
Davide Pesavento8663ed12022-07-23 03:04:27 -040065 data.emplace(dataName, str2);
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080066 }
67
68 void
69 set(Name name, const char* buf, int len)
70 {
71 string str2(buf, len);
Davide Pesavento8663ed12022-07-23 03:04:27 -040072 data.emplace(name, str2);
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080073 }
74
75 void
Ashlesh Gawande08784d42017-09-06 23:40:21 -050076 setNum(const Data& dataPacket)
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080077 {
78 // std::cerr << "setNum Data" << std::endl;
Ashlesh Gawande08784d42017-09-06 23:40:21 -050079 size_t n = dataPacket.getContent().value_size() / 4;
80 const uint32_t* numbers = reinterpret_cast<const uint32_t*>(dataPacket.getContent().value());
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -080081 for (size_t i = 0; i < n; i++) {
82 sum += numbers[i];
83 }
84 }
85
86 void
87 setNum(Name name, const uint8_t* buf, int len)
88 {
89 BOOST_ASSERT(len >= 4);
90
91 int n = len / 4;
92 const uint32_t* numbers = reinterpret_cast<const uint32_t*>(buf);
93 for (int i = 0; i < n; i++) {
94 sum += numbers[i];
95 }
96 }
97
98 void
Davide Pesaventofae9def2019-01-29 14:34:33 -050099 fetchAll(const std::vector<MissingDataInfo>& v)
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800100 {
101 // std::cerr << "fetchAll" << std::endl;
Yingdi Yu372697f2015-02-09 14:42:39 -0800102 for (size_t i = 0; i < v.size(); i++) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800103 for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
Ashlesh Gawande08784d42017-09-06 23:40:21 -0500104 socket.fetchData(v[i].session, s, [this] (const Data& dataPacket) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800105 this->set(dataPacket);
106 });
107 }
108 }
109 }
110
111 void
Davide Pesaventofae9def2019-01-29 14:34:33 -0500112 fetchNumbers(const std::vector<MissingDataInfo>& v)
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800113 {
114 // std::cerr << "fetchNumbers" << std::endl;
Yingdi Yu372697f2015-02-09 14:42:39 -0800115 for (size_t i = 0; i < v.size(); i++) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800116 for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
Ashlesh Gawande08784d42017-09-06 23:40:21 -0500117 socket.fetchData(v[i].session, s, [this] (const Data& dataPacket) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800118 this->setNum(dataPacket);
119 });
120 }
121 }
122 }
123
124 string
125 toString()
126 {
127 string str = "\n";
Davide Pesaventofae9def2019-01-29 14:34:33 -0500128 for (auto it = data.begin(); it != data.end(); ++it) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800129 str += "<";
130 str += it->first.toUri();
131 str += "|";
132 str += it->second;
133 str += ">";
134 str += "\n";
135 }
136
137 return str;
138 }
139
Junxiao Shi0c7f56a2016-07-14 15:27:14 +0000140public:
Davide Pesavento8663ed12022-07-23 03:04:27 -0400141 std::map<Name, string> data;
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800142 uint32_t sum;
143 Socket socket;
144};
145
146class SocketFixture : public ndn::tests::UnitTestTimeFixture
147{
148public:
149 SocketFixture()
150 : syncPrefix("/ndn/broadcast/sync")
151 {
152 syncPrefix.appendVersion();
153 userPrefix[0] = Name("/user0");
154 userPrefix[1] = Name("/user1");
155 userPrefix[2] = Name("/user2");
156
Davide Pesavento48dbab62023-08-12 16:06:52 -0400157 faces[0].reset(new ndn::DummyClientFace(io, {true, true}));
158 faces[1].reset(new ndn::DummyClientFace(io, {true, true}));
159 faces[2].reset(new ndn::DummyClientFace(io, {true, true}));
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800160
161 for (int i = 0; i < 3; i++) {
162 readInterestOffset[i] = 0;
163 readDataOffset[i] = 0;
164 }
165 }
166
167 void
168 passPacket()
169 {
170 for (int i = 0; i < 3; i++)
171 checkFace(i);
172 }
173
174 void
175 checkFace(int sender)
176 {
177 while (faces[sender]->sentInterests.size() > readInterestOffset[sender]) {
178 for (int i = 0; i < 3; i++) {
179 if (sender != i)
180 faces[i]->receive(faces[sender]->sentInterests[readInterestOffset[sender]]);
181 }
182 readInterestOffset[sender]++;
183 }
Junxiao Shi0c7f56a2016-07-14 15:27:14 +0000184 while (faces[sender]->sentData.size() > readDataOffset[sender]) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800185 for (int i = 0; i < 3; i++) {
186 if (sender != i)
Junxiao Shi0c7f56a2016-07-14 15:27:14 +0000187 faces[i]->receive(faces[sender]->sentData[readDataOffset[sender]]);
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800188 }
189 readDataOffset[sender]++;
190 }
191 }
192
193 void
194 createSocket(size_t idx, bool isNum)
195 {
Davide Pesavento8663ed12022-07-23 03:04:27 -0400196 app[idx] = make_shared<SocketTestApp>(syncPrefix, userPrefix[idx], std::ref(*faces[idx]), isNum);
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800197 sessionName[idx] = app[idx]->socket.getLogic().getSessionName();
198 }
199
200 void
201 publishAppData(size_t idx, const string& data)
202 {
203 app[idx]->socket.publishData(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(),
204 ndn::time::milliseconds(1000));
205 }
206
207 void
Ashlesh Gawande8d1347a2017-04-03 19:10:28 -0500208 publishAppData(size_t idx, const string& data, SeqNo seqNo)
209 {
210 app[idx]->socket.publishData(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(),
211 ndn::time::milliseconds(1000), seqNo);
212 }
213
214 void
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800215 setAppData(size_t idx, SeqNo seqNo, const string& data)
216 {
217 Name dataName = sessionName[idx];
218 dataName.appendNumber(seqNo);
219 app[idx]->set(dataName, data.c_str(), data.size());
220 }
221
222 void
223 publishAppNum(size_t idx, const uint8_t* buf, size_t size)
224 {
225 app[idx]->socket.publishData(buf, size, ndn::time::milliseconds(1000));
226 }
227
228 void
229 setAppNum(size_t idx, SeqNo seqNo, const uint8_t* buf, size_t size)
230 {
231 Name dataName = sessionName[idx];
232 dataName.appendNumber(seqNo);
233 app[idx]->setNum(dataName, buf, size);
234 }
235
Junxiao Shi0c7f56a2016-07-14 15:27:14 +0000236public:
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800237 Name syncPrefix;
238 Name userPrefix[3];
239 Name sessionName[3];
240
Davide Pesavento48dbab62023-08-12 16:06:52 -0400241 std::unique_ptr<ndn::DummyClientFace> faces[3];
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800242 shared_ptr<SocketTestApp> app[3];
243
244 size_t readInterestOffset[3];
245 size_t readDataOffset[3];
246};
247
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800248BOOST_FIXTURE_TEST_SUITE(SocketTests, SocketFixture)
249
250BOOST_AUTO_TEST_CASE(BasicData)
251{
252 createSocket(0, false);
253 advanceClocks(ndn::time::milliseconds(10), 5);
254 createSocket(1, false);
255 advanceClocks(ndn::time::milliseconds(10), 5);
256 createSocket(2, false);
257 advanceClocks(ndn::time::milliseconds(10), 5);
258
259 string data0 = "Very funny Scotty, now beam down my clothes";
260 publishAppData(0, data0);
261
262 for (int i = 0; i < 50; i++) {
263 advanceClocks(ndn::time::milliseconds(2), 10);
264 passPacket();
265 }
266 setAppData(0, 1, data0);
267
268 advanceClocks(ndn::time::milliseconds(10), 1);
269 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
270 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
271
272 string data1 = "Yes, give me that ketchup";
273 string data2 = "Don't look conspicuous, it draws fire";
274 publishAppData(0, data1);
275 advanceClocks(ndn::time::milliseconds(10), 1);
276 publishAppData(0, data2);
277
278 for (int i = 0; i < 50; i++) {
279 advanceClocks(ndn::time::milliseconds(2), 10);
280 passPacket();
281 }
282 setAppData(0, 2, data1);
283 advanceClocks(ndn::time::milliseconds(10), 1);
284 setAppData(0, 3, data2);
285
286 advanceClocks(ndn::time::milliseconds(10), 1);
287 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
288 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
289
290 string data3 = "You surf the Internet, I surf the real world";
291 string data4 = "I got a fortune cookie once that said 'You like Chinese food'";
292 string data5 = "Real men wear pink. Why? Because their wives make them";
293 publishAppData(2, data3);
294 advanceClocks(ndn::time::milliseconds(10), 2);
295 publishAppData(1, data4);
296 advanceClocks(ndn::time::milliseconds(10), 1);
297 publishAppData(1, data5);
298
299 for (int i = 0; i < 100; i++) {
300 advanceClocks(ndn::time::milliseconds(2), 10);
301 passPacket();
302 }
303 setAppData(2, 1, data3);
304 advanceClocks(ndn::time::milliseconds(10), 1);
305 setAppData(1, 1, data4);
306 advanceClocks(ndn::time::milliseconds(10), 1);
307 setAppData(1, 2, data5);
308
309 advanceClocks(ndn::time::milliseconds(10), 7);
310 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
311 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
312
313 string data6 = "Shakespeare says: 'Prose before hos.'";
314 string data7 = "Pick good people, talent never wears out";
315 publishAppData(0, data6);
316 publishAppData(1, data7);
317
318 for (int i = 0; i < 100; i++) {
319 advanceClocks(ndn::time::milliseconds(2), 10);
320 passPacket();
321 }
322 setAppData(0, 4, data6);
323 setAppData(1, 3, data7);
324
325 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
326 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
Alexander Afanasyevbf5bc6c2018-02-19 11:26:09 -0500327
328 BOOST_CHECK_EQUAL(sessionName[0], Name("/user0/override"));
329 BOOST_CHECK_EQUAL(sessionName[1], Name("/user1/override"));
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800330}
331
332BOOST_AUTO_TEST_CASE(BasicNumber)
333{
334 createSocket(0, true);
335 advanceClocks(ndn::time::milliseconds(10), 5);
336 createSocket(1, true);
337 advanceClocks(ndn::time::milliseconds(10), 5);
338
339 uint32_t num1[5] = {0, 1, 2, 3, 4};
340 uint8_t* buf1 = reinterpret_cast<uint8_t*>(num1);
341 size_t size1 = sizeof(num1);
342 publishAppNum(0, buf1, size1);
343 advanceClocks(ndn::time::milliseconds(10), 5);
344 setAppNum(0, 0, buf1, size1);
345
346 for (int i = 0; i < 100; i++) {
347 advanceClocks(ndn::time::milliseconds(2), 10);
348 passPacket();
349 }
350 BOOST_CHECK_EQUAL(app[0]->sum, app[1]->sum);
351 BOOST_CHECK_EQUAL(app[1]->sum, 10);
352
353 uint32_t num2[5] = {9, 7, 2, 1, 1};
354 uint8_t* buf2 = reinterpret_cast<uint8_t*>(num2);
355 size_t size2 = sizeof(num2);
356 publishAppNum(1, buf2, size2);
357 setAppNum(1, 0, buf2, size2);
358
359 for (int i = 0; i < 50; i++) {
360 advanceClocks(ndn::time::milliseconds(2), 10);
361 passPacket();
362 }
363 BOOST_CHECK_EQUAL(app[0]->sum, app[1]->sum);
364 BOOST_CHECK_EQUAL(app[1]->sum, 30);
365}
366
Ashlesh Gawande8d1347a2017-04-03 19:10:28 -0500367BOOST_AUTO_TEST_CASE(BasicDataWithAppSeq)
368{
369 createSocket(0, false);
370 advanceClocks(ndn::time::milliseconds(10), 5);
371 createSocket(1, false);
372 advanceClocks(ndn::time::milliseconds(10), 5);
373 createSocket(2, false);
374 advanceClocks(ndn::time::milliseconds(10), 5);
375
376 string data0 = "Very funny Scotty, now beam down my clothes";
377 publishAppData(0, data0, 100);
378
379 for (int i = 0; i < 50; i++) {
380 advanceClocks(ndn::time::milliseconds(2), 10);
381 passPacket();
382 }
383 setAppData(0, 100, data0);
384
385 advanceClocks(ndn::time::milliseconds(10), 1);
386 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
387 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
388
389 string data1 = "Yes, give me that ketchup";
390 string data2 = "Don't look conspicuous, it draws fire";
391 publishAppData(0, data1, 200);
392 advanceClocks(ndn::time::milliseconds(10), 1);
393 publishAppData(0, data2, 300);
394
395 for (int i = 0; i < 50; i++) {
396 advanceClocks(ndn::time::milliseconds(2), 10);
397 passPacket();
398 }
399 setAppData(0, 200, data1);
400 advanceClocks(ndn::time::milliseconds(10), 1);
401 setAppData(0, 300, data2);
402
403 advanceClocks(ndn::time::milliseconds(10), 1);
404 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
405 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
406
407 string data3 = "You surf the Internet, I surf the real world";
408 string data4 = "I got a fortune cookie once that said 'You like Chinese food'";
409 string data5 = "Real men wear pink. Why? Because their wives make them";
410 publishAppData(2, data3, 100);
411 advanceClocks(ndn::time::milliseconds(10), 2);
412 publishAppData(1, data4, 100);
413 advanceClocks(ndn::time::milliseconds(10), 1);
414 publishAppData(1, data5, 200);
415
416 for (int i = 0; i < 100; i++) {
417 advanceClocks(ndn::time::milliseconds(2), 10);
418 passPacket();
419 }
420 setAppData(2, 100, data3);
421 advanceClocks(ndn::time::milliseconds(10), 1);
422 setAppData(1, 100, data4);
423 advanceClocks(ndn::time::milliseconds(10), 1);
424 setAppData(1, 200, data5);
425
426 advanceClocks(ndn::time::milliseconds(10), 7);
427 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
428 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
429
430 string data6 = "Shakespeare says: 'Prose before hos.'";
431 string data7 = "Pick good people, talent never wears out";
432 publishAppData(0, data6, 500);
433 publishAppData(1, data7, 300);
434
435 for (int i = 0; i < 100; i++) {
436 advanceClocks(ndn::time::milliseconds(2), 10);
437 passPacket();
438 }
439 setAppData(0, 500, data6);
440 setAppData(1, 300, data7);
441
442 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
443 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
444}
445
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800446BOOST_AUTO_TEST_SUITE_END()
447
448} // namespace test
449} // namespace chronosync