/******************************************************************************* * * Copyright (c) 2004-2009, Oracle Corporation * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * * * *******************************************************************************/ package hudson.util; import junit.framework.TestCase; import java.util.Random; import java.util.Map; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.HashSet; import java.util.Map.Entry; /** * @author Kohsuke Kawaguchi */ public class ConsistentHashTest extends TestCase { /** * Just some random tests to ensure that we have no silly NPE or that kind of error. */ public void testBasic() { ConsistentHash<String> hash = new ConsistentHash<String>(); hash.add("data1"); hash.add("data2"); hash.add("data3"); System.out.println(hash.lookup(0)); // there's one in 2^32 chance that this test fails, but these two query points are // only off by one. String x = hash.lookup(Integer.MIN_VALUE); String y = hash.lookup(Integer.MAX_VALUE); assertEquals(x,y); // list them up Iterator<String> itr = hash.list(Integer.MIN_VALUE).iterator(); Set<String> all = new HashSet<String>(); String z = itr.next(); all.add(z); assertEquals(z,x); all.add(itr.next()); all.add(itr.next()); assertTrue(!itr.hasNext()); assertEquals(3,all.size()); } /** * Uneven distribution should result in uneven mapping. */ public void testUnevenDisribution() { ConsistentHash<String> hash = new ConsistentHash<String>(); hash.add("even",10); hash.add("odd",100); Random r = new Random(0); int even=0,odd=0; for(int i=0; i<1000; i++) { String v = hash.lookup(r.nextInt()); if(v.equals("even")) even++; else odd++; } // again, there's a small chance tha this test fails. System.out.printf("%d/%d\n",even,odd); assertTrue(even*8<odd); } /** * Removal shouldn't affect existing nodes */ public void testRemoval() { ConsistentHash<Integer> hash = new ConsistentHash<Integer>(); for( int i=0; i<10; i++ ) hash.add(i); // what was the mapping before the mutation? Map<Integer,Integer> before = new HashMap<Integer, Integer>(); Random r = new Random(0); for(int i=0; i<1000; i++) { int q = r.nextInt(); before.put(q,hash.lookup(q)); } // remove a node hash.remove(0); // verify that the mapping remains consistent for (Entry<Integer,Integer> e : before.entrySet()) { int m = hash.lookup(e.getKey()); assertTrue(e.getValue()==0 || e.getValue()==m); } } public void testEmptyBehavior() { ConsistentHash<String> hash = new ConsistentHash<String>(); assertFalse(hash.list(0).iterator().hasNext()); assertNull(hash.lookup(0)); assertNull(hash.lookup(999)); } }