spec/util_hashring_spec.lua
author Kim Alvefur <zash@zash.se>
Wed, 27 Mar 2024 19:33:11 +0100
changeset 13471 c2a476f4712a
parent 12799 87424cbedc55
permissions -rw-r--r--
util.startup: Fix exiting on pidfile trouble prosody.shutdown() relies on prosody.main_thread, which has not been set yet at this point. Doing a clean shutdown might actually be harmful in case it tears down things set up by the conflicting Prosody, such as the very pidfile we were looking at. Thanks again SigmaTel71 for noticing
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
10011
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 ()
12798
249b01adc54a util.hashring: tests: don't randomize order - they are written in a sequential style
Matthew Wild <mwild1@gmail.com>
parents: 10011
diff changeset
     4
	randomize(false);
10011
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
12799
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12798
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: 12798
diff changeset
    87
		local r = hashring.new(128, sha256);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12798
diff changeset
    88
		r:add_node("node1", { a = 1 });
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12798
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: 12798
diff changeset
    90
		assert.is_equal("node1", node);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12798
diff changeset
    91
		assert.same({ a = 1 }, value);
87424cbedc55 util.hashring: Support associating arbitrary data with nodes
Matthew Wild <mwild1@gmail.com>
parents: 12798
diff changeset
    92
	end);
10011
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    93
end);