Skip to content

Commit

Permalink
Retry on a Lua error in test_run:wait_cond()
Browse files Browse the repository at this point in the history
I think that a developer expects that wait_cond() will continue retrying
on any failure: as on a negative result from the condition function, as
well as when it raises a Lua error.

See motivating example in the linked issue: it was not obvious that a
condition function may raise an error in this case. I guess it is more
or less frequent case.

Fixes tarantool/tarantool-qa#128
  • Loading branch information
Totktonada authored and kyukhin committed Jun 23, 2021
1 parent 53389a8 commit ab453e3
Showing 1 changed file with 27 additions and 5 deletions.
32 changes: 27 additions & 5 deletions test_run.lua
Original file line number Diff line number Diff line change
Expand Up @@ -405,30 +405,52 @@ local function grep_log(self, node, what, bytes, opts)
return found
end

-- Strip pcall()'s true or re-raise catched error.
local function wait_cond_finish(res)
-- res: 1: pcall_ok
-- 2: pcall_error / cond_function_res_1
-- 3: cond_function_res_2
-- 4: cond_function_res_3
-- ...
--
-- cond_function_res_1 is the 'ok' / 'not ok' indicator for
-- wait_cond(). But we return it: this is deliberate choice.
-- This way a user may understand, whether we finally hit
-- timeout or not.
if not res[1] then
error(res[2])
end
return select(2, unpack(res))
end

-- Block until the condition function returns a positive value
-- (anything except `nil` and `false`) or until the timeout
-- exceeds. Return the result of the last invocation of the
-- condition function (it is `false` or `nil` in case of exiting
-- by the timeout).
--
-- If the condition function raises a Lua error, wait_cond()
-- continues retrying. If the latest attempt raises an error (and
-- we hit a timeout), the error will be re-raised.
local function wait_cond(self, cond, timeout, delay)
assert(type(cond) == 'function')

local timeout = timeout or 60
local delay = delay or 0.001

local start_time = clock.monotonic()
local res = {cond()}
local res = {pcall(cond)}

while not res[1] do
while not res[1] or not res[2] do
local work_time = clock.monotonic() - start_time
if work_time > timeout then
return unpack(res)
return wait_cond_finish(res)
end
fiber.sleep(delay)
res = {cond()}
res = {pcall(cond)}
end

return unpack(res)
return wait_cond_finish(res)
end

-- Wrapper for grep_log, wait until expected log entry is appear
Expand Down

0 comments on commit ab453e3

Please sign in to comment.