Annotate

spec/util_hashring_spec.lua @ 13190:9dc6de46dae3

mod_storage_sql: Remove completed TODO (testing UPSERT on PostgreSQL)
author Kim Alvefur <zash@zash.se>
date Wed, 12 Jul 2023 22:51:37 +0200
parent 12795:87424cbedc55
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
10007
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1 local hashring = require "util.hashring";
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
2
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
3 describe("util.hashring", function ()
12794
249b01adc54a util.hashring: tests: don't randomize order - they are written in a sequential style
Matthew Wild <mwild1@gmail.com>
parents: 10007
diff changeset
4 randomize(false);
10007
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
5
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
6 local sha256 = require "util.hashes".sha256;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
7
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8 local ring = hashring.new(128, sha256);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
9
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
10 it("should fail to get a node that does not exist", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 assert.is_nil(ring:get_node("foo"))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
12 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
13
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
14 it("should support adding nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
15 ring:add_node("node1");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 it("should return a single node for all keys if only one node exists", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
19 for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
20 assert.is_equal("node1", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
21 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
22 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
23
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
24 it("should support adding a second node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
25 ring:add_node("node2");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
26 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28 it("should fail to remove a non-existent node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29 assert.is_falsy(ring:remove_node("node3"));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
30 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
31
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32 it("should succeed to remove a node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 assert.is_truthy(ring:remove_node("node1"));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
34 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 it("should return the only node for all keys", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38 assert.is_equal("node2", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42 it("should support adding multiple nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 ring:add_nodes({ "node1", "node3", "node4", "node5" });
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 it("should disrupt a minimal number of keys on node removal", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 local orig_ring = ring:clone();
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48 local node_tallies = {};
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 local n = 1000;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
51
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 for i = 1, n do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53 local key = tostring(i);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 local node = ring:get_node(key);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
55 node_tallies[node] = (node_tallies[node] or 0) + 1;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
57
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
58 --[[
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
59 for node, key_count in pairs(node_tallies) do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
60 print(node, key_count, ("%.2f%%"):format((key_count/n)*100));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
61 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
62 ]]
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
63
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
64 ring:remove_node("node5");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
65
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
66 local disrupted_keys = 0;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
67 for i = 1, n do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
68 local key = tostring(i);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
69 if orig_ring:get_node(key) ~= ring:get_node(key) then
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
70 disrupted_keys = disrupted_keys + 1;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
71 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
73 assert.is_equal(node_tallies["node5"], disrupted_keys);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
74 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
75
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
76 it("should support removing multiple nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
77 ring:remove_nodes({"node2", "node3", "node4", "node5"});
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
78 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
79
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
80 it("should return a single node for all keys if only one node remains", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
81 for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
82 assert.is_equal("node1", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
83 end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
84 end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
85
12795
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
86 it("should support values associated with nodes", function ()
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
87 local r = hashring.new(128, sha256);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
88 r:add_node("node1", { a = 1 });
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
89 local node, value = r:get_node("foo");
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
90 assert.is_equal("node1", node);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
91 assert.same({ a = 1 }, value);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12794
diff changeset
92 end);
10007
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
93 end);