spec/util_hashring_spec.lua
author Matthew Wild <mwild1@gmail.com>
Wed, 27 Mar 2024 15:35:15 +0000
branch0.12
changeset 13469 54a936345aaa
parent 10011 de43ca319184
child 12798 249b01adc54a
permissions -rw-r--r--
prosodyctl check: Warn about invalid domain names in the config file This ensures that domain names of virtual hosts and components are valid in XMPP, and that they are encoded correctly.
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 ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     5
	local sha256 = require "util.hashes".sha256;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
	local ring = hashring.new(128, sha256);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
	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
    10
		assert.is_nil(ring:get_node("foo"))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
	it("should support adding nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
		ring:add_node("node1");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
	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
    18
		for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
			assert.is_equal("node1", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
		end
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
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
	it("should support adding a second node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
		ring:add_node("node2");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
	it("should fail to remove a non-existent node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
		assert.is_falsy(ring:remove_node("node3"));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	it("should succeed to remove a node", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
		assert.is_truthy(ring:remove_node("node1"));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
	it("should return the only node for all keys", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
		for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
			assert.is_equal("node2", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
		end
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
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
	it("should support adding multiple nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
		ring:add_nodes({ "node1", "node3", "node4", "node5" });
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
	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
    46
		local orig_ring = ring:clone();
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
		local node_tallies = {};
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
		local n = 1000;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
		for i = 1, n do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
			local key = tostring(i);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
			local node = ring:get_node(key);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
			node_tallies[node] = (node_tallies[node] or 0) + 1;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
		end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
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
		for node, key_count in pairs(node_tallies) do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
			print(node, key_count, ("%.2f%%"):format((key_count/n)*100));
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
		end
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
		]]
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
		ring:remove_node("node5");
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
		local disrupted_keys = 0;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
		for i = 1, n do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
			local key = tostring(i);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
			if orig_ring:get_node(key) ~= ring:get_node(key) then
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
				disrupted_keys = disrupted_keys + 1;
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
			end
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
		assert.is_equal(node_tallies["node5"], disrupted_keys);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
	it("should support removing multiple nodes", function ()
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
		ring:remove_nodes({"node2", "node3", "node4", "node5"});
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
	end);
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    79
	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
    80
		for i = 1, 100 do
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
			assert.is_equal("node1", ring:get_node(tostring(i)))
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    82
		end
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
de43ca319184 util.hashring: Add tests
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
end);