DHTBucketTest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "DHTBucket.h"
  2. #include "DHTNode.h"
  3. #include "Exception.h"
  4. #include "Util.h"
  5. #include <cppunit/extensions/HelperMacros.h>
  6. namespace aria2 {
  7. class DHTBucketTest:public CppUnit::TestFixture {
  8. CPPUNIT_TEST_SUITE(DHTBucketTest);
  9. CPPUNIT_TEST(testGetRandomNodeID);
  10. CPPUNIT_TEST(testIsInRange);
  11. CPPUNIT_TEST(testSplitAllowed);
  12. CPPUNIT_TEST(testSplit);
  13. CPPUNIT_TEST(testAddNode);
  14. CPPUNIT_TEST(testMoveToHead);
  15. CPPUNIT_TEST(testMoveToTail);
  16. CPPUNIT_TEST(testGetGoodNodes);
  17. CPPUNIT_TEST_SUITE_END();
  18. public:
  19. void setUp() {}
  20. void tearDown() {}
  21. void testGetRandomNodeID();
  22. void testIsInRange();
  23. void testSplitAllowed();
  24. void testSplit();
  25. void testAddNode();
  26. void testMoveToHead();
  27. void testMoveToTail();
  28. void testGetGoodNodes();
  29. };
  30. CPPUNIT_TEST_SUITE_REGISTRATION(DHTBucketTest);
  31. void DHTBucketTest::testGetRandomNodeID()
  32. {
  33. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  34. 0x00, 0x00, 0x00, 0x00, 0x00,
  35. 0x00, 0x00, 0x00, 0x00, 0x00,
  36. 0x00, 0x00, 0x00, 0x00, 0x00 };
  37. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  38. {
  39. DHTBucket bucket(localNode);
  40. unsigned char nodeID[DHT_ID_LENGTH];
  41. bucket.getRandomNodeID(nodeID);
  42. }
  43. {
  44. unsigned char max[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  45. 0xff, 0xff, 0xff, 0xff, 0xff,
  46. 0xff, 0xff, 0xff, 0xff, 0xff,
  47. 0xff, 0xff, 0xff, 0xff, 0xff };
  48. unsigned char min[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  49. 0x00, 0x00, 0x00, 0x00, 0x00,
  50. 0x00, 0x00, 0x00, 0x00, 0x00,
  51. 0x00, 0x00, 0x00, 0x00, 0x00 };
  52. DHTBucket bucket(16, max, min, localNode);
  53. unsigned char nodeID[DHT_ID_LENGTH];
  54. bucket.getRandomNodeID(nodeID);
  55. CPPUNIT_ASSERT_EQUAL(std::string("0101"),
  56. Util::toHex(nodeID, sizeof(nodeID)).substr(0, 4));
  57. }
  58. }
  59. void DHTBucketTest::testIsInRange()
  60. {
  61. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  62. 0x00, 0x00, 0x00, 0x00, 0x00,
  63. 0x00, 0x00, 0x00, 0x00, 0x00,
  64. 0x00, 0x00, 0x00, 0x00, 0x00 };
  65. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  66. {
  67. unsigned char nodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  68. 0x00, 0x00, 0x00, 0x00, 0x00,
  69. 0x00, 0x00, 0x00, 0x00, 0x00,
  70. 0x00, 0x00, 0x00, 0x00, 0x00 };
  71. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  72. DHTBucket bucket(localNode);
  73. CPPUNIT_ASSERT(bucket.isInRange(node));
  74. memset(nodeID, 0xff, sizeof(nodeID));
  75. CPPUNIT_ASSERT(bucket.isInRange(node));
  76. }
  77. {
  78. unsigned char max[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  79. 0xff, 0xff, 0xff, 0xff, 0xff,
  80. 0xff, 0xff, 0xff, 0xff, 0xff,
  81. 0xff, 0xff, 0xff, 0xff, 0xff };
  82. unsigned char min[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  83. 0x00, 0x00, 0x00, 0x00, 0x00,
  84. 0x00, 0x00, 0x00, 0x00, 0x00,
  85. 0x00, 0x00, 0x00, 0x00, 0x00 };
  86. {
  87. //min
  88. unsigned char nodeID[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  89. 0x00, 0x00, 0x00, 0x00, 0x00,
  90. 0x00, 0x00, 0x00, 0x00, 0x00,
  91. 0x00, 0x00, 0x00, 0x00, 0x00 };
  92. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  93. DHTBucket bucket(16, max, min, localNode);
  94. CPPUNIT_ASSERT(bucket.isInRange(node));
  95. }
  96. {
  97. //max
  98. unsigned char nodeID[] = { 0x01, 0x01, 0xff, 0xff, 0xff,
  99. 0xff, 0xff, 0xff, 0xff, 0xff,
  100. 0xff, 0xff, 0xff, 0xff, 0xff,
  101. 0xff, 0xff, 0xff, 0xff, 0xff };
  102. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  103. DHTBucket bucket(16, max, min, localNode);
  104. CPPUNIT_ASSERT(bucket.isInRange(node));
  105. }
  106. {
  107. unsigned char nodeID[] = { 0x01, 0x01, 0x00, 0x00, 0x00,
  108. 0x00, 0x00, 0x00, 0x00, 0x00,
  109. 0xff, 0xff, 0xff, 0xff, 0xff,
  110. 0xff, 0xff, 0xff, 0xff, 0xff };
  111. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  112. DHTBucket bucket(16, max, min, localNode);
  113. CPPUNIT_ASSERT(bucket.isInRange(node));
  114. }
  115. {
  116. // nodeID is out of range: smaller than this range
  117. unsigned char nodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  118. 0x00, 0x00, 0x00, 0x00, 0x00,
  119. 0x00, 0x00, 0x00, 0x00, 0x00,
  120. 0x00, 0x00, 0x00, 0x00, 0x00 };
  121. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  122. DHTBucket bucket(16, max, min, localNode);
  123. CPPUNIT_ASSERT(!bucket.isInRange(node));
  124. }
  125. {
  126. // nodeID is out of range: larger than this range
  127. unsigned char nodeID[] = { 0x10, 0x00, 0x00, 0x00, 0x00,
  128. 0x00, 0x00, 0x00, 0x00, 0x00,
  129. 0x00, 0x00, 0x00, 0x00, 0x00,
  130. 0x00, 0x00, 0x00, 0x00, 0x00 };
  131. SharedHandle<DHTNode> node = new DHTNode(nodeID);
  132. DHTBucket bucket(16, max, min, localNode);
  133. CPPUNIT_ASSERT(!bucket.isInRange(node));
  134. }
  135. }
  136. }
  137. void DHTBucketTest::testSplitAllowed()
  138. {
  139. {
  140. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  141. 0x00, 0x00, 0x00, 0x00, 0x00,
  142. 0x00, 0x00, 0x00, 0x00, 0x00,
  143. 0x00, 0x00, 0x00, 0x00, 0x00 };
  144. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  145. DHTBucket bucket(localNode);
  146. CPPUNIT_ASSERT(bucket.splitAllowed());
  147. }
  148. {
  149. unsigned char max[] = { 0xff, 0xff, 0xff, 0xff, 0xff,
  150. 0xff, 0xff, 0xff, 0xff, 0xff,
  151. 0xff, 0xff, 0xff, 0xff, 0xff,
  152. 0xff, 0xff, 0xff, 0xff, 0xff };
  153. unsigned char min[] = { 0xe0, 0x00, 0x00, 0x00, 0x00,
  154. 0x00, 0x00, 0x00, 0x00, 0x00,
  155. 0x00, 0x00, 0x00, 0x00, 0x00,
  156. 0x00, 0x00, 0x00, 0x00, 0x00 };
  157. {
  158. unsigned char localNodeID[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  159. 0x00, 0x00, 0x00, 0x00, 0x00,
  160. 0x00, 0x00, 0x00, 0x00, 0x00,
  161. 0x00, 0x00, 0x00, 0x00, 0x00 };
  162. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  163. DHTBucket bucket(3, max, min, localNode);
  164. CPPUNIT_ASSERT(!bucket.splitAllowed());
  165. }
  166. {
  167. unsigned char localNodeID[] = { 0xe0, 0x00, 0x00, 0x00, 0x00,
  168. 0x00, 0x00, 0x00, 0x00, 0x00,
  169. 0x00, 0x00, 0x00, 0x00, 0x00,
  170. 0x00, 0x00, 0x00, 0x00, 0x01 };
  171. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  172. DHTBucket bucket(3, max, min, localNode);
  173. CPPUNIT_ASSERT(bucket.splitAllowed());
  174. }
  175. }
  176. }
  177. void DHTBucketTest::testSplit()
  178. {
  179. unsigned char localNodeID[DHT_ID_LENGTH];
  180. memset(localNodeID, 0, DHT_ID_LENGTH);
  181. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  182. {
  183. DHTBucket bucket(localNode);
  184. SharedHandle<DHTBucket> r = bucket.split();
  185. {
  186. unsigned char expectedRMax[] = { 0x7f, 0xff, 0xff, 0xff, 0xff,
  187. 0xff, 0xff, 0xff, 0xff, 0xff,
  188. 0xff, 0xff, 0xff, 0xff, 0xff,
  189. 0xff, 0xff, 0xff, 0xff, 0xff };
  190. unsigned char expectedRMin[DHT_ID_LENGTH];
  191. memset(expectedRMin, 0, DHT_ID_LENGTH);
  192. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedRMax, DHT_ID_LENGTH),
  193. Util::toHex(r->getMaxID(), DHT_ID_LENGTH));
  194. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedRMin, DHT_ID_LENGTH),
  195. Util::toHex(r->getMinID(), DHT_ID_LENGTH));
  196. CPPUNIT_ASSERT_EQUAL((size_t)1, r->getPrefixLength());
  197. }
  198. {
  199. unsigned char expectedLMax[DHT_ID_LENGTH];
  200. memset(expectedLMax, 0xff, DHT_ID_LENGTH);
  201. unsigned char expectedLMin[] = { 0x80, 0x00, 0x00, 0x00, 0x00,
  202. 0x00, 0x00, 0x00, 0x00, 0x00,
  203. 0x00, 0x00, 0x00, 0x00, 0x00,
  204. 0x00, 0x00, 0x00, 0x00, 0x00 };
  205. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedLMax, DHT_ID_LENGTH),
  206. Util::toHex(bucket.getMaxID(), DHT_ID_LENGTH));
  207. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedLMin, DHT_ID_LENGTH),
  208. Util::toHex(bucket.getMinID(), DHT_ID_LENGTH));
  209. CPPUNIT_ASSERT_EQUAL((size_t)1, bucket.getPrefixLength());
  210. }
  211. }
  212. {
  213. SharedHandle<DHTBucket> bucket = new DHTBucket(localNode);
  214. for(int i = 0; i < 159; ++i) {
  215. CPPUNIT_ASSERT(bucket->splitAllowed());
  216. SharedHandle<DHTBucket> t = bucket;
  217. bucket = bucket->split();
  218. CPPUNIT_ASSERT(!t->splitAllowed());
  219. }
  220. CPPUNIT_ASSERT(!bucket->splitAllowed());
  221. unsigned char expectedMax[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  222. 0x00, 0x00, 0x00, 0x00, 0x00,
  223. 0x00, 0x00, 0x00, 0x00, 0x00,
  224. 0x00, 0x00, 0x00, 0x00, 0x01 };
  225. unsigned char expectedMin[DHT_ID_LENGTH];
  226. memset(expectedMin, 0, DHT_ID_LENGTH);
  227. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedMax, DHT_ID_LENGTH),
  228. Util::toHex(bucket->getMaxID(), DHT_ID_LENGTH));
  229. CPPUNIT_ASSERT_EQUAL(Util::toHex(expectedMin, DHT_ID_LENGTH),
  230. Util::toHex(bucket->getMinID(), DHT_ID_LENGTH));
  231. CPPUNIT_ASSERT_EQUAL((size_t)159, bucket->getPrefixLength());
  232. }
  233. }
  234. static void createID(unsigned char* id, unsigned char firstChar, unsigned char lastChar)
  235. {
  236. memset(id, 0, DHT_ID_LENGTH);
  237. id[0] = firstChar;
  238. id[DHT_ID_LENGTH-1] = lastChar;
  239. }
  240. void DHTBucketTest::testAddNode()
  241. {
  242. unsigned char localNodeID[DHT_ID_LENGTH];
  243. memset(localNodeID, 0, DHT_ID_LENGTH);
  244. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  245. DHTBucket bucket(localNode);
  246. unsigned char id[DHT_ID_LENGTH];
  247. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  248. for(size_t i = 0; i < DHTBucket::K; ++i) {
  249. createID(id, 0xf0, i);
  250. nodes[i] = new DHTNode(id);
  251. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  252. }
  253. createID(id, 0xf0, 0xff);
  254. SharedHandle<DHTNode> newNode = new DHTNode(id);
  255. CPPUNIT_ASSERT(!bucket.addNode(newNode));
  256. // nodes[0] is located at the tail of the bucket(least recent seen)
  257. nodes[0]->markBad();
  258. CPPUNIT_ASSERT(bucket.addNode(newNode));
  259. CPPUNIT_ASSERT(bucket.getNodes().back() == newNode);
  260. }
  261. void DHTBucketTest::testMoveToHead()
  262. {
  263. unsigned char localNodeID[DHT_ID_LENGTH];
  264. memset(localNodeID, 0, DHT_ID_LENGTH);
  265. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  266. DHTBucket bucket(localNode);
  267. unsigned char id[DHT_ID_LENGTH];
  268. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  269. for(size_t i = 0; i < DHTBucket::K; ++i) {
  270. createID(id, 0xf0, i);
  271. nodes[i] = new DHTNode(id);
  272. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  273. }
  274. bucket.moveToHead(nodes[DHTBucket::K-1]);
  275. CPPUNIT_ASSERT(bucket.getNodes().front() == nodes[DHTBucket::K-1]);
  276. }
  277. void DHTBucketTest::testMoveToTail()
  278. {
  279. unsigned char localNodeID[DHT_ID_LENGTH];
  280. memset(localNodeID, 0, DHT_ID_LENGTH);
  281. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  282. DHTBucket bucket(localNode);
  283. unsigned char id[DHT_ID_LENGTH];
  284. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  285. for(size_t i = 0; i < DHTBucket::K; ++i) {
  286. createID(id, 0xf0, i);
  287. nodes[i] = new DHTNode(id);
  288. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  289. }
  290. bucket.moveToTail(nodes[0]);
  291. CPPUNIT_ASSERT(bucket.getNodes().back() == nodes[0]);
  292. }
  293. void DHTBucketTest::testGetGoodNodes()
  294. {
  295. unsigned char localNodeID[DHT_ID_LENGTH];
  296. memset(localNodeID, 0, DHT_ID_LENGTH);
  297. SharedHandle<DHTNode> localNode = new DHTNode(localNodeID);
  298. DHTBucket bucket(localNode);
  299. unsigned char id[DHT_ID_LENGTH];
  300. SharedHandle<DHTNode> nodes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  301. for(size_t i = 0; i < DHTBucket::K; ++i) {
  302. createID(id, 0xf0, i);
  303. nodes[i] = new DHTNode(id);
  304. nodes[i]->setPort(6881+i);
  305. CPPUNIT_ASSERT(bucket.addNode(nodes[i]));
  306. }
  307. nodes[3]->markBad();
  308. nodes[5]->markBad();
  309. std::deque<SharedHandle<DHTNode> > goodNodes = bucket.getGoodNodes();
  310. CPPUNIT_ASSERT_EQUAL((size_t)6, goodNodes.size());
  311. CPPUNIT_ASSERT_EQUAL((uint16_t)6881, goodNodes[0]->getPort());
  312. CPPUNIT_ASSERT_EQUAL((uint16_t)6882, goodNodes[1]->getPort());
  313. CPPUNIT_ASSERT_EQUAL((uint16_t)6883, goodNodes[2]->getPort());
  314. CPPUNIT_ASSERT_EQUAL((uint16_t)6885, goodNodes[3]->getPort());
  315. CPPUNIT_ASSERT_EQUAL((uint16_t)6887, goodNodes[4]->getPort());
  316. CPPUNIT_ASSERT_EQUAL((uint16_t)6888, goodNodes[5]->getPort());
  317. }
  318. } // namespace aria2