Software /
code /
prosody
File
spec/util_cache_spec.lua @ 12863:891edd1ebde6 0.12
util.startup: Close state on exit to ensure GC finalizers are called
Ensures a last round of garbage collection and that finalizers are
called. Fixes things like proper closing of SQLite3 state.
There are more calls to os.exit() but most of them exit with an error or
in a case where a final GC sweep might not matter as much.
It would be nice if this was the default.
Calling util.statup.exit() everywhere may be sensible, but would be more
involved, requiring imports everywhere.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 22 Jan 2023 14:45:47 +0100 |
parent | 11366:618ab9bba1c2 |
child | 12571:c4337ff4f1c4 |
line wrap: on
line source
local cache = require "util.cache"; describe("util.cache", function() describe("#new()", function() it("should work", function() local c = cache.new(5); local function expect_kv(key, value, actual_key, actual_value) assert.are.equal(key, actual_key, "key incorrect"); assert.are.equal(value, actual_value, "value incorrect"); end expect_kv(nil, nil, c:head()); expect_kv(nil, nil, c:tail()); assert.are.equal(c:count(), 0); c:set("one", 1) assert.are.equal(c:count(), 1); expect_kv("one", 1, c:head()); expect_kv("one", 1, c:tail()); c:set("two", 2) expect_kv("two", 2, c:head()); expect_kv("one", 1, c:tail()); c:set("three", 3) expect_kv("three", 3, c:head()); expect_kv("one", 1, c:tail()); c:set("four", 4) c:set("five", 5); assert.are.equal(c:count(), 5); expect_kv("five", 5, c:head()); expect_kv("one", 1, c:tail()); c:set("foo", nil); assert.are.equal(c:count(), 5); expect_kv("five", 5, c:head()); expect_kv("one", 1, c:tail()); assert.are.equal(c:get("one"), 1); expect_kv("five", 5, c:head()); expect_kv("one", 1, c:tail()); assert.are.equal(c:get("two"), 2); assert.are.equal(c:get("three"), 3); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("foo"), nil); assert.are.equal(c:get("bar"), nil); c:set("six", 6); assert.are.equal(c:count(), 5); expect_kv("six", 6, c:head()); expect_kv("two", 2, c:tail()); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), 2); assert.are.equal(c:get("three"), 3); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("six"), 6); c:set("three", nil); assert.are.equal(c:count(), 4); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), 2); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("six"), 6); c:set("seven", 7); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), 2); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); c:set("eight", 8); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); c:set("four", 4); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), 5); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); c:set("nine", 9); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), 4); assert.are.equal(c:get("five"), nil); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); assert.are.equal(c:get("nine"), 9); do local keys = { "nine", "four", "eight", "seven", "six" }; local values = { 9, 4, 8, 7, 6 }; local i = 0; for k, v in c:items() do i = i + 1; assert.are.equal(k, keys[i]); assert.are.equal(v, values[i]); end assert.are.equal(i, 5); c:set("four", "2+2"); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), "2+2"); assert.are.equal(c:get("five"), nil); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); assert.are.equal(c:get("nine"), 9); end do local keys = { "four", "nine", "eight", "seven", "six" }; local values = { "2+2", 9, 8, 7, 6 }; local i = 0; for k, v in c:items() do i = i + 1; assert.are.equal(k, keys[i]); assert.are.equal(v, values[i]); end assert.are.equal(i, 5); c:set("foo", nil); assert.are.equal(c:count(), 5); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), "2+2"); assert.are.equal(c:get("five"), nil); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); assert.are.equal(c:get("nine"), 9); end do local keys = { "four", "nine", "eight", "seven", "six" }; local values = { "2+2", 9, 8, 7, 6 }; local i = 0; for k, v in c:items() do i = i + 1; assert.are.equal(k, keys[i]); assert.are.equal(v, values[i]); end assert.are.equal(i, 5); c:set("four", nil); assert.are.equal(c:get("one"), nil); assert.are.equal(c:get("two"), nil); assert.are.equal(c:get("three"), nil); assert.are.equal(c:get("four"), nil); assert.are.equal(c:get("five"), nil); assert.are.equal(c:get("six"), 6); assert.are.equal(c:get("seven"), 7); assert.are.equal(c:get("eight"), 8); assert.are.equal(c:get("nine"), 9); end do local keys = { "nine", "eight", "seven", "six" }; local values = { 9, 8, 7, 6 }; local i = 0; for k, v in c:items() do i = i + 1; assert.are.equal(k, keys[i]); assert.are.equal(v, values[i]); end assert.are.equal(i, 4); end do local evicted_key, evicted_value; local c2 = cache.new(3, function (_key, _value) evicted_key, evicted_value = _key, _value; end); local function set(k, v, should_evict_key, should_evict_value) evicted_key, evicted_value = nil, nil; c2:set(k, v); assert.are.equal(evicted_key, should_evict_key); assert.are.equal(evicted_value, should_evict_value); end set("a", 1) set("a", 1) set("a", 1) set("a", 1) set("a", 1) set("b", 2) set("c", 3) set("b", 2) set("d", 4, "a", 1) set("e", 5, "c", 3) end do local evicted_key, evicted_value; local c3 = cache.new(1, function (_key, _value) evicted_key, evicted_value = _key, _value; if _key == "a" then -- Sanity check for what we're evicting assert.are.equal(_key, "a"); assert.are.equal(_value, 1); -- We're going to block eviction of this key/value, so set to nil... evicted_key, evicted_value = nil, nil; -- Returning false to block eviction return false end end); local function set(k, v, should_evict_key, should_evict_value) evicted_key, evicted_value = nil, nil; local ret = c3:set(k, v); assert.are.equal(evicted_key, should_evict_key); assert.are.equal(evicted_value, should_evict_value); return ret; end set("a", 1) set("a", 1) set("a", 1) set("a", 1) set("a", 1) -- Our on_evict prevents "a" from being evicted, causing this to fail... assert.are.equal(set("b", 2), false, "Failed to prevent eviction, or signal result"); expect_kv("a", 1, c3:head()); expect_kv("a", 1, c3:tail()); -- Check the final state is what we expect assert.are.equal(c3:get("a"), 1); assert.are.equal(c3:get("b"), nil); assert.are.equal(c3:count(), 1); end local c4 = cache.new(3, false); assert.are.equal(c4:set("a", 1), true); assert.are.equal(c4:set("a", 1), true); assert.are.equal(c4:set("a", 1), true); assert.are.equal(c4:set("a", 1), true); assert.are.equal(c4:set("b", 2), true); assert.are.equal(c4:set("c", 3), true); assert.are.equal(c4:set("d", 4), false); assert.are.equal(c4:set("d", 4), false); assert.are.equal(c4:set("d", 4), false); expect_kv("c", 3, c4:head()); expect_kv("a", 1, c4:tail()); local c5 = cache.new(3, function (k, v) --luacheck: ignore 212/v if k == "a" then return nil; elseif k == "b" then return true; end return false; end); assert.are.equal(c5:set("a", 1), true); assert.are.equal(c5:set("a", 1), true); assert.are.equal(c5:set("a", 1), true); assert.are.equal(c5:set("a", 1), true); assert.are.equal(c5:set("b", 2), true); assert.are.equal(c5:set("c", 3), true); assert.are.equal(c5:set("d", 4), true); -- "a" evicted (cb returned nil) assert.are.equal(c5:set("d", 4), true); -- nop assert.are.equal(c5:set("d", 4), true); -- nop assert.are.equal(c5:set("e", 5), true); -- "b" evicted (cb returned true) assert.are.equal(c5:set("f", 6), false); -- "c" won't evict (cb returned false) expect_kv("e", 5, c5:head()); expect_kv("c", 3, c5:tail()); end); (_VERSION=="Lua 5.1" and pending or it)(":table works", function () local t = cache.new(3):table(); assert.is.table(t); t["a"] = "1"; assert.are.equal(t["a"], "1"); t["b"] = "2"; assert.are.equal(t["b"], "2"); t["c"] = "3"; assert.are.equal(t["c"], "3"); t["d"] = "4"; assert.are.equal(t["d"], "4"); assert.are.equal(t["a"], nil); local i = spy.new(function () end); for k, v in pairs(t) do i(k,v) end assert.spy(i).was_called(); assert.spy(i).was_called_with("b", "2"); assert.spy(i).was_called_with("c", "3"); assert.spy(i).was_called_with("d", "4"); end); end); end);