blob: 4e3f4dad1779c0d965820505c082fff29507f521 [file] [log] [blame]
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2012-2014 University of California, Los Angeles
4 *
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"
21#include "../unit-test-time-fixture.hpp"
22#include <ndn-cxx/util/dummy-client-face.hpp>
23#include "boost-test.hpp"
24
25namespace chronosync {
26namespace test {
27
28using std::string;
29using std::vector;
30using std::map;
31using ndn::util::DummyClientFace;
32using ndn::util::makeDummyClientFace;
33
34
35/**
36 * @brief Emulate an app that use the Socket class
37 *
38 * The app has two types of data set: one is simply string while the other is integer array.
39 * For each type of data set, the app has a specific fetching strategy.
40 */
41class SocketTestApp : noncopyable
42{
43public:
44 SocketTestApp(const Name& syncPrefix,
45 const Name& userPrefix,
46 DummyClientFace& face,
47 bool isNum)
48 : sum(0)
49 , socket(syncPrefix,
50 userPrefix,
51 face,
52 isNum ? bind(&SocketTestApp::fetchNumbers, this, _1) :
53 bind(&SocketTestApp::fetchAll, this, _1))
54 {
55 }
56
57 void
58 set(const shared_ptr<const Data>& dataPacket)
59 {
60 // std::cerr << "set Data" << std::endl;
61 Name dataName(dataPacket->getName());
62 string str2(reinterpret_cast<const char*>(dataPacket->getContent().value()),
63 dataPacket->getContent().value_size());
64 data.insert(make_pair(dataName, str2));
65 }
66
67 void
68 set(Name name, const char* buf, int len)
69 {
70 string str2(buf, len);
71 data.insert(make_pair(name, str2));
72 }
73
74 void
75 setNum(const shared_ptr<const Data>& dataPacket)
76 {
77 // std::cerr << "setNum Data" << std::endl;
78 size_t n = dataPacket->getContent().value_size() / 4;
79 const uint32_t* numbers = reinterpret_cast<const uint32_t*>(dataPacket->getContent().value());
80 for (size_t i = 0; i < n; i++) {
81 sum += numbers[i];
82 }
83 }
84
85 void
86 setNum(Name name, const uint8_t* buf, int len)
87 {
88 BOOST_ASSERT(len >= 4);
89
90 int n = len / 4;
91 const uint32_t* numbers = reinterpret_cast<const uint32_t*>(buf);
92 for (int i = 0; i < n; i++) {
93 sum += numbers[i];
94 }
95 }
96
97 void
98 fetchAll(const vector<MissingDataInfo>& v)
99 {
100 // std::cerr << "fetchAll" << std::endl;
Yingdi Yu372697f2015-02-09 14:42:39 -0800101 for (size_t i = 0; i < v.size(); i++) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800102 for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
103 socket.fetchData(v[i].session, s, [this] (const shared_ptr<const Data>& dataPacket) {
104 this->set(dataPacket);
105 });
106 }
107 }
108 }
109
110 void
111 fetchNumbers(const vector<MissingDataInfo> &v)
112 {
113 // std::cerr << "fetchNumbers" << std::endl;
Yingdi Yu372697f2015-02-09 14:42:39 -0800114 for (size_t i = 0; i < v.size(); i++) {
Qiuhan Dingfb8c9e02015-01-30 14:04:55 -0800115 for(SeqNo s = v[i].low; s <= v[i].high; ++s) {
116 socket.fetchData(v[i].session, s, [this] (const shared_ptr<const Data>& dataPacket) {
117 this->setNum(dataPacket);
118 });
119 }
120 }
121 }
122
123 string
124 toString()
125 {
126 string str = "\n";
127 for (map<Name, string>::iterator it = data.begin(); it != data.end(); ++it) {
128 str += "<";
129 str += it->first.toUri();
130 str += "|";
131 str += it->second;
132 str += ">";
133 str += "\n";
134 }
135
136 return str;
137 }
138
139 map<ndn::Name, string> data;
140 uint32_t sum;
141 Socket socket;
142};
143
144class SocketFixture : public ndn::tests::UnitTestTimeFixture
145{
146public:
147 SocketFixture()
148 : syncPrefix("/ndn/broadcast/sync")
149 {
150 syncPrefix.appendVersion();
151 userPrefix[0] = Name("/user0");
152 userPrefix[1] = Name("/user1");
153 userPrefix[2] = Name("/user2");
154
155 faces[0] = makeDummyClientFace(ref(io), {true, true});
156 faces[1] = makeDummyClientFace(ref(io), {true, true});
157 faces[2] = makeDummyClientFace(ref(io), {true, true});
158
159 for (int i = 0; i < 3; i++) {
160 readInterestOffset[i] = 0;
161 readDataOffset[i] = 0;
162 }
163 }
164
165 void
166 passPacket()
167 {
168 for (int i = 0; i < 3; i++)
169 checkFace(i);
170 }
171
172 void
173 checkFace(int sender)
174 {
175 while (faces[sender]->sentInterests.size() > readInterestOffset[sender]) {
176 for (int i = 0; i < 3; i++) {
177 if (sender != i)
178 faces[i]->receive(faces[sender]->sentInterests[readInterestOffset[sender]]);
179 }
180 readInterestOffset[sender]++;
181 }
182 while (faces[sender]->sentDatas.size() > readDataOffset[sender]) {
183 for (int i = 0; i < 3; i++) {
184 if (sender != i)
185 faces[i]->receive(faces[sender]->sentDatas[readDataOffset[sender]]);
186 }
187 readDataOffset[sender]++;
188 }
189 }
190
191 void
192 createSocket(size_t idx, bool isNum)
193 {
194 app[idx] = make_shared<SocketTestApp>(syncPrefix, userPrefix[idx], ref(*faces[idx]), isNum);
195 sessionName[idx] = app[idx]->socket.getLogic().getSessionName();
196 }
197
198 void
199 publishAppData(size_t idx, const string& data)
200 {
201 app[idx]->socket.publishData(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(),
202 ndn::time::milliseconds(1000));
203 }
204
205 void
206 setAppData(size_t idx, SeqNo seqNo, const string& data)
207 {
208 Name dataName = sessionName[idx];
209 dataName.appendNumber(seqNo);
210 app[idx]->set(dataName, data.c_str(), data.size());
211 }
212
213 void
214 publishAppNum(size_t idx, const uint8_t* buf, size_t size)
215 {
216 app[idx]->socket.publishData(buf, size, ndn::time::milliseconds(1000));
217 }
218
219 void
220 setAppNum(size_t idx, SeqNo seqNo, const uint8_t* buf, size_t size)
221 {
222 Name dataName = sessionName[idx];
223 dataName.appendNumber(seqNo);
224 app[idx]->setNum(dataName, buf, size);
225 }
226
227 Name syncPrefix;
228 Name userPrefix[3];
229 Name sessionName[3];
230
231 shared_ptr<DummyClientFace> faces[3];
232 shared_ptr<SocketTestApp> app[3];
233
234 size_t readInterestOffset[3];
235 size_t readDataOffset[3];
236};
237
238
239
240BOOST_FIXTURE_TEST_SUITE(SocketTests, SocketFixture)
241
242BOOST_AUTO_TEST_CASE(BasicData)
243{
244 createSocket(0, false);
245 advanceClocks(ndn::time::milliseconds(10), 5);
246 createSocket(1, false);
247 advanceClocks(ndn::time::milliseconds(10), 5);
248 createSocket(2, false);
249 advanceClocks(ndn::time::milliseconds(10), 5);
250
251 string data0 = "Very funny Scotty, now beam down my clothes";
252 publishAppData(0, data0);
253
254 for (int i = 0; i < 50; i++) {
255 advanceClocks(ndn::time::milliseconds(2), 10);
256 passPacket();
257 }
258 setAppData(0, 1, data0);
259
260 advanceClocks(ndn::time::milliseconds(10), 1);
261 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
262 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
263
264 string data1 = "Yes, give me that ketchup";
265 string data2 = "Don't look conspicuous, it draws fire";
266 publishAppData(0, data1);
267 advanceClocks(ndn::time::milliseconds(10), 1);
268 publishAppData(0, data2);
269
270 for (int i = 0; i < 50; i++) {
271 advanceClocks(ndn::time::milliseconds(2), 10);
272 passPacket();
273 }
274 setAppData(0, 2, data1);
275 advanceClocks(ndn::time::milliseconds(10), 1);
276 setAppData(0, 3, data2);
277
278 advanceClocks(ndn::time::milliseconds(10), 1);
279 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
280 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
281
282 string data3 = "You surf the Internet, I surf the real world";
283 string data4 = "I got a fortune cookie once that said 'You like Chinese food'";
284 string data5 = "Real men wear pink. Why? Because their wives make them";
285 publishAppData(2, data3);
286 advanceClocks(ndn::time::milliseconds(10), 2);
287 publishAppData(1, data4);
288 advanceClocks(ndn::time::milliseconds(10), 1);
289 publishAppData(1, data5);
290
291 for (int i = 0; i < 100; i++) {
292 advanceClocks(ndn::time::milliseconds(2), 10);
293 passPacket();
294 }
295 setAppData(2, 1, data3);
296 advanceClocks(ndn::time::milliseconds(10), 1);
297 setAppData(1, 1, data4);
298 advanceClocks(ndn::time::milliseconds(10), 1);
299 setAppData(1, 2, data5);
300
301 advanceClocks(ndn::time::milliseconds(10), 7);
302 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
303 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
304
305 string data6 = "Shakespeare says: 'Prose before hos.'";
306 string data7 = "Pick good people, talent never wears out";
307 publishAppData(0, data6);
308 publishAppData(1, data7);
309
310 for (int i = 0; i < 100; i++) {
311 advanceClocks(ndn::time::milliseconds(2), 10);
312 passPacket();
313 }
314 setAppData(0, 4, data6);
315 setAppData(1, 3, data7);
316
317 BOOST_CHECK_EQUAL(app[0]->toString(), app[1]->toString());
318 BOOST_CHECK_EQUAL(app[0]->toString(), app[2]->toString());
319}
320
321BOOST_AUTO_TEST_CASE(BasicNumber)
322{
323 createSocket(0, true);
324 advanceClocks(ndn::time::milliseconds(10), 5);
325 createSocket(1, true);
326 advanceClocks(ndn::time::milliseconds(10), 5);
327
328 uint32_t num1[5] = {0, 1, 2, 3, 4};
329 uint8_t* buf1 = reinterpret_cast<uint8_t*>(num1);
330 size_t size1 = sizeof(num1);
331 publishAppNum(0, buf1, size1);
332 advanceClocks(ndn::time::milliseconds(10), 5);
333 setAppNum(0, 0, buf1, size1);
334
335 for (int i = 0; i < 100; i++) {
336 advanceClocks(ndn::time::milliseconds(2), 10);
337 passPacket();
338 }
339 BOOST_CHECK_EQUAL(app[0]->sum, app[1]->sum);
340 BOOST_CHECK_EQUAL(app[1]->sum, 10);
341
342 uint32_t num2[5] = {9, 7, 2, 1, 1};
343 uint8_t* buf2 = reinterpret_cast<uint8_t*>(num2);
344 size_t size2 = sizeof(num2);
345 publishAppNum(1, buf2, size2);
346 setAppNum(1, 0, buf2, size2);
347
348 for (int i = 0; i < 50; i++) {
349 advanceClocks(ndn::time::milliseconds(2), 10);
350 passPacket();
351 }
352 BOOST_CHECK_EQUAL(app[0]->sum, app[1]->sum);
353 BOOST_CHECK_EQUAL(app[1]->sum, 30);
354}
355
356BOOST_AUTO_TEST_SUITE_END()
357
358} // namespace test
359} // namespace chronosync