204 lines
5.1 KiB
Python
204 lines
5.1 KiB
Python
from pymemcache.client.rendezvous import RendezvousHash
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_init_no_options():
|
|
rendezvous = RendezvousHash()
|
|
assert 0 == len(rendezvous.nodes)
|
|
assert 1361238019 == rendezvous.hash_function("6666")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_init():
|
|
nodes = ["0", "1", "2"]
|
|
rendezvous = RendezvousHash(nodes=nodes)
|
|
assert 3 == len(rendezvous.nodes)
|
|
assert 1361238019 == rendezvous.hash_function("6666")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_seed():
|
|
rendezvous = RendezvousHash(seed=10)
|
|
assert 2981722772 == rendezvous.hash_function("6666")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_add_node():
|
|
rendezvous = RendezvousHash()
|
|
rendezvous.add_node("1")
|
|
|
|
assert 1 == len(rendezvous.nodes)
|
|
rendezvous.add_node("1")
|
|
|
|
assert 1 == len(rendezvous.nodes)
|
|
rendezvous.add_node("2")
|
|
|
|
assert 2 == len(rendezvous.nodes)
|
|
rendezvous.add_node("1")
|
|
|
|
assert 2 == len(rendezvous.nodes)
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_remove_node():
|
|
nodes = ["0", "1", "2"]
|
|
rendezvous = RendezvousHash(nodes=nodes)
|
|
rendezvous.remove_node("2")
|
|
|
|
assert 2 == len(rendezvous.nodes)
|
|
|
|
with pytest.raises(ValueError):
|
|
rendezvous.remove_node("2")
|
|
|
|
assert 2 == len(rendezvous.nodes)
|
|
|
|
rendezvous.remove_node("1")
|
|
assert 1 == len(rendezvous.nodes)
|
|
|
|
rendezvous.remove_node("0")
|
|
assert 0 == len(rendezvous.nodes)
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_get_node():
|
|
nodes = ["0", "1", "2"]
|
|
rendezvous = RendezvousHash(nodes=nodes)
|
|
assert "0" == rendezvous.get_node("ok")
|
|
assert "1" == rendezvous.get_node("mykey")
|
|
assert "2" == rendezvous.get_node("wat")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_get_node_after_removal():
|
|
nodes = ["0", "1", "2"]
|
|
rendezvous = RendezvousHash(nodes=nodes)
|
|
rendezvous.remove_node("1")
|
|
|
|
assert "0" == rendezvous.get_node("ok")
|
|
assert "0" == rendezvous.get_node("mykey")
|
|
assert "2" == rendezvous.get_node("wat")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_get_node_after_addition():
|
|
nodes = ["0", "1", "2"]
|
|
rendezvous = RendezvousHash(nodes=nodes)
|
|
assert "0" == rendezvous.get_node("ok")
|
|
assert "1" == rendezvous.get_node("mykey")
|
|
assert "2" == rendezvous.get_node("wat")
|
|
assert "2" == rendezvous.get_node("lol")
|
|
rendezvous.add_node("3")
|
|
|
|
assert "0" == rendezvous.get_node("ok")
|
|
assert "1" == rendezvous.get_node("mykey")
|
|
assert "2" == rendezvous.get_node("wat")
|
|
assert "3" == rendezvous.get_node("lol")
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_grow():
|
|
rendezvous = RendezvousHash()
|
|
|
|
placements = {}
|
|
|
|
for i in range(10):
|
|
rendezvous.add_node(str(i))
|
|
placements[str(i)] = []
|
|
|
|
for i in range(1000):
|
|
node = rendezvous.get_node(str(i))
|
|
placements[node].append(i)
|
|
|
|
new_placements = {}
|
|
|
|
for i in range(20):
|
|
rendezvous.add_node(str(i))
|
|
new_placements[str(i)] = []
|
|
|
|
for i in range(1000):
|
|
node = rendezvous.get_node(str(i))
|
|
new_placements[node].append(i)
|
|
|
|
keys = [k for sublist in placements.values() for k in sublist]
|
|
new_keys = [k for sublist in new_placements.values() for k in sublist]
|
|
assert sorted(keys) == sorted(new_keys)
|
|
|
|
added = 0
|
|
removed = 0
|
|
|
|
for node, assignments in new_placements.items():
|
|
after = set(assignments)
|
|
before = set(placements.get(node, []))
|
|
removed += len(before.difference(after))
|
|
added += len(after.difference(before))
|
|
|
|
assert added == removed
|
|
assert 1062 == (added + removed)
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_shrink():
|
|
rendezvous = RendezvousHash()
|
|
|
|
placements = {}
|
|
for i in range(10):
|
|
rendezvous.add_node(str(i))
|
|
placements[str(i)] = []
|
|
|
|
for i in range(1000):
|
|
node = rendezvous.get_node(str(i))
|
|
placements[node].append(i)
|
|
|
|
rendezvous.remove_node("9")
|
|
new_placements = {}
|
|
for i in range(9):
|
|
new_placements[str(i)] = []
|
|
|
|
for i in range(1000):
|
|
node = rendezvous.get_node(str(i))
|
|
new_placements[node].append(i)
|
|
|
|
keys = [k for sublist in placements.values() for k in sublist]
|
|
new_keys = [k for sublist in new_placements.values() for k in sublist]
|
|
assert sorted(keys) == sorted(new_keys)
|
|
|
|
added = 0
|
|
removed = 0
|
|
for node, assignments in placements.items():
|
|
after = set(assignments)
|
|
before = set(new_placements.get(node, []))
|
|
removed += len(before.difference(after))
|
|
added += len(after.difference(before))
|
|
|
|
assert added == removed
|
|
assert 202 == (added + removed)
|
|
|
|
|
|
def collide(key, seed):
|
|
return 1337
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_rendezvous_collision():
|
|
nodes = ["c", "b", "a"]
|
|
rendezvous = RendezvousHash(nodes, hash_function=collide)
|
|
|
|
for i in range(1000):
|
|
assert "c" == rendezvous.get_node(i)
|
|
|
|
|
|
@pytest.mark.unit()
|
|
def test_rendezvous_names():
|
|
nodes = [1, 2, 3, "a", "b", "lol.wat.com"]
|
|
rendezvous = RendezvousHash(nodes, hash_function=collide)
|
|
|
|
for i in range(10):
|
|
assert "lol.wat.com" == rendezvous.get_node(i)
|
|
|
|
nodes = [1, "a", "0"]
|
|
rendezvous = RendezvousHash(nodes, hash_function=collide)
|
|
|
|
for i in range(10):
|
|
assert "a" == rendezvous.get_node(i)
|