Merge pull request #2711 from psychon/improve_test_runner

Improve the test runner: allow "direct" tests (instead of only steps-based tests)
This commit is contained in:
Daniel Hahler 2019-03-03 11:12:04 +01:00 committed by GitHub
commit a802d0c2c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 93 deletions

View File

@ -43,7 +43,54 @@ runner.step_kill_clients = function(step)
end end
end end
runner.run_steps = function(steps, options) --- Print a message if verbose mode is enabled.
-- @tparam string message The message to print.
function runner.verbose(message)
if verbose then
io.stderr:write(message .. "\n")
end
end
--- When using run_direct(), this function indicates that the test is now done.
-- @tparam[opt=nil] string message An error message explaining the test failure, if it failed.
function runner.done(message)
if message then
io.stderr:write("Error: " .. message .. "\n")
if not runner.quit_awesome_on_error then
io.stderr:write("Keeping awesome open...\n")
return
end
end
local client_count = #client.get()
if client_count > 0 then
io.stderr:write(string.format(
"NOTE: there were %d clients left after the test.\n", client_count))
-- Remove any clients.
for _,c in ipairs(client.get()) do
c:kill()
end
end
if not message then
io.stderr:write("Test finished successfully.\n")
end
awesome.quit()
end
--- This function is called to indicate that a test does not use the run_steps()
-- facility, but instead runs something else directly.
function runner.run_direct()
assert(not running, "API abuse: Test was started twice")
running = true
end
--- Start some step-wise tests. The given steps are called in order until all
-- succeeded. Each step is a function that can return true/false to indicate
-- success/failure, but can also return nothing if it needs to be called again
-- later.
function runner.run_steps(steps, options)
-- Setup timer/timeout to limit waiting for signal and quitting awesome. -- Setup timer/timeout to limit waiting for signal and quitting awesome.
local t = timer({timeout=0}) local t = timer({timeout=0})
local wait=20 local wait=20
@ -52,8 +99,7 @@ runner.run_steps = function(steps, options)
options = options or { options = options or {
kill_clients=true, kill_clients=true,
} }
assert(not running, "run_steps() was called twice") runner.run_direct()
running = true
if options.kill_clients then if options.kill_clients then
-- Add a final step to kill all clients and wait for them to finish. -- Add a final step to kill all clients and wait for them to finish.
@ -65,9 +111,7 @@ runner.run_steps = function(steps, options)
io.flush() -- for "tail -f". io.flush() -- for "tail -f".
step_count = step_count + 1 step_count = step_count + 1
local step_as_string = step..'/'..#steps..' (@'..step_count..')' local step_as_string = step..'/'..#steps..' (@'..step_count..')'
if verbose then runner.verbose(string.format('Running step %s..\n', step_as_string))
io.stderr:write(string.format('Running step %s..\n', step_as_string))
end
-- Call the current step's function. -- Call the current step's function.
local success, result = xpcall(function() local success, result = xpcall(function()
@ -75,14 +119,9 @@ runner.run_steps = function(steps, options)
end, debug.traceback) end, debug.traceback)
if not success then if not success then
io.stderr:write('Error: running function for step ' runner.done('running function for step '
..step_as_string..': '..tostring(result)..'!\n') ..step_as_string..': '..tostring(result)..'!')
t:stop() 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 elseif result then
-- true: test succeeded. -- true: test succeeded.
if step < #steps then if step < #steps then
@ -92,16 +131,12 @@ runner.run_steps = function(steps, options)
wait = 20 wait = 20
t.timeout = 0 t.timeout = 0
t:again() t:again()
return else
-- All steps finished, we are done.
runner.done()
end end
elseif result == false then elseif result == false then
io.stderr:write("Step "..step_as_string.." failed (returned false).\n") runner.done("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 else
-- No result yet, run this step again. -- No result yet, run this step again.
wait = wait-1 wait = wait-1
@ -109,28 +144,11 @@ runner.run_steps = function(steps, options)
t.timeout = 0.1 t.timeout = 0.1
t:again() t:again()
else else
io.stderr:write("Error: timeout waiting for signal in step " runner.done("timeout waiting for signal in step "
..step_as_string..".\n") ..step_as_string..".")
t:stop() t:stop()
end end
return
end end
local client_count = #client.get()
if client_count > 0 then
io.stderr:write(string.format(
"NOTE: there were %d clients left after the test.\n", client_count))
-- Remove any clients.
for _,c in ipairs(client.get()) do
c:kill()
end
end
if success and result then
io.stderr:write("Test finished successfully.\n")
end
awesome.quit()
end) end) end) end)
t:start() t:start()
end end

View File

@ -3,62 +3,44 @@
local runner = require("_runner") local runner = require("_runner")
local spawn = require("awful.spawn") local spawn = require("awful.spawn")
local todo = 2 local had_exit, had_success
local had_error = false local had_error = false
local function wait_a_bit(count) local function check_done()
if todo == 0 or count == 5 then if had_exit and had_success then
return true if had_error then
end runner.done("Some error occurred, see above")
end else
runner.run_steps({ runner.done()
function()
local err = spawn.with_line_callback(
{ os.getenv("build_dir") .. "/test-gravity" },
{
exit = function(what, code)
assert(what == "exit", what)
assert(code == 0, "Exit code was " .. code)
todo = todo - 1
end,
stderr = function(line)
had_error = true
print("Read on stderr: " .. line)
end,
stdout = function(line)
if line == "SUCCESS" then
todo = todo - 1
elseif line:sub(1, 5) ~= "LOG: " then
had_error = true
print("Read on stdout: " .. line)
end
end
})
assert(type(err) ~= "string", err)
return true
end,
-- Buy the external program some time to finish
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
wait_a_bit,
function()
if todo == 0 then
assert(not had_error, "Some error occurred, see above")
return true
end end
end end
}) end
local err = spawn.with_line_callback(
{ os.getenv("build_dir") .. "/test-gravity" },
{
exit = function(what, code)
assert(what == "exit", what)
assert(code == 0, "Exit code was " .. code)
had_exit = true
check_done()
end,
stderr = function(line)
had_error = true
print("Read on stderr: " .. line)
end,
stdout = function(line)
if line == "SUCCESS" then
had_success = true
check_done()
elseif line:sub(1, 5) ~= "LOG: " then
had_error = true
print("Read on stdout: " .. line)
end
end
})
assert(type(err) ~= "string", err)
runner.run_direct()
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80