test_rendezvous.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. from library.pymemcache.client.rendezvous import RendezvousHash
  2. import pytest
  3. @pytest.mark.unit()
  4. def test_init_no_options():
  5. rendezvous = RendezvousHash()
  6. assert 0 == len(rendezvous.nodes)
  7. assert 1361238019 == rendezvous.hash_function('6666')
  8. @pytest.mark.unit()
  9. def test_init():
  10. nodes = ['0', '1', '2']
  11. rendezvous = RendezvousHash(nodes=nodes)
  12. assert 3 == len(rendezvous.nodes)
  13. assert 1361238019 == rendezvous.hash_function('6666')
  14. @pytest.mark.unit()
  15. def test_seed():
  16. rendezvous = RendezvousHash(seed=10)
  17. assert 2981722772 == rendezvous.hash_function('6666')
  18. @pytest.mark.unit()
  19. def test_add_node():
  20. rendezvous = RendezvousHash()
  21. rendezvous.add_node('1')
  22. assert 1 == len(rendezvous.nodes)
  23. rendezvous.add_node('1')
  24. assert 1 == len(rendezvous.nodes)
  25. rendezvous.add_node('2')
  26. assert 2 == len(rendezvous.nodes)
  27. rendezvous.add_node('1')
  28. assert 2 == len(rendezvous.nodes)
  29. @pytest.mark.unit()
  30. def test_remove_node():
  31. nodes = ['0', '1', '2']
  32. rendezvous = RendezvousHash(nodes=nodes)
  33. rendezvous.remove_node('2')
  34. assert 2 == len(rendezvous.nodes)
  35. with pytest.raises(ValueError):
  36. rendezvous.remove_node('2')
  37. assert 2 == len(rendezvous.nodes)
  38. rendezvous.remove_node('1')
  39. assert 1 == len(rendezvous.nodes)
  40. rendezvous.remove_node('0')
  41. assert 0 == len(rendezvous.nodes)
  42. @pytest.mark.unit()
  43. def test_get_node():
  44. nodes = ['0', '1', '2']
  45. rendezvous = RendezvousHash(nodes=nodes)
  46. assert '0' == rendezvous.get_node('ok')
  47. assert '1' == rendezvous.get_node('mykey')
  48. assert '2' == rendezvous.get_node('wat')
  49. @pytest.mark.unit()
  50. def test_get_node_after_removal():
  51. nodes = ['0', '1', '2']
  52. rendezvous = RendezvousHash(nodes=nodes)
  53. rendezvous.remove_node('1')
  54. assert '0' == rendezvous.get_node('ok')
  55. assert '0' == rendezvous.get_node('mykey')
  56. assert '2' == rendezvous.get_node('wat')
  57. @pytest.mark.unit()
  58. def test_get_node_after_addition():
  59. nodes = ['0', '1', '2']
  60. rendezvous = RendezvousHash(nodes=nodes)
  61. assert '0' == rendezvous.get_node('ok')
  62. assert '1' == rendezvous.get_node('mykey')
  63. assert '2' == rendezvous.get_node('wat')
  64. assert '2' == rendezvous.get_node('lol')
  65. rendezvous.add_node('3')
  66. assert '0' == rendezvous.get_node('ok')
  67. assert '1' == rendezvous.get_node('mykey')
  68. assert '2' == rendezvous.get_node('wat')
  69. assert '3' == rendezvous.get_node('lol')
  70. @pytest.mark.unit()
  71. def test_grow():
  72. rendezvous = RendezvousHash()
  73. placements = {}
  74. for i in range(10):
  75. rendezvous.add_node(str(i))
  76. placements[str(i)] = []
  77. for i in range(1000):
  78. node = rendezvous.get_node(str(i))
  79. placements[node].append(i)
  80. new_placements = {}
  81. for i in range(20):
  82. rendezvous.add_node(str(i))
  83. new_placements[str(i)] = []
  84. for i in range(1000):
  85. node = rendezvous.get_node(str(i))
  86. new_placements[node].append(i)
  87. keys = [k for sublist in placements.values() for k in sublist]
  88. new_keys = [k for sublist in new_placements.values() for k in sublist]
  89. assert sorted(keys) == sorted(new_keys)
  90. added = 0
  91. removed = 0
  92. for node, assignments in new_placements.items():
  93. after = set(assignments)
  94. before = set(placements.get(node, []))
  95. removed += len(before.difference(after))
  96. added += len(after.difference(before))
  97. assert added == removed
  98. assert 1062 == (added + removed)
  99. @pytest.mark.unit()
  100. def test_shrink():
  101. rendezvous = RendezvousHash()
  102. placements = {}
  103. for i in range(10):
  104. rendezvous.add_node(str(i))
  105. placements[str(i)] = []
  106. for i in range(1000):
  107. node = rendezvous.get_node(str(i))
  108. placements[node].append(i)
  109. rendezvous.remove_node('9')
  110. new_placements = {}
  111. for i in range(9):
  112. new_placements[str(i)] = []
  113. for i in range(1000):
  114. node = rendezvous.get_node(str(i))
  115. new_placements[node].append(i)
  116. keys = [k for sublist in placements.values() for k in sublist]
  117. new_keys = [k for sublist in new_placements.values() for k in sublist]
  118. assert sorted(keys) == sorted(new_keys)
  119. added = 0
  120. removed = 0
  121. for node, assignments in placements.items():
  122. after = set(assignments)
  123. before = set(new_placements.get(node, []))
  124. removed += len(before.difference(after))
  125. added += len(after.difference(before))
  126. assert added == removed
  127. assert 202 == (added + removed)
  128. def collide(key, seed):
  129. return 1337
  130. @pytest.mark.unit()
  131. def test_rendezvous_collision():
  132. nodes = ['c', 'b', 'a']
  133. rendezvous = RendezvousHash(nodes, hash_function=collide)
  134. for i in range(1000):
  135. assert 'c' == rendezvous.get_node(i)
  136. @pytest.mark.unit()
  137. def test_rendezvous_names():
  138. nodes = [1, 2, 3, 'a', 'b', 'lol.wat.com']
  139. rendezvous = RendezvousHash(nodes, hash_function=collide)
  140. for i in range(10):
  141. assert 'lol.wat.com' == rendezvous.get_node(i)
  142. nodes = [1, 'a', '0']
  143. rendezvous = RendezvousHash(nodes, hash_function=collide)
  144. for i in range(10):
  145. assert 'a' == rendezvous.get_node(i)