Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #include <cppunit/TestAssert.h>
18 : #include <cppunit/TestFixture.h>
19 : #include <cppunit/extensions/HelperMacros.h>
20 :
21 : #include "../../test_runner.h"
22 : #include "jami.h"
23 : #include "../common.h"
24 : #include "jamidht/swarm/swarm_manager.h"
25 : #include <algorithm>
26 :
27 : #include <dhtnet/multiplexed_socket.h>
28 : #include "nodes.h"
29 :
30 : #include <opendht/thread_pool.h>
31 :
32 : using namespace std::string_literals;
33 : using namespace std::chrono_literals;
34 : using namespace dht;
35 : using NodeId = dht::PkId;
36 :
37 : namespace jami {
38 : namespace test {
39 :
40 : constexpr size_t nNodes = 6;
41 : constexpr size_t mNodes = 3;
42 : constexpr size_t kNodes = 4;
43 :
44 : constexpr size_t BOOTSTRAP_SIZE = 2;
45 : constexpr int time = 10;
46 :
47 : struct Counter
48 : {
49 5 : Counter(unsigned t)
50 5 : : target(t)
51 5 : {}
52 : const unsigned target;
53 : unsigned added {0};
54 : std::mutex mutex;
55 : std::condition_variable cv;
56 :
57 45 : void count()
58 : {
59 45 : std::lock_guard lock(mutex);
60 45 : ++added;
61 45 : if (added == target)
62 5 : cv.notify_one();
63 45 : }
64 : bool wait(std::chrono::steady_clock::duration timeout)
65 : {
66 : std::unique_lock lock(mutex);
67 : return cv.wait_for(lock, timeout, [&] { return added == target; });
68 : }
69 5 : void wait()
70 : {
71 5 : std::unique_lock lock(mutex);
72 20 : return cv.wait(lock, [&] { return added == target; });
73 5 : }
74 : };
75 :
76 : class RoutingTableTest : public CppUnit::TestFixture
77 : {
78 : public:
79 36 : ~RoutingTableTest() { libjami::fini(); }
80 2 : static std::string name() { return "RoutingTable"; }
81 :
82 : void setUp();
83 : void tearDown();
84 :
85 : private:
86 : // ################# METHODS AND VARIABLES GENERATING DATA #################//
87 :
88 : std::mt19937_64 rd {dht::crypto::getSeededRandomEngine<std::mt19937_64>()};
89 : std::mutex channelSocketsMtx_;
90 : std::vector<NodeId> randomNodeIds;
91 : std::map<NodeId, std::map<NodeId, std::shared_ptr<dhtnet::ChannelSocketTest>>> channelSockets_;
92 : std::map<NodeId, std::shared_ptr<jami::SwarmManager>> swarmManagers;
93 : std::map<NodeId, std::set<NodeId>> nodesToConnect;
94 : std::set<NodeId> messageNode;
95 :
96 : void generaterandomNodeIds();
97 : void generateSwarmManagers();
98 363 : std::shared_ptr<jami::SwarmManager> getManager(const NodeId& id)
99 : {
100 363 : auto it = swarmManagers.find(id);
101 726 : return it == swarmManagers.end() ? nullptr : it->second;
102 : }
103 : void setKnownNodesToManager(const std::shared_ptr<SwarmManager>& sm);
104 : void needSocketCallBack(const std::shared_ptr<SwarmManager>& sm);
105 :
106 : // ################# METHODS AND VARIABLES TO TEST DATA #################//
107 :
108 : std::map<std::shared_ptr<jami::SwarmManager>, std::vector<NodeId>> knownNodesSwarmManager;
109 : std::map<NodeId, std::shared_ptr<jami::SwarmManager>> swarmManagersTest_;
110 : std::vector<NodeId> discoveredNodes;
111 :
112 : void crossNodes(NodeId nodeId);
113 : void distribution();
114 :
115 : // ################# UNIT TEST METHODES #################//
116 :
117 : void testBucketMainFunctions();
118 : void testRoutingTableMainFunctions();
119 : void testBucketKnownNodes();
120 : void testSwarmManagerConnectingNodes_1b();
121 : void testClosestNodes_1b();
122 : void testClosestNodes_multipleb();
123 : void testSendKnownNodes_1b();
124 : void testSendKnownNodes_multipleb();
125 : void testMobileNodeFunctions();
126 : void testMobileNodeAnnouncement();
127 : void testMobileNodeSplit();
128 : void testSendMobileNodes();
129 : void testBucketSplit_1n();
130 : void testSwarmManagersSmallBootstrapList();
131 : void testRoutingTableForConnectingNode();
132 : void testRoutingTableForShuttingNode();
133 : void testRoutingTableForMassShuttingsNodes();
134 : void testSwarmManagersWMobileModes();
135 :
136 2 : CPPUNIT_TEST_SUITE(RoutingTableTest);
137 1 : CPPUNIT_TEST(testBucketMainFunctions);
138 1 : CPPUNIT_TEST(testRoutingTableMainFunctions);
139 1 : CPPUNIT_TEST(testClosestNodes_multipleb);
140 1 : CPPUNIT_TEST(testBucketSplit_1n);
141 1 : CPPUNIT_TEST(testBucketKnownNodes);
142 1 : CPPUNIT_TEST(testSendKnownNodes_1b);
143 1 : CPPUNIT_TEST(testSendKnownNodes_multipleb);
144 1 : CPPUNIT_TEST(testClosestNodes_1b);
145 1 : CPPUNIT_TEST(testSwarmManagersSmallBootstrapList);
146 1 : CPPUNIT_TEST(testSwarmManagerConnectingNodes_1b);
147 1 : CPPUNIT_TEST(testRoutingTableForConnectingNode);
148 1 : CPPUNIT_TEST(testMobileNodeFunctions);
149 1 : CPPUNIT_TEST(testMobileNodeAnnouncement);
150 1 : CPPUNIT_TEST(testMobileNodeSplit);
151 1 : CPPUNIT_TEST(testSendMobileNodes);
152 1 : CPPUNIT_TEST(testSwarmManagersWMobileModes);
153 1 : CPPUNIT_TEST(testRoutingTableForMassShuttingsNodes);
154 1 : CPPUNIT_TEST(testRoutingTableForShuttingNode);
155 4 : CPPUNIT_TEST_SUITE_END();
156 : };
157 :
158 : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(RoutingTableTest, RoutingTableTest::name());
159 :
160 : void
161 18 : RoutingTableTest::setUp()
162 : {
163 18 : libjami::init(
164 : libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
165 18 : if (not Manager::instance().initialized) {
166 1 : CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
167 : }
168 :
169 18 : generaterandomNodeIds();
170 18 : generateSwarmManagers();
171 18 : }
172 :
173 : void
174 18 : RoutingTableTest::tearDown()
175 : {
176 18 : discoveredNodes.clear();
177 18 : swarmManagersTest_.clear();
178 18 : }
179 :
180 : void
181 18 : RoutingTableTest::generaterandomNodeIds()
182 : {
183 18 : auto total = nNodes + mNodes;
184 18 : randomNodeIds.reserve(total);
185 180 : for (size_t i = 0; i < total; i++) {
186 162 : NodeId node = Hash<32>::getRandom();
187 162 : randomNodeIds.emplace_back(node);
188 : }
189 18 : }
190 :
191 : void
192 18 : RoutingTableTest::generateSwarmManagers()
193 : {
194 18 : auto total = nNodes + mNodes;
195 180 : for (size_t i = 0; i < total; i++) {
196 162 : const NodeId& node = randomNodeIds.at(i);
197 413 : auto sm = std::make_shared<SwarmManager>(node, rd, std::move([](auto) {return false;}));
198 162 : i >= nNodes ? sm->setMobility(true) : sm->setMobility(false);
199 162 : swarmManagers[node] = sm;
200 162 : }
201 18 : }
202 :
203 : void
204 0 : RoutingTableTest::setKnownNodesToManager(const std::shared_ptr<SwarmManager>& sm)
205 : {
206 0 : std::uniform_int_distribution<> distrib(1, kNodes - 1);
207 :
208 0 : int numberKnownNodesToAdd = distrib(rd);
209 :
210 0 : std::uniform_int_distribution<> distribBis(0, kNodes - 1);
211 : int indexNodeIdToAdd;
212 0 : std::vector<NodeId> kNodesToAdd;
213 0 : knownNodesSwarmManager.insert({sm, {}});
214 :
215 0 : int counter = 0;
216 :
217 0 : while (counter < numberKnownNodesToAdd) {
218 0 : indexNodeIdToAdd = distribBis(rd);
219 :
220 0 : NodeId node = randomNodeIds.at(indexNodeIdToAdd);
221 0 : auto it = find(kNodesToAdd.begin(), kNodesToAdd.end(), node);
222 0 : if (sm->getId() != node && it == kNodesToAdd.end()) {
223 0 : kNodesToAdd.push_back(node);
224 0 : knownNodesSwarmManager.at(sm).push_back(node);
225 0 : counter++;
226 : }
227 : }
228 :
229 0 : sm->setKnownNodes(kNodesToAdd);
230 0 : }
231 :
232 : void
233 62 : RoutingTableTest::needSocketCallBack(const std::shared_ptr<SwarmManager>& sm)
234 : {
235 62 : sm->needSocketCb_ = [this, wsm = std::weak_ptr<SwarmManager>(sm)](const std::string& nodeId,
236 294 : auto&& onSocket) {
237 296 : Manager::instance().ioContext()->post([this, wsm, nodeId, onSocket = std::move(onSocket)] {
238 297 : auto sm = wsm.lock();
239 297 : if (!sm || sm->isShutdown())
240 16 : return;
241 281 : NodeId node = dhtnet::DeviceId(nodeId);
242 281 : std::lock_guard lk(channelSocketsMtx_);
243 542 : if (auto smRemote = getManager(node)) {
244 261 : if (sm->isShutdown()) {
245 0 : std::cout << "SWARMMANAGER " << sm->getId() << " IS SHUTDOWN" << std::endl;
246 0 : return;
247 : }
248 261 : auto myId = sm->getId();
249 261 : auto& cstRemote = channelSockets_[node][myId];
250 261 : auto& cstMe = channelSockets_[myId][node];
251 261 : if (!cstRemote) {
252 202 : cstRemote = std::make_shared<dhtnet::ChannelSocketTest>(Manager::instance().ioContext(), myId, "test1", 0);
253 : }
254 261 : if (!cstMe) {
255 202 : cstMe = std::make_shared<dhtnet::ChannelSocketTest>(Manager::instance().ioContext(), node, "test1", 0);
256 : }
257 261 : dhtnet::ChannelSocketTest::link(cstMe, cstRemote);
258 261 : onSocket(cstMe);
259 261 : smRemote->addChannel(cstRemote);
260 : }
261 297 : });
262 421 : };
263 62 : }
264 :
265 : void
266 0 : RoutingTableTest::distribution()
267 : {
268 0 : std::vector<unsigned> dist(8);
269 0 : for (const auto& sm : swarmManagers) {
270 0 : auto val = sm.second->getRoutingTable().getRoutingTableNodeCount();
271 0 : if (dist.size() <= val)
272 0 : dist.resize(val + 1);
273 0 : dist[val]++;
274 : }
275 :
276 0 : for (size_t i = 0; i < dist.size(); i++) {
277 0 : std::cout << "Swarm Managers with " << i << " nodes: " << dist[i] << std::endl;
278 : }
279 0 : }
280 :
281 : void
282 1 : RoutingTableTest::testBucketMainFunctions()
283 : {
284 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
285 :
286 1 : NodeId node0 = nodeTestIds1.at(0);
287 1 : NodeId node1 = nodeTestIds1.at(1);
288 1 : NodeId node2 = nodeTestIds1.at(2);
289 1 : NodeId node3 = nodeTestIds1.at(3);
290 :
291 1 : auto sNode1 = nodeTestChannels1.at(1);
292 1 : auto sNode2 = nodeTestChannels1.at(2);
293 1 : auto sNode3 = nodeTestChannels1.at(3);
294 :
295 1 : NodeInfo InfoNode1(true, sNode2);
296 :
297 4 : std::set<std::shared_ptr<dhtnet::ChannelSocketInterface>> socketsCheck {sNode1, sNode2};
298 1 : std::set<NodeId> nodesCheck {node1, node2};
299 :
300 1 : Bucket bucket(node0);
301 :
302 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Lower limit error", node0, bucket.getLowerLimit());
303 :
304 1 : bucket.addNode(sNode1);
305 1 : bucket.addNode(std::move(InfoNode1));
306 :
307 : //bucket.printBucket(0);
308 :
309 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have node", true, bucket.hasNode(sNode1->deviceId()));
310 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have node", true, bucket.hasNode(sNode2->deviceId()));
311 :
312 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have nodes",
313 : true,
314 : socketsCheck == bucket.getNodeSockets());
315 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have nodes", true, nodesCheck == bucket.getNodeIds());
316 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have nodes", true, bucket.isFull());
317 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known node",
318 : false,
319 : bucket.hasKnownNode(node1));
320 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known node",
321 : false,
322 : bucket.hasKnownNode(node2));
323 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
324 : false,
325 : bucket.hasConnectingNode(node1));
326 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
327 : false,
328 : bucket.hasConnectingNode(node2));
329 :
330 2 : CPPUNIT_ASSERT_THROW_MESSAGE("Supposed to be out of range",
331 : bucket.getKnownNode(5),
332 : std::out_of_range);
333 :
334 1 : bucket.removeNode(sNode1->deviceId());
335 1 : bucket.shutdownNode(sNode2->deviceId());
336 :
337 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node", false, bucket.hasNode(node1));
338 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node", false, bucket.hasNode(node2));
339 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have known node", true, bucket.hasKnownNode(node1));
340 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have known node", false, bucket.hasKnownNode(node2));
341 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have known node", false, bucket.hasMobileNode(node1));
342 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have known node", true, bucket.hasMobileNode(node2));
343 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
344 : false,
345 : bucket.hasConnectingNode(node1));
346 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
347 : false,
348 : bucket.hasConnectingNode(node2));
349 :
350 1 : auto nodeTest = bucket.randomId(rd);
351 :
352 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("One of the two nodes",
353 : true,
354 : nodeTest == node1 || nodeTest == node2);
355 :
356 1 : bucket.addNode(sNode1);
357 1 : bucket.addNode(sNode2);
358 :
359 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be 2", 2u, bucket.getNodesSize());
360 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to return zero, node already added",
361 : false,
362 : bucket.addNode(sNode2));
363 :
364 1 : bucket.removeNode(node1);
365 1 : bucket.removeNode(node2);
366 :
367 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node", false, bucket.hasNode(node1));
368 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node", false, bucket.hasNode(node2));
369 :
370 1 : bucket.addKnownNode(node3);
371 :
372 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have known node", true, bucket.hasKnownNode(node3));
373 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
374 : false,
375 : bucket.hasConnectingNode(node3));
376 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be 3", 3u, bucket.getKnownNodesSize());
377 1 : bucket.removeKnownNode(node3);
378 :
379 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known node",
380 : false,
381 : bucket.hasKnownNode(node3));
382 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have connecting node",
383 : false,
384 : bucket.hasConnectingNode(node3));
385 :
386 1 : bucket.addConnectingNode(node1);
387 1 : bucket.addConnectingNode(node2);
388 :
389 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have connecting node",
390 : true,
391 : bucket.hasConnectingNode(node1));
392 :
393 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have nodes",
394 : true,
395 : nodesCheck == bucket.getConnectingNodes());
396 :
397 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be 2", 2u, bucket.getConnectingNodesSize());
398 :
399 1 : bucket.removeConnectingNode(node2);
400 :
401 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not upposed to have connecting node",
402 : false,
403 : bucket.hasConnectingNode(node2));
404 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be 1", 1u, bucket.getConnectingNodesSize());
405 1 : }
406 :
407 : void
408 1 : RoutingTableTest::testBucketKnownNodes()
409 : {
410 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
411 :
412 1 : Bucket bucket(randomNodeIds.at(0));
413 :
414 10 : for (size_t i = 0; i < randomNodeIds.size(); i++) {
415 9 : bucket.addKnownNode(randomNodeIds.at(i));
416 : }
417 :
418 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have the known node",
419 : true,
420 : bucket.hasKnownNode(randomNodeIds.at(randomNodeIds.size() - 1)));
421 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Error with bucket size",
422 : true,
423 : bucket.getKnownNodesSize() == randomNodeIds.size());
424 1 : }
425 :
426 : void
427 1 : RoutingTableTest::testRoutingTableMainFunctions()
428 : {
429 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
430 :
431 1 : RoutingTable rt;
432 1 : NodeId node1 = nodeTestIds1.at(0);
433 1 : NodeId node2 = nodeTestIds1.at(1);
434 1 : NodeId node3 = nodeTestIds1.at(2);
435 :
436 1 : rt.setId(node1);
437 :
438 1 : rt.addKnownNode(node1);
439 1 : rt.addKnownNode(node2);
440 1 : rt.addKnownNode(node3);
441 :
442 1 : CPPUNIT_ASSERT(!rt.hasKnownNode(node1));
443 1 : CPPUNIT_ASSERT(rt.hasKnownNode(node2));
444 :
445 1 : auto knownNodes = rt.getKnownNodes();
446 :
447 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have 2 nodes", true, knownNodes.size() == 2);
448 :
449 1 : auto bucket1 = rt.findBucket(node1);
450 1 : auto bucket2 = rt.findBucket(node2);
451 1 : auto bucket3 = rt.findBucket(node3);
452 :
453 1 : rt.addNode(nodeTestChannels1.at(0), bucket1);
454 1 : rt.addNode(nodeTestChannels1.at(1), bucket2);
455 1 : rt.addNode(nodeTestChannels1.at(2), bucket3);
456 :
457 1 : CPPUNIT_ASSERT(!rt.hasNode(node1));
458 1 : CPPUNIT_ASSERT(rt.hasNode(node2));
459 1 : CPPUNIT_ASSERT(rt.hasNode(node3));
460 :
461 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist 0", false, rt.removeNode(node1));
462 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist 1", true, rt.removeNode(node2));
463 :
464 1 : rt.removeNode(node1);
465 1 : rt.removeNode(node2);
466 1 : rt.removeNode(node3);
467 :
468 1 : rt.addConnectingNode(node1);
469 1 : rt.addConnectingNode(node2);
470 1 : rt.addConnectingNode(node3);
471 :
472 1 : std::vector<NodeId> nodesCheck({node2, node3});
473 1 : const auto& nodes = rt.getConnectingNodes();
474 :
475 1 : std::vector<NodeId> connectingNode;
476 1 : connectingNode.insert(connectingNode.end(), nodes.begin(), nodes.end());
477 :
478 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist 3", false, rt.hasNode(node3));
479 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist 1", false, rt.hasConnectingNode(node1));
480 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist 3", true, rt.hasConnectingNode(node3));
481 :
482 1 : std::vector<NodeId> diff;
483 1 : std::set_difference(connectingNode.begin(),
484 : connectingNode.end(),
485 : nodes.begin(),
486 : nodes.end(),
487 : std::inserter(diff, diff.begin()));
488 :
489 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be equal", true, diff.size() == 0);
490 :
491 1 : rt.shutdownNode(node2);
492 1 : rt.shutdownNode(node3);
493 :
494 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist", true, rt.hasConnectingNode(node2));
495 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to exist", true, rt.hasConnectingNode(node3));
496 1 : }
497 :
498 : void
499 1 : RoutingTableTest::testSwarmManagerConnectingNodes_1b()
500 : {
501 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
502 :
503 1 : std::vector<NodeId> tryConnect;
504 1 : std::vector<std::string> needSocketNodes;
505 1 : std::condition_variable cv;
506 1 : std::mutex mutex;
507 1 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds1.at(0), rd, std::move([&](auto n) {
508 1 : std::lock_guard<std::mutex> lk(mutex);
509 1 : tryConnect.emplace_back(n);
510 1 : cv.notify_one();
511 1 : return false;
512 2 : }));
513 2 : sm1->needSocketCb_ = [&](const auto& n, auto) {
514 1 : std::lock_guard<std::mutex> lk(mutex);
515 1 : needSocketNodes.emplace_back(n);
516 1 : cv.notify_one();
517 2 : };
518 1 : auto& rt1 = sm1->getRoutingTable();
519 :
520 : std::vector<NodeId> toTest(
521 1 : {NodeId("053927d831827a9f7e606d4c9c9fe833922c0d35b3960dd2250085f46c0e4f41"),
522 2 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")});
523 :
524 1 : std::unique_lock lk(mutex);
525 1 : sm1->setKnownNodes(toTest);
526 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&](){return tryConnect.size() != 0 && needSocketNodes.size() != 0;}));
527 :
528 1 : CPPUNIT_ASSERT(!rt1.hasConnectingNode(nodeTestIds1.at(0)));
529 1 : CPPUNIT_ASSERT(rt1.hasConnectingNode(nodeTestIds1.at(1)));
530 1 : CPPUNIT_ASSERT(!rt1.hasKnownNode(nodeTestIds1.at(0)));
531 1 : CPPUNIT_ASSERT(!rt1.hasKnownNode(nodeTestIds1.at(1)));
532 1 : }
533 :
534 : void
535 1 : RoutingTableTest::testClosestNodes_1b()
536 : {
537 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
538 :
539 1 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds1.at(0), rd, std::move([](auto) {return false;}));
540 1 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds2.at(0), rd, std::move([](auto) {return false;}));
541 :
542 1 : auto& rt1 = sm1->getRoutingTable();
543 1 : auto& rt2 = sm2->getRoutingTable();
544 :
545 1 : auto bucket1 = rt1.findBucket(nodeTestIds1.at(0));
546 1 : auto bucket2 = rt2.findBucket(nodeTestIds2.at(0));
547 :
548 11 : for (size_t i = 0; i < nodeTestIds2.size(); i++) {
549 10 : bucket1->addNode(nodeTestChannels1.at(i));
550 10 : bucket2->addNode(nodeTestChannels2.at(i));
551 : }
552 :
553 : std::vector<NodeId>
554 1 : closestNodes1 {NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8"),
555 1 : NodeId("28f4c7e34eb4310b2e1ea3b139ee6993e6b021770ee98895a54cdd1e372bd78e"),
556 1 : NodeId("2dd1dd976c7dc234ca737c85e4ea48ad09423067a77405254424c4cdd845720d"),
557 1 : NodeId("33f280d8208f42ac34321e6e6871aecd100c2bfd4f1848482e7a7ed8ae895414")
558 :
559 4 : };
560 :
561 : std::vector<NodeId>
562 1 : closestNodes2 {NodeId("053927d831827a9f7e606d4c9c9fe833922c0d35b3960dd2250085f46c0e4f41"),
563 1 : NodeId("4f76e769061f343b2caf9eea35632d28cde8d7a67e5e0f59857733cabc538997"),
564 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8"),
565 1 : NodeId("77a9fba2c5a65812d9290c567897131b20a723e0ca2f65ef5c6b421585e4da2b")
566 :
567 4 : };
568 :
569 1 : auto closestNodes1_ = rt1.closestNodes(nodeTestIds2.at(4), 4);
570 1 : auto closestNodes2_ = rt2.closestNodes(nodeTestIds1.at(4), 4);
571 1 : auto sameIdTest = rt2.closestNodes(nodeTestIds2.at(0), 1);
572 :
573 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", true, closestNodes1 == closestNodes1_);
574 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", true, closestNodes2 == closestNodes2_);
575 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", false, nodeTestIds1.at(0) == sameIdTest.at(0));
576 1 : }
577 :
578 : void
579 1 : RoutingTableTest::testClosestNodes_multipleb()
580 : {
581 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
582 :
583 1 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds1.at(2), rd, std::move([](auto) {return false;}));
584 1 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds1.at(6), rd, std::move([](auto) {return false;}));
585 :
586 11 : for (size_t i = 0; i < nodeTestChannels1.size(); i++) {
587 10 : sm1->addChannel(nodeTestChannels1.at(i));
588 10 : sm2->addChannel(nodeTestChannels1.at(i));
589 : }
590 :
591 : std::vector<NodeId>
592 1 : closestNodes1 {NodeId("2dd1dd976c7dc234ca737c85e4ea48ad09423067a77405254424c4cdd845720d"),
593 1 : NodeId("30e177a56bd1a7969e1973ad8b210a556f6a2b15debc972661a8f555d52edbe2"),
594 2 : NodeId("312226d8fa653704758a681c8c21ec81cec914d0b8aa19e1142d3cf900e3f3b4")};
595 :
596 : std::vector<NodeId>
597 1 : closestNodes2 {NodeId("30e177a56bd1a7969e1973ad8b210a556f6a2b15debc972661a8f555d52edbe2"),
598 1 : NodeId("312226d8fa653704758a681c8c21ec81cec914d0b8aa19e1142d3cf900e3f3b4"),
599 2 : NodeId("33f280d8208f42ac34321e6e6871aecd100c2bfd4f1848482e7a7ed8ae895414")};
600 :
601 1 : auto closestNodes1_ = sm1->getRoutingTable().closestNodes(nodeTestIds1.at(5), 3);
602 1 : auto closestNodes2_ = sm2->getRoutingTable().closestNodes(nodeTestIds1.at(5), 3);
603 :
604 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", true, closestNodes1 == closestNodes1_);
605 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", true, closestNodes2 == closestNodes2_);
606 1 : }
607 :
608 : void
609 1 : RoutingTableTest::testBucketSplit_1n()
610 : {
611 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
612 :
613 1 : SwarmManager sm1(nodeTestIds2.at(0), rd, std::move([](auto) {return false;}));
614 1 : SwarmManager sm2(nodeTestIds2.at(nodeTestIds2.size() - 1), rd, std::move([](auto) {return false;}));
615 1 : SwarmManager sm3(nodeTestIds2.at(nodeTestIds2.size() / 2), rd, std::move([](auto) {return false;}));
616 :
617 1 : auto& rt1 = sm1.getRoutingTable();
618 1 : auto& rt2 = sm2.getRoutingTable();
619 1 : auto& rt3 = sm3.getRoutingTable();
620 :
621 1 : auto& b1 = rt1.getBuckets();
622 1 : auto& b2 = rt2.getBuckets();
623 1 : auto& b3 = rt3.getBuckets();
624 :
625 11 : for (size_t i = 0; i < nodeTestIds2.size(); i++) {
626 10 : auto bucket1 = rt1.findBucket(nodeTestIds2.at(i));
627 10 : auto bucket2 = rt2.findBucket(nodeTestIds2.at(i));
628 10 : auto bucket3 = rt3.findBucket(nodeTestIds2.at(i));
629 :
630 10 : rt1.addNode(nodeTestChannels2.at(i), bucket1);
631 10 : rt2.addNode(nodeTestChannels2.at(i), bucket2);
632 10 : rt3.addNode(nodeTestChannels2.at(i), bucket3);
633 : }
634 :
635 : // SM1
636 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node ntc2 0",
637 : false,
638 : rt1.hasNode(nodeTestChannels2.at(0)->deviceId()));
639 :
640 1 : int sm1BucketCounter = 1;
641 4 : for (const auto& buckIt : b1) {
642 3 : switch (sm1BucketCounter) {
643 1 : case 1:
644 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Size error", 0u, buckIt.getNodesSize());
645 1 : break;
646 :
647 1 : case 2: {
648 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(1),
649 2 : nodeTestIds2.at(2),
650 2 : nodeTestIds2.at(3),
651 2 : nodeTestIds2.at(4),
652 1 : nodeTestIds2.at(8)};
653 :
654 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
655 : true,
656 : nodesCheck == buckIt.getNodeIds());
657 1 : }
658 :
659 1 : break;
660 :
661 1 : case 3: {
662 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(5),
663 2 : nodeTestIds2.at(6),
664 2 : nodeTestIds2.at(7),
665 1 : nodeTestIds2.at(9)};
666 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
667 : true,
668 : nodesCheck == buckIt.getNodeIds());
669 1 : }
670 :
671 1 : break;
672 : }
673 :
674 3 : sm1BucketCounter++;
675 : }
676 :
677 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", 3, sm1BucketCounter - 1);
678 :
679 : // SM2
680 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node ntc2 9",
681 : false,
682 : rt2.hasNode(nodeTestChannels2.at(9)->deviceId()));
683 :
684 1 : int sm2BucketCounter = 1;
685 4 : for (const auto& buckIt : b2) {
686 3 : switch (sm2BucketCounter) {
687 1 : case 1: {
688 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(0),
689 2 : nodeTestIds2.at(1),
690 2 : nodeTestIds2.at(2),
691 2 : nodeTestIds2.at(3),
692 2 : nodeTestIds2.at(4),
693 1 : nodeTestIds2.at(8)};
694 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
695 : true,
696 : nodesCheck == buckIt.getNodeIds());
697 1 : }
698 :
699 1 : break;
700 :
701 1 : case 2: {
702 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(6), nodeTestIds2.at(7)};
703 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
704 : true,
705 : nodesCheck == buckIt.getNodeIds());
706 1 : }
707 :
708 1 : break;
709 :
710 1 : case 3:
711 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have node ntc2 5",
712 : true,
713 : buckIt.hasNode(nodeTestChannels2.at(5)->deviceId()));
714 1 : break;
715 : }
716 :
717 3 : sm2BucketCounter++;
718 : }
719 :
720 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", 3, sm2BucketCounter - 1);
721 :
722 : // SM3
723 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have node ntc2 5",
724 : false,
725 : rt3.hasNode(nodeTestChannels2.at(5)->deviceId()));
726 :
727 1 : int sm3BucketCounter = 1;
728 4 : for (const auto& buckIt : b3) {
729 3 : switch (sm3BucketCounter) {
730 1 : case 1: {
731 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(0),
732 2 : nodeTestIds2.at(1),
733 2 : nodeTestIds2.at(2),
734 2 : nodeTestIds2.at(3),
735 2 : nodeTestIds2.at(4),
736 1 : nodeTestIds2.at(8)};
737 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
738 : true,
739 : nodesCheck == buckIt.getNodeIds());
740 1 : }
741 :
742 1 : break;
743 :
744 1 : case 2: {
745 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(6), nodeTestIds2.at(7)};
746 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
747 : true,
748 : nodesCheck == buckIt.getNodeIds());
749 1 : } break;
750 :
751 1 : case 3:
752 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have node ntc2 9",
753 : true,
754 : buckIt.hasNode(nodeTestChannels2.at(9)->deviceId()));
755 1 : break;
756 : }
757 :
758 3 : sm3BucketCounter++;
759 : }
760 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("ERROR", 3, sm3BucketCounter - 1);
761 1 : }
762 :
763 : void
764 1 : RoutingTableTest::testSendKnownNodes_1b()
765 : {
766 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
767 :
768 4 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds2.at(0), rd, std::move([](auto) {return false;}));
769 1 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds3.at(0), rd, std::move([](auto) {return false;}));
770 :
771 1 : swarmManagers.insert({sm1->getId(), sm1});
772 1 : swarmManagers.insert({sm2->getId(), sm2});
773 :
774 1 : auto& rt1 = sm1->getRoutingTable();
775 1 : auto& rt2 = sm2->getRoutingTable();
776 :
777 1 : auto bucket1 = rt1.findBucket(nodeTestIds2.at(0));
778 1 : auto bucket2 = rt2.findBucket(nodeTestIds3.at(0));
779 :
780 11 : for (size_t i = 0; i < nodeTestChannels3.size(); i++) {
781 10 : auto node = nodeTestChannels3.at(i)->deviceId();
782 10 : if (node != sm1->getId() && node != sm2->getId()) {
783 8 : bucket2->addNode(nodeTestChannels3.at(i));
784 : }
785 : }
786 :
787 : std::vector<NodeId> node2Co = {
788 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")};
789 1 : needSocketCallBack(sm1);
790 :
791 1 : sm1->setKnownNodes(node2Co);
792 :
793 1 : auto start = std::chrono::steady_clock::now();
794 1 : bool cn1 {false}, cn2 {false};
795 :
796 2 : auto isGood = [&] {
797 2 : return (cn1 and cn2);
798 1 : };
799 : do {
800 1 : std::this_thread::sleep_for(1s);
801 1 : cn1 = bucket1->hasConnectingNode(nodeTestIds3.at(2));
802 1 : cn2 = bucket1->hasConnectingNode(nodeTestIds3.at(3));
803 :
804 1 : if (isGood())
805 1 : break;
806 0 : } while (std::chrono::steady_clock::now() - start < 10s);
807 :
808 1 : CPPUNIT_ASSERT(isGood());
809 1 : }
810 :
811 : void
812 1 : RoutingTableTest::testSendKnownNodes_multipleb()
813 : {
814 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
815 :
816 4 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds2.at(8), rd, std::move([](auto) {return false;}));
817 3 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds3.at(0), rd, std::move([](auto) {return false;}));
818 :
819 1 : swarmManagers.insert({sm1->getId(), sm1});
820 1 : swarmManagers.insert({sm2->getId(), sm2});
821 :
822 1 : auto& rt1 = sm1->getRoutingTable();
823 1 : auto& rt2 = sm2->getRoutingTable();
824 :
825 11 : for (size_t i = 0; i < nodeTestIds2.size(); i++) {
826 10 : if (i != 1 && i != 0) {
827 8 : auto bucket1 = rt1.findBucket(nodeTestIds2.at(i));
828 8 : rt1.addNode(nodeTestChannels2.at(i), bucket1);
829 : }
830 :
831 10 : auto bucket2 = rt2.findBucket(nodeTestIds3.at(i));
832 10 : rt2.addNode(nodeTestChannels3.at(i), bucket2);
833 : }
834 :
835 : std::vector<NodeId> node2Co = {
836 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")};
837 1 : needSocketCallBack(sm1);
838 :
839 1 : sm1->setKnownNodes(node2Co);
840 :
841 1 : auto bucket1 = rt1.findBucket(nodeTestIds3.at(1));
842 1 : auto bucket2 = rt1.findBucket(nodeTestIds3.at(3));
843 :
844 1 : auto start = std::chrono::steady_clock::now();
845 1 : bool cn1 {false}, cn2 {false};
846 2 : auto isGood = [&] {
847 2 : return (cn1 or cn2);
848 1 : };
849 : do {
850 1 : std::this_thread::sleep_for(1s);
851 1 : cn1 = bucket1->hasConnectingNode(nodeTestIds3.at(1));
852 1 : cn2 = bucket2->hasConnectingNode(nodeTestIds3.at(3));
853 :
854 1 : } while (not isGood() and std::chrono::steady_clock::now() - start < 10s);
855 :
856 1 : CPPUNIT_ASSERT(isGood());
857 1 : }
858 :
859 : void
860 1 : RoutingTableTest::testMobileNodeFunctions()
861 : {
862 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
863 :
864 1 : RoutingTable rt;
865 1 : NodeId node1 = nodeTestIds1.at(0);
866 1 : NodeId node2 = nodeTestIds1.at(1);
867 1 : NodeId node3 = nodeTestIds1.at(2);
868 :
869 1 : rt.setId(node1);
870 1 : rt.addMobileNode(node1);
871 1 : rt.addMobileNode(node2);
872 1 : rt.addMobileNode(node3);
873 :
874 1 : CPPUNIT_ASSERT(!rt.hasMobileNode(node1));
875 1 : CPPUNIT_ASSERT(rt.hasMobileNode(node2));
876 1 : CPPUNIT_ASSERT(rt.hasMobileNode(node3));
877 :
878 1 : auto mobileNodes = rt.getMobileNodes();
879 1 : CPPUNIT_ASSERT(mobileNodes.size() == 2);
880 :
881 1 : rt.removeMobileNode(node2);
882 1 : rt.removeMobileNode(node3);
883 :
884 1 : CPPUNIT_ASSERT(!rt.hasMobileNode(node2));
885 1 : CPPUNIT_ASSERT(!rt.hasMobileNode(node3));
886 1 : }
887 :
888 : void
889 1 : RoutingTableTest::testMobileNodeAnnouncement()
890 : {
891 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
892 :
893 2 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds1.at(0), rd, std::move([](auto) {return false;}));
894 1 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds2.at(1), rd, std::move([](auto) {return false;}));
895 :
896 1 : swarmManagers.insert({sm1->getId(), sm1});
897 1 : swarmManagers.insert({sm2->getId(), sm2});
898 1 : sm2->setMobility(true);
899 :
900 : std::vector<NodeId> node2Co = {
901 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")};
902 :
903 1 : needSocketCallBack(sm1);
904 :
905 1 : sm1->setKnownNodes(node2Co);
906 1 : sleep(1);
907 1 : auto& rt1 = sm1->getRoutingTable();
908 :
909 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE(
910 : "Supposed to have",
911 : true,
912 : rt1.hasNode(NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")));
913 :
914 1 : sm2->shutdown();
915 1 : sleep(5);
916 :
917 1 : auto mb1 = rt1.getMobileNodes();
918 :
919 : std::vector<NodeId> node2Test = {
920 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")};
921 :
922 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be identical", true, node2Test == mb1);
923 1 : }
924 :
925 : void
926 1 : RoutingTableTest::testMobileNodeSplit()
927 : {
928 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
929 :
930 1 : SwarmManager sm1(nodeTestIds1.at(0), rd, std::move([](auto) {return false;}));
931 :
932 1 : auto& rt1 = sm1.getRoutingTable();
933 :
934 11 : for (size_t i = 0; i < nodeTestIds1.size(); i++) {
935 10 : rt1.addNode(nodeTestChannels1.at(i));
936 : }
937 :
938 1 : sm1.setMobileNodes(nodeTestIds2);
939 :
940 1 : auto& buckets = rt1.getBuckets();
941 :
942 1 : unsigned counter = 1;
943 :
944 6 : for (auto& buckIt : buckets) {
945 5 : switch (counter) {
946 1 : case 1:
947 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have",
948 : false,
949 : buckIt.hasMobileNode(nodeTestIds2.at(0)));
950 1 : break;
951 :
952 1 : case 4: {
953 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(2),
954 2 : nodeTestIds2.at(3),
955 2 : nodeTestIds2.at(4),
956 1 : nodeTestIds2.at(8)};
957 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
958 : true,
959 : nodesCheck == buckIt.getMobileNodes());
960 1 : }
961 :
962 1 : break;
963 :
964 1 : case 5: {
965 1 : std::set<NodeId> nodesCheck {nodeTestIds2.at(5),
966 2 : nodeTestIds2.at(6),
967 2 : nodeTestIds2.at(7),
968 1 : nodeTestIds2.at(9)};
969 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Not supposed to have known nodes",
970 : true,
971 : nodesCheck == buckIt.getMobileNodes());
972 1 : }
973 :
974 1 : break;
975 : }
976 :
977 5 : counter++;
978 : }
979 1 : }
980 :
981 : void
982 1 : RoutingTableTest::testSendMobileNodes()
983 : {
984 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
985 :
986 4 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds2.at(8), rd, std::move([](auto) {return false;}));
987 3 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds3.at(0), rd, std::move([](auto) {return false;}));
988 :
989 1 : std::cout << sm1->getId() << std::endl;
990 :
991 1 : swarmManagers.insert({sm1->getId(), sm1});
992 1 : swarmManagers.insert({sm2->getId(), sm2});
993 :
994 1 : auto& rt1 = sm1->getRoutingTable();
995 1 : auto& rt2 = sm2->getRoutingTable();
996 :
997 11 : for (size_t i = 0; i < nodeTestIds2.size(); i++) {
998 10 : if (i != 1 && i != 0) {
999 8 : auto bucket1 = rt1.findBucket(nodeTestIds2.at(i));
1000 8 : rt1.addNode(nodeTestChannels2.at(i), bucket1);
1001 : }
1002 :
1003 10 : auto bucket2 = rt2.findBucket(nodeTestIds3.at(i));
1004 10 : rt2.addNode(nodeTestChannels3.at(i), bucket2);
1005 : }
1006 :
1007 : std::vector<NodeId> mobileNodes
1008 1 : = {NodeId("4000000000000000000000000000000000000000000000000000000000000000"),
1009 1 : NodeId("8000000000000000000000000000000000000000000000000000000000000000")};
1010 1 : sm2->setMobileNodes(mobileNodes);
1011 :
1012 : std::vector<NodeId> node2Co = {
1013 1 : NodeId("41a05179e4b3e42c3409b10280bb448d5bbd5ef64784b997d2d1663457bb6ba8")};
1014 1 : needSocketCallBack(sm1);
1015 :
1016 1 : sm1->setKnownNodes(node2Co);
1017 :
1018 1 : sleep(4);
1019 :
1020 1 : auto bucket1 = rt1.findBucket(sm1->getId());
1021 1 : auto bucket2 = rt2.findBucket(sm2->getId());
1022 :
1023 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have",
1024 : true,
1025 : bucket1->hasMobileNode(mobileNodes.at(0)));
1026 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have",
1027 : false,
1028 : bucket1->hasMobileNode(mobileNodes.at(1)));
1029 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have", false, rt1.hasMobileNode(mobileNodes.at(1)));
1030 :
1031 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have",
1032 : true,
1033 : bucket2->hasMobileNode(mobileNodes.at(0)));
1034 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to have", true, rt2.hasMobileNode(mobileNodes.at(1)));
1035 1 : }
1036 :
1037 : void
1038 8 : RoutingTableTest::crossNodes(NodeId nodeId)
1039 : {
1040 8 : std::list<NodeId> pendingNodes {nodeId};
1041 8 : discoveredNodes.clear();
1042 :
1043 540 : for (const auto& curNode : pendingNodes) {
1044 532 : if (std::find(discoveredNodes.begin(), discoveredNodes.end(), curNode)
1045 1064 : == discoveredNodes.end()) {
1046 82 : if (discoveredNodes.emplace_back(curNode)) {
1047 82 : if (auto sm = getManager(curNode))
1048 606 : for (auto const& node : sm->getRoutingTable().getNodes()) {
1049 524 : pendingNodes.emplace_back(node);
1050 164 : }
1051 : }
1052 : }
1053 : }
1054 8 : }
1055 :
1056 : void
1057 1 : RoutingTableTest::testSwarmManagersSmallBootstrapList()
1058 : {
1059 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
1060 :
1061 10 : for (const auto& sm : swarmManagers) {
1062 9 : needSocketCallBack(sm.second);
1063 : }
1064 :
1065 1 : Counter counter(swarmManagers.size());
1066 10 : for (const auto& sm : swarmManagers) {
1067 9 : dht::ThreadPool::computation().run([&] {
1068 9 : std::vector<NodeId> randIds(BOOTSTRAP_SIZE);
1069 9 : std::uniform_int_distribution<size_t> distribution(0, randomNodeIds.size() - 1);
1070 9 : std::generate(randIds.begin(), randIds.end(), [&] {
1071 17 : return randomNodeIds[distribution(rd)];
1072 : });
1073 9 : sm.second->setKnownNodes(randIds);
1074 9 : counter.count();
1075 9 : });
1076 : }
1077 :
1078 1 : counter.wait();
1079 :
1080 1 : sleep(time * 2);
1081 :
1082 1 : crossNodes(swarmManagers.begin()->first);
1083 : // distribution();
1084 :
1085 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1086 1 : }
1087 :
1088 : void
1089 1 : RoutingTableTest::testRoutingTableForConnectingNode()
1090 : {
1091 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
1092 :
1093 10 : for (const auto& sm : swarmManagers) {
1094 9 : needSocketCallBack(sm.second);
1095 : }
1096 :
1097 1 : Counter counter(swarmManagers.size());
1098 10 : for (const auto& sm : swarmManagers) {
1099 9 : dht::ThreadPool::computation().run([&] {
1100 9 : std::vector<NodeId> randIds(BOOTSTRAP_SIZE);
1101 9 : std::uniform_int_distribution<size_t> distribution(0, randomNodeIds.size() - 1);
1102 9 : std::generate(randIds.begin(), randIds.end(), [&] {
1103 18 : return randomNodeIds[distribution(rd)];
1104 : });
1105 9 : sm.second->setKnownNodes(randIds);
1106 9 : counter.count();
1107 9 : });
1108 : }
1109 1 : counter.wait();
1110 :
1111 9 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds3.at(0), rd, std::move([](auto) {return false;}));
1112 8 : auto sm2 = std::make_shared<SwarmManager>(nodeTestIds3.at(1), rd, std::move([](auto) {return false;}));
1113 :
1114 1 : swarmManagers.insert({sm1->getId(), sm1});
1115 1 : swarmManagers.insert({sm2->getId(), sm2});
1116 :
1117 1 : needSocketCallBack(sm1);
1118 1 : needSocketCallBack(sm2);
1119 :
1120 1 : std::vector<NodeId> knownNodesSm1({randomNodeIds.at(2), randomNodeIds.at(3)});
1121 1 : std::vector<NodeId> knownNodesSm2({randomNodeIds.at(4), randomNodeIds.at(5)});
1122 :
1123 1 : sm1->setKnownNodes(knownNodesSm1);
1124 1 : sm2->setKnownNodes(knownNodesSm2);
1125 :
1126 1 : sleep(10);
1127 :
1128 1 : crossNodes(swarmManagers.begin()->first);
1129 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1130 1 : }
1131 :
1132 : void
1133 1 : RoutingTableTest::testRoutingTableForShuttingNode()
1134 : {
1135 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
1136 :
1137 10 : for (const auto& sm : swarmManagers) {
1138 9 : needSocketCallBack(sm.second);
1139 : }
1140 :
1141 1 : Counter counter(swarmManagers.size());
1142 10 : for (const auto& sm : swarmManagers) {
1143 9 : dht::ThreadPool::computation().run([&] {
1144 9 : std::vector<NodeId> randIds(BOOTSTRAP_SIZE);
1145 9 : std::uniform_int_distribution<size_t> distribution(0, randomNodeIds.size() - 1);
1146 9 : std::generate(randIds.begin(), randIds.end(), [&] {
1147 16 : return randomNodeIds[distribution(rd)];
1148 : });
1149 8 : sm.second->setKnownNodes(randIds);
1150 9 : counter.count();
1151 9 : });
1152 : }
1153 :
1154 1 : counter.wait();
1155 :
1156 7 : auto sm1 = std::make_shared<SwarmManager>(nodeTestIds3.at(0), rd, std::move([](auto) {return false;}));
1157 1 : auto sm1Id = sm1->getId();
1158 :
1159 1 : swarmManagers.emplace(sm1->getId(), sm1);
1160 1 : needSocketCallBack(sm1);
1161 :
1162 1 : std::vector<NodeId> knownNodesSm1({randomNodeIds.at(2), randomNodeIds.at(3)});
1163 1 : sm1->setKnownNodes(knownNodesSm1);
1164 :
1165 1 : sleep(10);
1166 :
1167 1 : crossNodes(swarmManagers.begin()->first);
1168 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1169 :
1170 11 : for (const auto& sm : swarmManagers) {
1171 10 : if (sm.first != nodeTestIds3.at(0)) {
1172 9 : swarmManagersTest_.emplace(sm);
1173 : }
1174 : }
1175 :
1176 1 : auto it1 = swarmManagers.find(sm1Id);
1177 1 : swarmManagers.erase(it1);
1178 :
1179 1 : auto it2 = channelSockets_.find(sm1Id);
1180 1 : channelSockets_.erase(it2);
1181 :
1182 1 : sm1 = {};
1183 1 : sleep(5);
1184 10 : for (const auto& sm : swarmManagersTest_) {
1185 9 : auto& a = sm.second->getRoutingTable();
1186 9 : CPPUNIT_ASSERT(!a.hasNode(sm1Id));
1187 : }
1188 1 : }
1189 :
1190 : void
1191 1 : RoutingTableTest::testRoutingTableForMassShuttingsNodes()
1192 : {
1193 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
1194 :
1195 1 : std::vector<NodeId> swarmToCompare;
1196 :
1197 10 : for (const auto& sm : swarmManagers) {
1198 9 : needSocketCallBack(sm.second);
1199 9 : swarmManagersTest_.emplace(sm);
1200 9 : swarmToCompare.emplace_back(sm.first);
1201 : }
1202 :
1203 1 : Counter counter(swarmManagers.size());
1204 10 : for (const auto& sm : swarmManagers) {
1205 9 : dht::ThreadPool::computation().run([&] {
1206 9 : std::vector<NodeId> randIds(BOOTSTRAP_SIZE);
1207 9 : std::uniform_int_distribution<size_t> distribution(0, randomNodeIds.size() - 1);
1208 9 : std::generate(randIds.begin(), randIds.end(), [&] {
1209 18 : return randomNodeIds[distribution(rd)];
1210 : });
1211 9 : sm.second->setKnownNodes(randIds);
1212 :
1213 9 : counter.count();
1214 9 : });
1215 : }
1216 1 : counter.wait();
1217 :
1218 1 : sleep(time * 2);
1219 :
1220 1 : crossNodes(swarmManagers.begin()->first);
1221 :
1222 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1223 :
1224 : // ADDING NEW NODES TO NETWORK
1225 11 : for (size_t i = 0; i < nodeTestIds1.size(); i++) {
1226 82 : auto sm = std::make_shared<SwarmManager>(nodeTestIds1.at(i), rd, std::move([](auto) {return false;}));
1227 10 : auto smId = sm->getId();
1228 10 : swarmManagers.emplace(smId, sm);
1229 10 : needSocketCallBack(sm);
1230 10 : std::vector<NodeId> knownNodesSm({randomNodeIds.at(2), randomNodeIds.at(3)});
1231 10 : sm->setKnownNodes(knownNodesSm);
1232 10 : }
1233 :
1234 1 : sleep(time * 3);
1235 1 : crossNodes(swarmManagers.begin()->first);
1236 :
1237 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1238 :
1239 : // SHUTTING DOWN ADDED NODES
1240 1 : std::lock_guard lk(channelSocketsMtx_);
1241 11 : for (auto& nodes : nodeTestIds1) {
1242 10 : auto it = swarmManagers.find(nodes);
1243 10 : if (it != swarmManagers.end()) {
1244 10 : it->second->shutdown();
1245 10 : channelSockets_.erase(it->second->getId());
1246 10 : swarmManagers.erase(it);
1247 : }
1248 : }
1249 :
1250 1 : sleep(time * 2);
1251 :
1252 1 : crossNodes(swarmManagers.begin()->first);
1253 :
1254 1 : CPPUNIT_ASSERT_EQUAL(swarmManagers.size(), discoveredNodes.size());
1255 :
1256 10 : for (const auto& sm : swarmManagersTest_) {
1257 99 : for (size_t i = 0; i < nodeTestIds1.size(); i++) {
1258 90 : auto& a = sm.second->getRoutingTable();
1259 90 : if (!a.hasNode(nodeTestIds1.at(i))) {
1260 90 : CPPUNIT_ASSERT(true);
1261 : } else {
1262 0 : CPPUNIT_ASSERT(false);
1263 : }
1264 : }
1265 : }
1266 1 : }
1267 :
1268 : void
1269 1 : RoutingTableTest::testSwarmManagersWMobileModes()
1270 : {
1271 1 : std::cout << "\nRunning test: " << __func__ << std::endl;
1272 :
1273 10 : for (const auto& sm : swarmManagers) {
1274 9 : needSocketCallBack(sm.second);
1275 : }
1276 :
1277 1 : Counter counter(swarmManagers.size());
1278 10 : for (const auto& sm : swarmManagers) {
1279 9 : dht::ThreadPool::computation().run([&] {
1280 8 : std::vector<NodeId> randIds(BOOTSTRAP_SIZE);
1281 9 : std::uniform_int_distribution<size_t> distribution(0, randomNodeIds.size() - 1);
1282 9 : std::generate(randIds.begin(), randIds.end(), [&] {
1283 18 : return randomNodeIds[distribution(rd)];
1284 : });
1285 9 : sm.second->setKnownNodes(randIds);
1286 9 : counter.count();
1287 9 : });
1288 : }
1289 :
1290 1 : counter.wait();
1291 :
1292 1 : sleep(time);
1293 :
1294 : // distribution();
1295 :
1296 1 : crossNodes(swarmManagers.begin()->first);
1297 1 : sleep(2);
1298 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be equal with mobile nodes",
1299 : swarmManagers.size(),
1300 : discoveredNodes.size());
1301 :
1302 : // Shutting down Mobile Nodes
1303 : {
1304 1 : std::lock_guard lk(channelSocketsMtx_);
1305 10 : for (auto it = swarmManagers.begin(); it != swarmManagers.end();) {
1306 9 : if (it->second->isMobile()) {
1307 3 : it->second->shutdown();
1308 3 : channelSockets_.erase(it->second->getId());
1309 3 : it = swarmManagers.erase(it);
1310 :
1311 : } else {
1312 6 : ++it;
1313 : }
1314 : }
1315 1 : }
1316 :
1317 1 : sleep(20);
1318 :
1319 : {
1320 1 : if (!swarmManagers.empty()) {
1321 1 : crossNodes(swarmManagers.begin()->first);
1322 : // distribution();
1323 : }
1324 : }
1325 :
1326 1 : sleep(10);
1327 :
1328 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Supposed to be equal without mobile nodes",
1329 : swarmManagers.size(),
1330 : discoveredNodes.size());
1331 1 : }
1332 :
1333 : }; // namespace test
1334 : } // namespace jami
1335 1 : RING_TEST_RUNNER(jami::test::RoutingTableTest::name())
|