awesome/tests/_runner.lua
Uli Schlachter e18bece3df Make tests more reliable on "early errors"
When e.g. test-leaks.lua fails, it will cause a Lua error before starting the
test runner. This means that the test will just hang, because nothing causes
awesome to quit.

Handle this by starting a timer when the test runner is loaded and quitting
awesome in there if no test run was started yet. This only works if all tests
load the runner before doing anything that could fail, so the require("_runner")
is moved to the beginning in every test.

Signed-off-by: Uli Schlachter <psychon@znc.in>
2016-03-06 10:20:45 +01:00

108 lines
3 KiB
Lua

local timer = require("gears.timer")
local awful = require("awful")
local runner = {
quit_awesome_on_error = os.getenv('TEST_PAUSE_ON_ERRORS') ~= '1',
-- quit-on-timeout defaults to false: indicates some problem with the test itself.
quit_awesome_on_timeout = os.getenv('TEST_QUIT_ON_TIMEOUT') ~= '1',
}
-- Helpers.
--- Add some rules to awful.rules.rules, after the defaults.
local default_rules = awful.util.table.clone(awful.rules.rules)
runner.add_to_default_rules = function(r)
awful.rules.rules = awful.util.table.clone(default_rules)
table.insert(awful.rules.rules, r)
end
-- Was the runner started already?
local running = false
-- This is used if a test causes errors before starting the runner
timer.start_new(1, function()
if not running then
io.stderr:write("Error: run_steps() was never called\n")
if not runner.quit_awesome_on_error then
io.stderr:write("Keeping awesome open...\n")
return -- keep awesome open on error.
end
awesome.quit()
end
end)
runner.run_steps = function(steps)
-- Setup timer/timeout to limit waiting for signal and quitting awesome.
-- This would be common for all tests.
local t = timer({timeout=0.1})
local wait=20
local step=1
local step_count=0
assert(not running, "run_steps() was called twice")
running = true
t:connect_signal("timeout", function() timer.delayed_call(function()
io.flush() -- for "tail -f".
step_count = step_count + 1
local step_as_string = step..'/'..#steps..' (@'..step_count..')'
-- Call the current step's function.
local success, result = xpcall(function()
return steps[step](step_count)
end, debug.traceback)
if not success then
io.stderr:write('Error: running function for step '
..step_as_string..': '..tostring(result)..'!\n')
t:stop()
if not runner.quit_awesome_on_error then
io.stderr:write("Keeping awesome open...\n")
return -- keep awesome open on error.
end
elseif result then
-- true: test succeeded.
if step < #steps then
-- Next step.
step = step+1
step_count = 0
wait = 5
t:again()
return
end
elseif result == false then
io.stderr:write("Step "..step_as_string.." failed (returned false).")
if not runner.quit_awesome_on_error then
io.stderr:write("Keeping awesome open...\n")
return
end
else
wait = wait-1
if wait > 0 then
t:again()
return
else
io.stderr:write("Error: timeout waiting for signal in step "
..step_as_string..".\n")
t:stop()
if not runner.quit_awesome_on_timeout then
return
end
end
end
-- Remove any clients.
for _,c in ipairs(client.get()) do
c:kill()
end
if success and result then
io.stderr:write("Test finished successfully\n")
end
awesome.quit()
end) end)
t:start()
end
return runner
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80