Add functional tests via Xephyr/Xvfb/xdotool
Closes https://github.com/awesomeWM/awesome/pull/133
This commit is contained in:
parent
ae6a1efe65
commit
611438a892
|
@ -90,6 +90,9 @@ install:
|
||||||
- tar xf cmake-3.2.3-Linux-x86_64.tar.Z
|
- tar xf cmake-3.2.3-Linux-x86_64.tar.Z
|
||||||
- PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH
|
- PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH
|
||||||
|
|
||||||
|
# Deps for functional tests.
|
||||||
|
- sudo apt-get install -qq dbus-x11 xterm xdotool xterm xvfb
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIB} -DLUA_INCLUDE_DIR=/usr/include/lua${LUAPKG}"
|
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIB} -DLUA_INCLUDE_DIR=/usr/include/lua${LUAPKG}"
|
||||||
- make && sudo env PATH=$PATH make install && awesome --version
|
- make && sudo env PATH=$PATH make install && awesome --version && tests/run.sh
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
timer = require("gears.timer")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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 = pcall(steps[step], step_count)
|
||||||
|
|
||||||
|
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
|
||||||
|
awesome.quit()
|
||||||
|
end) end)
|
||||||
|
t:start()
|
||||||
|
end
|
||||||
|
|
||||||
|
return runner
|
|
@ -0,0 +1,130 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# Change to file's dir (POSIXly).
|
||||||
|
cd -P -- "$(dirname -- "$0")"
|
||||||
|
this_dir=$PWD
|
||||||
|
|
||||||
|
# Get test files: test*, or the ones provided as args (relative to tests/).
|
||||||
|
if [ $# != 0 ]; then
|
||||||
|
tests="$@"
|
||||||
|
else
|
||||||
|
tests=$this_dir/test*.lua
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use a separate D-Bus session; sets $DBUS_SESSION_BUS_PID.
|
||||||
|
eval $(dbus-launch --sh-syntax)
|
||||||
|
|
||||||
|
root_dir=$PWD/..
|
||||||
|
|
||||||
|
# Travis.
|
||||||
|
if [ "$CI" = true ]; then
|
||||||
|
HEADLESS=1
|
||||||
|
TEST_PAUSE_ON_ERRORS=0
|
||||||
|
TEST_QUIT_ON_TIMEOUT=1
|
||||||
|
else
|
||||||
|
HEADLESS=0
|
||||||
|
TEST_PAUSE_ON_ERRORS=0
|
||||||
|
TEST_QUIT_ON_TIMEOUT=1
|
||||||
|
fi
|
||||||
|
export TEST_PAUSE_ON_ERRORS
|
||||||
|
|
||||||
|
XEPHYR=Xephyr
|
||||||
|
XVFB=Xvfb
|
||||||
|
AWESOME=$root_dir/build/awesome
|
||||||
|
RC_FILE=$root_dir/build/awesomerc.lua
|
||||||
|
D=:5
|
||||||
|
SIZE=1024x768
|
||||||
|
|
||||||
|
if [ $HEADLESS = 1 ]; then
|
||||||
|
"$XVFB" $D -screen 0 ${SIZE}x24 &
|
||||||
|
sleep 1
|
||||||
|
xserver_pid=$(pgrep -n Xvfb)
|
||||||
|
else
|
||||||
|
# export XEPHYR_PAUSE=1000
|
||||||
|
# if [ -f /tmp/.X5-lock ]; then
|
||||||
|
# echo "Xephyr is already running for display $D.. aborting." >&2
|
||||||
|
# exit 1
|
||||||
|
# fi
|
||||||
|
"$XEPHYR" $D -ac -name xephyr_$D -noreset -screen "$SIZE" $XEPHYR_OPTIONS &
|
||||||
|
sleep 1
|
||||||
|
xserver_pid=$(pgrep -n Xephyr)
|
||||||
|
fi
|
||||||
|
# Toggles debugging mode, using XEPHYR_PAUSE.
|
||||||
|
# pkill -USR1 Xephyr
|
||||||
|
|
||||||
|
|
||||||
|
cd $root_dir/build
|
||||||
|
|
||||||
|
LUA_PATH="$(lua -e 'print(package.path)');lib/?.lua;lib/?/init.lua"
|
||||||
|
# Add test dir (for _runner.lua).
|
||||||
|
LUA_PATH="$LUA_PATH;$this_dir/?.lua"
|
||||||
|
XDG_CONFIG_HOME="./"
|
||||||
|
export LUA_PATH
|
||||||
|
export XDG_CONFIG_HOME
|
||||||
|
|
||||||
|
# awesome_log=$(mktemp)
|
||||||
|
awesome_log=/tmp/_awesome_test.log
|
||||||
|
echo "awesome_log: $awesome_log"
|
||||||
|
|
||||||
|
cd -
|
||||||
|
|
||||||
|
|
||||||
|
kill_childs() {
|
||||||
|
for p in $awesome_pid $xserver_pid $DBUS_SESSION_BUS_PID; do
|
||||||
|
kill -TERM $p 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
# Cleanup on errors / aborting.
|
||||||
|
set_trap() {
|
||||||
|
trap "kill_childs" 2 3 15
|
||||||
|
}
|
||||||
|
set_trap
|
||||||
|
|
||||||
|
# Start awesome.
|
||||||
|
start_awesome() {
|
||||||
|
(cd $root_dir/build; \
|
||||||
|
DISPLAY=$D "$AWESOME" -c "$RC_FILE" $AWESOME_OPTIONS > $awesome_log 2>&1 || true &)
|
||||||
|
sleep 1
|
||||||
|
awesome_pid=$(pgrep -nf "awesome -c $RC_FILE" || true)
|
||||||
|
|
||||||
|
if [ -z $awesome_pid ]; then
|
||||||
|
echo "Error: Failed to start awesome (-c $RC_FILE)!"
|
||||||
|
echo "Log:"
|
||||||
|
cat "$awesome_log"
|
||||||
|
kill_childs
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set_trap
|
||||||
|
}
|
||||||
|
|
||||||
|
# Count errors.
|
||||||
|
errors=0
|
||||||
|
|
||||||
|
for f in $tests; do
|
||||||
|
echo "== Running $f =="
|
||||||
|
start_awesome
|
||||||
|
|
||||||
|
# Send the test file to awesome.
|
||||||
|
cat $f | DISPLAY=$D $root_dir/utils/awesome-client 2>&1
|
||||||
|
|
||||||
|
# Tail the log and quit, when awesome quits.
|
||||||
|
tail -f --pid $awesome_pid $awesome_log
|
||||||
|
|
||||||
|
if grep -q -E '^Error|assertion failed' $awesome_log; then
|
||||||
|
echo "===> ERROR running $f! <==="
|
||||||
|
grep --color -o --binary-files=text -E '^Error.*|.*assertion failed.*' $awesome_log
|
||||||
|
errors=$(expr $errors + 1)
|
||||||
|
|
||||||
|
if [ "$TEST_PAUSE_ON_ERRORS" = 1 ]; then
|
||||||
|
echo "Pausing... press Enter to continue."
|
||||||
|
read enter
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
kill_childs
|
||||||
|
|
||||||
|
[ $errors = 0 ] && exit 0 || exit 1
|
|
@ -0,0 +1,49 @@
|
||||||
|
--- Tests for focus signals / property.
|
||||||
|
-- Test for https://github.com/awesomeWM/awesome/issues/134.
|
||||||
|
|
||||||
|
awful = require("awful")
|
||||||
|
timer = require("gears.timer")
|
||||||
|
|
||||||
|
beautiful = require("beautiful")
|
||||||
|
beautiful.border_normal = "#0000ff"
|
||||||
|
beautiful.border_focus = "#00ff00"
|
||||||
|
|
||||||
|
client.connect_signal("focus", function(c)
|
||||||
|
c.border_color = "#ff0000"
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
local steps = {
|
||||||
|
-- border_color should get applied via focus signal for first client on tag.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then
|
||||||
|
awful.util.spawn("xterm")
|
||||||
|
else
|
||||||
|
local c = client.get()[1]
|
||||||
|
if c then
|
||||||
|
print(c.border_color)
|
||||||
|
assert(c.border_color == "#ff0000")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- border_color should get applied via focus signal for second client on tag.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then
|
||||||
|
awful.util.spawn("xterm")
|
||||||
|
else
|
||||||
|
if #client.get() == 2 then
|
||||||
|
local c = client.get()[1]
|
||||||
|
assert(c == client.focus)
|
||||||
|
if c then
|
||||||
|
assert(c.border_color == "#ff0000")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
require("_runner").run_steps(steps)
|
|
@ -0,0 +1,106 @@
|
||||||
|
--- Tests for urgent property.
|
||||||
|
|
||||||
|
awful = require("awful")
|
||||||
|
|
||||||
|
-- Some basic assertion that the tag is not marked "urgent" already.
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent") == nil)
|
||||||
|
|
||||||
|
|
||||||
|
-- Setup signal handler which should be called.
|
||||||
|
-- TODO: generalize and move to runner.
|
||||||
|
local urgent_cb_done
|
||||||
|
client.connect_signal("property::urgent", function (c)
|
||||||
|
urgent_cb_done = true
|
||||||
|
assert(c.class == "XTerm", "Client should be xterm!")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local manage_cb_done
|
||||||
|
client.connect_signal("manage", function (c)
|
||||||
|
manage_cb_done = true
|
||||||
|
assert(c.class == "XTerm", "Client should be xterm!")
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- Steps to do for this test.
|
||||||
|
local steps = {
|
||||||
|
-- Step 1: tag 2 should become urgent, when a client gets tagged via rules.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then -- Setup.
|
||||||
|
urgent_cb_done = false
|
||||||
|
-- Select first tag.
|
||||||
|
awful.tag.viewonly(tags[1][1])
|
||||||
|
|
||||||
|
runner.add_to_default_rules({ rule = { class = "XTerm" },
|
||||||
|
properties = { tag = tags[1][2], focus = true } })
|
||||||
|
|
||||||
|
awful.util.spawn("xterm")
|
||||||
|
end
|
||||||
|
if urgent_cb_done then
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent") == true)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent_count") == 1)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Step 2: when switching to tag 2, it should not be urgent anymore.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then
|
||||||
|
-- Setup: switch to tag.
|
||||||
|
os.execute('xdotool key super+2')
|
||||||
|
|
||||||
|
elseif awful.tag.selectedlist()[1] == tags[1][2] then
|
||||||
|
assert(#client.get() == 1)
|
||||||
|
c = client.get()[1]
|
||||||
|
assert(not c.urgent, "Client is not urgent anymore.")
|
||||||
|
assert(c == client.focus, "Client is focused.")
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent") == false)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent_count") == 0)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Step 3: tag 2 should not be urgent, but switched to.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then -- Setup.
|
||||||
|
local urgent_cb_done = false
|
||||||
|
|
||||||
|
-- Select first tag.
|
||||||
|
awful.tag.viewonly(tags[1][1])
|
||||||
|
|
||||||
|
runner.add_to_default_rules({ rule = { class = "XTerm" },
|
||||||
|
properties = { tag = tags[1][2], focus = true, switchtotag = true }})
|
||||||
|
|
||||||
|
awful.util.spawn("xterm")
|
||||||
|
|
||||||
|
elseif awful.tag.selectedlist()[1] == tags[1][2] then
|
||||||
|
assert(urgent_cb_done)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent") == false)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent_count") == 0)
|
||||||
|
assert(awful.tag.selectedlist()[2] == nil)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
|
||||||
|
-- Step 4: tag 2 should not become urgent, when a client gets tagged via
|
||||||
|
-- rules with focus=false.
|
||||||
|
function(count)
|
||||||
|
if count == 1 then -- Setup.
|
||||||
|
client.get()[1]:kill()
|
||||||
|
manage_cb_done = false
|
||||||
|
|
||||||
|
runner.add_to_default_rules({rule = { class = "XTerm" },
|
||||||
|
properties = { tag = tags[1][2], focus = false }})
|
||||||
|
|
||||||
|
awful.util.spawn("xterm")
|
||||||
|
end
|
||||||
|
if manage_cb_done then
|
||||||
|
assert(client.get()[1].urgent == false)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent") == false)
|
||||||
|
assert(awful.tag.getproperty(tags[1][2], "urgent_count") == 0)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
require("_runner").run_steps(steps)
|
Loading…
Reference in New Issue