DHTBucketTest.cc 11 KB

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