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