1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 |
#!/usr/bin/env luajit
--- Main test runner.
--
-- @script run_test
-- @copyright 2017 Aidan Holm <aidanholm@gmail.com>
-- Add ./tests to package.path
package.path = package.path .. ';./tests/?.lua'
package.path = package.path .. ';./lib/?.lua;./lib/?/init.lua'
local shared_lib = {}
local test = require "tests.lib"
local priv = require "tests.priv"
local util = require "tests.util"
test.init(shared_lib)
local lfs = require "lfs"
local lousy = { util = require "lousy.util" }
local orig_print = print
local xvfb_display
local current_test_file
local current_test_name
local prev_test_name
local have_test_failures = false
-- Wrap print()
local function log_test_output(...)
local msg = table.concat({...}, "\t")
prev_test_name = nil
local indent = " "
orig_print(indent .. msg:gsub("\n", "\n" .. indent))
end
local function update_test_status(status, test_name, test_file)
assert(type(status) == "string")
local esc = string.char(27)
local c_red = esc .. "[0;31m"
local c_green = esc .. "[0;32m"
local c_grey = esc .. "[0;37m"
local c_reset = esc .. "[0;0m"
local status_color = ({
pass = c_green,
fail = c_red,
wait = c_grey,
cont = c_grey,
run = c_grey,
load = c_grey,
})[status] or ""
-- Beginning a new test file
if status == "load" then
current_test_file = test_file:match("tests/(.*)%.lua")
current_test_name = ""
end
if status == "run" then
status = "run "
current_test_name = test_name
end
if status == "fail" then
have_test_failures = true
end
-- Overwrite the previous status line if it's for the same test
-- Or if the previous test was "" (a test file load)
if prev_test_name == current_test_name
or prev_test_name == "" then
io.write(esc .. "[1A" .. esc .. "[K")
end
prev_test_name = current_test_name
local line = current_test_file .. " / " .. current_test_name
orig_print(status_color .. status:upper() .. c_reset .. " " .. line)
end
local function do_style_tests(test_files)
print = log_test_output -- luacheck: ignore
for _, test_file in ipairs(test_files) do
-- Load test table
update_test_status("load", "", test_file)
local T, err = priv.load_test_file(test_file)
if not T then
update_test_status("fail")
log_test_output(err)
break
end
for test_name, func in pairs(T) do
assert(type(test_name) == "string")
assert(type(func) == "function")
update_test_status("run", test_name, test_file)
local ok, ret = pcall(func)
update_test_status(ok and "pass" or "fail")
if not ok and ret then
log_test_output(ret)
end
end
end
print = orig_print -- luacheck: ignore
end
local luakit_tmp_dirs = {}
local function spawn_luakit_instance(config, ...)
-- Create a temporary directory, hopefully on a ramdisk
local dir = util.make_tmp_dir("luakit_test_XXXXXX")
table.insert(luakit_tmp_dirs, dir)
-- Cheap version of a chroot that doesn't require special permissions
local env = {
HOME = dir,
XDG_CACHE_HOME = dir .. "/cache",
XDG_DATA_HOME = dir .. "/data",
XDG_CONFIG_HOME = dir .. "/config",
XDG_RUNTIME_DIR = dir .. "/runtime",
XDG_CONFIG_DIRS = "",
DISPLAY = xvfb_display
}
-- env -i clears everything, so pass the Lua module paths back through
-- when they are set. Without this the suite cannot run with luassert
-- installed outside the system prefix.
for _, var in ipairs({ "LUA_PATH", "LUA_CPATH", "LD_LIBRARY_PATH" }) do
local val = util.getenv(var)
if val and val ~= "" then env[var] = "'" .. val .. "'" end
end
-- HACK: make GStreamer shut up about not finding random .so files
-- when it rebuilds its registry, which it does with every single
-- luakit instance spawned this way
local cache_dir = util.getenv("XDG_CACHE_HOME") or (util.getenv("HOME") .. "/")
local gst_dir = cache_dir .. "/gstreamer-1.0"
if lfs.attributes(gst_dir, "mode") == "directory" then
os.execute(string.format("mkdir -p %q", env.XDG_CACHE_HOME .. "/gstreamer-1.0/"))
os.execute(string.format("cp %q %q", gst_dir.."/registry.x86_64.bin", env.XDG_CACHE_HOME .. "/gstreamer-1.0"))
end
-- Build env prefix
local cmd = "env -i - "
for k, v in pairs(env) do
cmd = cmd .. k .."=" .. v .. " "
end
cmd = cmd .. "./skull -U --log=error -c " .. config .. " " .. table.concat({...}, " ") .. " 2>&1"
return assert(io.popen(cmd))
end
-- On exit stuff
local exit_handlers = {}
local cleanup = function ()
for _, f in ipairs(exit_handlers) do f() end
exit_handlers = {}
end
-- Run automatically
local onexit_prx = newproxy(true)
getmetatable(onexit_prx).__gc = cleanup
-- Automatically clean up test directories
table.insert(exit_handlers, function ()
print("Removing temporary directories")
for _, dir in ipairs(luakit_tmp_dirs) do
os.execute(string.format("rm -r %q", dir))
end
end)
local function do_async_tests(test_files)
for _, test_file in ipairs(test_files) do
local f = spawn_luakit_instance("tests/async/run_test.lua", test_file)
local status, test_name
for line in f:lines() do
status, test_name = line:match("^__(%a+)__ (.*)$")
if status and test_name then
update_test_status(status, test_name, test_file)
else
log_test_output(line)
end
end
f:close()
end
end
-- Check for luassert
if not pcall(require, "luassert") then
print("Running tests requires installing luassert")
os.exit(1)
end
-- Check for untracked files in Git
local git=io.open(".git","r")
if git~=nil then
io.close(git)
do
local untracked = {}
local f = io.popen("git ls-files --others --exclude-standard")
for line in f:lines() do
table.insert(untracked, line)
end
f:close()
if #untracked > 0 then
local c_yellow = string.char(27) .. "[0;33m"
local c_reset = string.char(27) .. "[0;0m"
print(c_yellow .. "WARN" .. c_reset .. " The following files are untracked:")
for _, line in ipairs(untracked) do
print(" " .. line)
end
end
end
end
-- Reuse an existing display when asked to. Xvfb wants /tmp/.X11-unix with
-- its own owner and mode, and an xkbcomp in /usr/bin. Not every environment
-- has either (WSLg, containers), and in those an X server is already up.
local reuse_display = os.getenv("SKULL_TEST_DISPLAY")
-- Find a free server number
-- Does have a race condition...
for i=0,math.huge do
local flat_lock = lfs.attributes(("/tmp/.X%d-lock"):format(i))
local nest_lock = lfs.attributes(("/tmp/.X11-unix/X%d"):format(i))
if not (flat_lock or nest_lock) then
xvfb_display = ":" .. tostring(i)
break
end
end
-- Launch Xvfb for lifetime of test runner
if reuse_display and reuse_display ~= "" then
xvfb_display = reuse_display
print("Using display " .. xvfb_display)
else
print("Starting Xvfb")
local pid_xvfb = assert(util.spawn_async({"Xvfb", xvfb_display, "-screen", "0", "800x600x8"}))
table.insert(exit_handlers, function ()
print("Stopping Xvfb")
util.kill(pid_xvfb)
end)
end
-- Find test files
local test_file_pat = "/test_%S+%.lua$"
local test_files = {
style = test.find_files("tests/style/", test_file_pat),
async = test.find_files("tests/async/", test_file_pat),
}
-- Filter test files to arguments
local include_patterns = arg
if #arg > 0 then
for k, v in pairs(test_files) do
test_files[k] = lousy.util.table.filter_array(v, function (_, file)
for _, pat in ipairs(include_patterns) do
if file:match(pat) then return true end
end
return false
end)
end
end
local ok, err = pcall(function ()
do_style_tests(test_files.style)
do_async_tests(test_files.async)
end)
if not ok then print("\n" .. err) end
cleanup()
os.exit(have_test_failures and 1 or 0)
-- vim: et:sw=4:ts=8:sts=4:tw=80
|