I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 8699c826 authored by zzz's avatar zzz
Browse files

Kad unit tests:

  - Port KBSTest from i2p.zzz.kademlia branch
  - Fix RandomTrimmer so it always returns true, so it may be used
    as the trimmer in the unit tests
parent 1d7eedd4
No related branches found
No related tags found
No related merge requests found
...@@ -26,6 +26,7 @@ public class RandomTrimmer<T extends SimpleDataStructure> implements KBucketTrim ...@@ -26,6 +26,7 @@ public class RandomTrimmer<T extends SimpleDataStructure> implements KBucketTrim
if (sz < _max) if (sz < _max)
return true; return true;
T toRemove = e.get(_ctx.random().nextInt(sz)); T toRemove = e.get(_ctx.random().nextInt(sz));
return kbucket.remove(toRemove); kbucket.remove(toRemove);
return true;
} }
} }
...@@ -8,37 +8,154 @@ package net.i2p.kademlia; ...@@ -8,37 +8,154 @@ package net.i2p.kademlia;
* *
*/ */
import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.util.Log;
/** /**
* Test KBucketSet * Test KBucketSet.
* Newer tests ported from KBSTest in i2p.zzz.kademlia branch
* *
* @author comwiz * @author comwiz
* @since 0.9.10 moved from net.i2p.router.networkdb.kademlia
*/ */
public class KBucketSetTest extends TestCase{ public class KBucketSetTest extends TestCase{
private I2PAppContext context; private I2PAppContext context;
private KBucketSet<Hash> set; private KBucketSet<Hash> set;
private Hash usHash;
private Log log;
private static final int K = 8; private static final int K = 8;
private static final int B = 1; private static final int B = 1;
public void setUp(){ public void setUp(){
context = I2PAppContext.getGlobalContext(); context = I2PAppContext.getGlobalContext();
set = new KBucketSet<Hash>(context, Hash.FAKE_HASH, K, B); log = context.logManager().getLog(KBucketSet.class);
byte[] us = new byte[Hash.HASH_LENGTH];
context.random().nextBytes(us);
usHash = new Hash(us);
// We use the default RandomTrimmer so add() will never fail
set = new KBucketSet<Hash>(context, usHash, K, B);
// tests may be run in any order so prime it
addRandom(1000);
} }
public void testRandom(){ public void testRandom(){
for (int i = 0; i < 1000; i++) { addRandom(1000);
byte val[] = new byte[Hash.HASH_LENGTH]; }
context.random().nextBytes(val);
assertTrue(set.add(new Hash(val))); private void addRandom(int count) {
} for (int i = 0; i < count; i++) {
} byte val[] = new byte[Hash.HASH_LENGTH];
context.random().nextBytes(val);
Hash h = new Hash(val);
// in the highly unlikely chance we randomly generate a hash equal to us
assertTrue(set.add(h) || h.equals(usHash));
}
}
public void testSelf() { public void testSelf() {
// new implementation will never include myself // new implementation will never include myself
assertFalse(set.add(Hash.FAKE_HASH)); assertFalse(set.add(usHash));
}
/** @since 0.9.10 */
public void testConcurrent() {
int count = 2500;
int n = 4;
Thread[] threads = new Thread[n];
for (int i = 0; i < n; i++) {
threads[i] = new RTester(count);
}
for (int i = 0; i < n; i++) {
threads[i].start();
}
for (int i = 0; i < n; i++) {
try {
threads[i].join();
} catch (InterruptedException ie) {}
}
}
/** @since 0.9.10 */
private class RTester extends Thread {
private final int _count;
public RTester(int count) {
_count = count;
}
public void run() {
addRandom(_count);
}
}
/** @since 0.9.10 */
public void testAudit() {
int errors = 0;
for (KBucket<Hash> b : set.getBuckets()) {
for (Hash sds : b.getEntries()) {
int range = set.getRange(sds);
if (range < b.getRangeBegin() || range > b.getRangeEnd()) {
log.error("Hash " + sds + " with range " + range +
" does not belong in " + b);
errors++;
}
}
}
assertTrue(errors == 0);
}
/** @since 0.9.10 */
public void testOrder() {
int bits = Hash.HASH_LENGTH * 8;
int errors = 0;
int lastEnd = -1;
for (KBucket<Hash> b : set.getBuckets()) {
int beg = b.getRangeBegin();
if (beg != lastEnd + 1) {
log.error("Out of order: " + b);
errors++;
}
lastEnd = b.getRangeEnd();
}
if (lastEnd != (bits * (1 << (B-1))) - 1) {
log.error("Out of order: last=" + lastEnd);
errors++;
}
assertTrue(errors == 0);
}
/** @since 0.9.10 */
public void testGenRandom() {
int errors = 0;
for (KBucket b : set.getBuckets()) {
for (int j = 0; j < 4000; j++) {
Hash rand = set.generateRandomKey(b);
int range = set.getRange(rand);
if (range < b.getRangeBegin() || range > b.getRangeEnd()) {
log.error("Generate random key failed range=" + range + " for " + rand + " meant for bucket " + b);
errors++;
}
}
}
assertTrue(errors == 0);
}
/** @since 0.9.10 */
public void testExplore() {
List<Hash> keys = set.getExploreKeys(-1000);
assertTrue(keys.size() > 0);
}
/** @since 0.9.10 */
public void testClosest() {
byte val[] = new byte[Hash.HASH_LENGTH];
for (int i = 0; i < 23; i++) {
context.random().nextBytes(val);
Hash h = new Hash(val);
List<Hash> c = set.getClosest(h, i);
assertTrue(c.size() == i);
}
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment