summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua/clever_f/repeat_resolver.lua42
-rw-r--r--tests/run.lua24
2 files changed, 66 insertions, 0 deletions
diff --git a/lua/clever_f/repeat_resolver.lua b/lua/clever_f/repeat_resolver.lua
index 5e1dc41..c62a86f 100644
--- a/lua/clever_f/repeat_resolver.lua
+++ b/lua/clever_f/repeat_resolver.lua
@@ -34,6 +34,22 @@ local function require_policy(service)
return service
end
+local function require_clock(clock)
+ if clock ~= nil and (type(clock) ~= "table"
+ or type(clock.read_time_ms) ~= "function")
+ then
+ fail("RepeatResolver clock must provide read_time_ms", 3)
+ end
+ return clock
+end
+
+local function finite_time(value)
+ return type(value) == "number"
+ and value == value
+ and value > -math.huge
+ and value < math.huge
+end
+
local resolver_metatable = {
__index = RepeatResolver,
__newindex = function()
@@ -64,6 +80,7 @@ function RepeatResolver.new(options)
local resolver = setmetatable({}, resolver_metatable)
resolver_records[resolver] = {
+ clock = require_clock(options.clock or options.time_provider or options.host),
policy = require_policy(options.policy or options.policy_service),
state = state,
}
@@ -109,6 +126,27 @@ end
RepeatResolver.sample_repeat_timeout = RepeatResolver.sample_repeat_timeout_ms
+function RepeatResolver:evaluate_timeout()
+ local timeout = self:sample_repeat_timeout_ms()
+ if timeout == 0 then
+ return M.Decision.REPEAT, nil
+ end
+
+ local clock = resolver_records[self].clock
+ if clock == nil then
+ fail("RepeatResolver requires a clock for positive repeat timeout", 2)
+ end
+ local current_time = clock:read_time_ms()
+ if not finite_time(current_time) then
+ fail("repeat clock must return finite milliseconds", 2)
+ end
+ local elapsed_ms = current_time - resolver_records[self].state.repeat_timestamp_ms
+ return nil, elapsed_ms
+end
+
+RepeatResolver.check_timeout = RepeatResolver.evaluate_timeout
+RepeatResolver.resolve_timeout = RepeatResolver.evaluate_timeout
+
function M.new(options)
return RepeatResolver.new(options)
end
@@ -131,6 +169,10 @@ function M.sample_repeat_timeout_ms(options)
return RepeatResolver.new(options):sample_repeat_timeout_ms()
end
+function M.evaluate_timeout(options)
+ return RepeatResolver.new(options):evaluate_timeout()
+end
+
setmetatable(M, {
__call = function(_, options)
return RepeatResolver.new(options)
diff --git a/tests/run.lua b/tests/run.lua
index a2bf7e1..437a3ba 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -3860,6 +3860,30 @@ test("Repeated primary timeout is sampled from live policy", function()
end, "requires a policy")
end)
+test("Positive repeat timeout reads the current clock", function()
+ local _, transitions = fresh_sequence_state()
+ transitions:SetRepeatTimestamp(25.25)
+ local host = MemoryHost.new({
+ configuration = { repeat_timeout_ms = 100 },
+ time_values_ms = { 125.75 },
+ })
+ local resolver = repeat_resolver.new({
+ clock = host,
+ policy = policy.new(host),
+ })
+
+ local decision, elapsed_ms = resolver:evaluate_timeout()
+ same(nil, decision)
+ same(100.5, elapsed_ms)
+ local reads = 0
+ for _, operation in ipairs(host:operations()) do
+ if operation.operation == "read_time_ms" then
+ reads = reads + 1
+ end
+ end
+ same(1, reads)
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then