|
1 local hashring = require "util.hashring"; |
|
2 |
|
3 describe("util.hashring", function () |
|
4 |
|
5 local sha256 = require "util.hashes".sha256; |
|
6 |
|
7 local ring = hashring.new(128, sha256); |
|
8 |
|
9 it("should fail to get a node that does not exist", function () |
|
10 assert.is_nil(ring:get_node("foo")) |
|
11 end); |
|
12 |
|
13 it("should support adding nodes", function () |
|
14 ring:add_node("node1"); |
|
15 end); |
|
16 |
|
17 it("should return a single node for all keys if only one node exists", function () |
|
18 for i = 1, 100 do |
|
19 assert.is_equal("node1", ring:get_node(tostring(i))) |
|
20 end |
|
21 end); |
|
22 |
|
23 it("should support adding a second node", function () |
|
24 ring:add_node("node2"); |
|
25 end); |
|
26 |
|
27 it("should fail to remove a non-existent node", function () |
|
28 assert.is_falsy(ring:remove_node("node3")); |
|
29 end); |
|
30 |
|
31 it("should succeed to remove a node", function () |
|
32 assert.is_truthy(ring:remove_node("node1")); |
|
33 end); |
|
34 |
|
35 it("should return the only node for all keys", function () |
|
36 for i = 1, 100 do |
|
37 assert.is_equal("node2", ring:get_node(tostring(i))) |
|
38 end |
|
39 end); |
|
40 |
|
41 it("should support adding multiple nodes", function () |
|
42 ring:add_nodes({ "node1", "node3", "node4", "node5" }); |
|
43 end); |
|
44 |
|
45 it("should disrupt a minimal number of keys on node removal", function () |
|
46 local orig_ring = ring:clone(); |
|
47 local node_tallies = {}; |
|
48 |
|
49 local n = 1000; |
|
50 |
|
51 for i = 1, n do |
|
52 local key = tostring(i); |
|
53 local node = ring:get_node(key); |
|
54 node_tallies[node] = (node_tallies[node] or 0) + 1; |
|
55 end |
|
56 |
|
57 --[[ |
|
58 for node, key_count in pairs(node_tallies) do |
|
59 print(node, key_count, ("%.2f%%"):format((key_count/n)*100)); |
|
60 end |
|
61 ]] |
|
62 |
|
63 ring:remove_node("node5"); |
|
64 |
|
65 local disrupted_keys = 0; |
|
66 for i = 1, n do |
|
67 local key = tostring(i); |
|
68 if orig_ring:get_node(key) ~= ring:get_node(key) then |
|
69 disrupted_keys = disrupted_keys + 1; |
|
70 end |
|
71 end |
|
72 assert.is_equal(node_tallies["node5"], disrupted_keys); |
|
73 end); |
|
74 |
|
75 it("should support removing multiple nodes", function () |
|
76 ring:remove_nodes({"node2", "node3", "node4", "node5"}); |
|
77 end); |
|
78 |
|
79 it("should return a single node for all keys if only one node remains", function () |
|
80 for i = 1, 100 do |
|
81 assert.is_equal("node1", ring:get_node(tostring(i))) |
|
82 end |
|
83 end); |
|
84 |
|
85 end); |