[Tarantool-patches] [PATCH luajit 2/5] test: stop using utils.selfrun in tests
Igor Munkin
imun at tarantool.org
Mon Feb 27 12:07:20 MSK 2023
Unfortunately, <utils.selfrun> is too complex to be maintained, so the
corresponding tests are split into two files: the test itself and the
script to be run by the test. As a result of the patch <utils.makecmd>
helper is introduced: it inherits some approaches from <utils.selfrun>,
but it's considered for more general use.
Signed-off-by: Igor Munkin <imun at tarantool.org>
---
.../gh-4427-ffi-sandwich.test.lua | 88 +++++++++++--------
.../gh-4427-ffi-sandwich/script.lua | 25 ++++++
.../lj-351-print-tostring-number.test.lua | 34 +++----
.../lj-351-print-tostring-number/script.lua | 9 ++
.../lj-586-debug-non-string-error.test.lua | 2 +-
.../lj-flush-on-trace.test.lua | 87 ++++++++++--------
.../lj-flush-on-trace/script.lua | 23 +++++
test/tarantool-tests/utils.lua | 80 +++++++----------
8 files changed, 200 insertions(+), 148 deletions(-)
create mode 100644 test/tarantool-tests/gh-4427-ffi-sandwich/script.lua
create mode 100644 test/tarantool-tests/lj-351-print-tostring-number/script.lua
create mode 100644 test/tarantool-tests/lj-flush-on-trace/script.lua
diff --git a/test/tarantool-tests/gh-4427-ffi-sandwich.test.lua b/test/tarantool-tests/gh-4427-ffi-sandwich.test.lua
index dd02130c..06985dcd 100644
--- a/test/tarantool-tests/gh-4427-ffi-sandwich.test.lua
+++ b/test/tarantool-tests/gh-4427-ffi-sandwich.test.lua
@@ -3,52 +3,62 @@ local utils = require('utils')
-- Disabled on *BSD due to #4819.
utils.skipcond(jit.os == 'BSD', 'Disabled due to #4819')
-utils.selfrun(arg, {
- {
- arg = {
- 1, -- hotloop (arg[1])
- 1, -- trigger (arg[2])
- },
- msg = 'Trace is aborted',
- res = tostring(3), -- hotloop + trigger + 1
- test = 'is',
- },
- {
- arg = {
- 1, -- hotloop (arg[1])
- 2, -- trigger (arg[2])
- },
- msg = 'Trace is recorded',
- res = 'Lua VM re%-entrancy is detected while executing the trace',
- test = 'like',
- },
-})
-
------ Test payload. ----------------------------------------------
-
-local cfg = {
- hotloop = arg[1] or 1,
- trigger = arg[2] or 1,
-}
+local tap = require('tap')
-local ffi = require('ffi')
-local ffisandwich = ffi.load('libsandwich')
-ffi.cdef('int increment(struct sandwich *state, int i)')
+local test = tap.test('gh-4427-ffi-sandwich')
+test:plan(2)
--- Save the current coroutine and set the value to trigger
--- <increment> call the Lua routine instead of C implementation.
-local sandwich = require('libsandwich')(cfg.trigger)
+-- <makecmd> runs %testname%/script.lua by <LUAJIT_TEST_BINARY>
+-- with the given environment, launch options and CLI arguments.
+local script = utils.makecmd(arg, {
+ -- XXX: Apple tries their best to "protect their users from
+ -- malware". As a result SIP (see the link[1] below) has been
+ -- designed and released. Now, Apple developers are so
+ -- protected, that they can load nothing being not installed in
+ -- the system, since the environment is sanitized before the
+ -- child process is launched. In particular, environment
+ -- variables starting with DYLD_ and LD_ are unset for child
+ -- process. For more info, see the docs[2] below.
+ --
+ -- The environment variable below is used by FFI machinery to
+ -- find the proper shared library.
+ --
+ -- luacheck: push no max comment line length
+ --
+ -- [1]: https://support.apple.com/en-us/HT204899
+ -- [2]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html
+ --
+ -- luacheck: pop
+ env = { DYLD_LIBRARY_PATH = os.getenv('DYLD_LIBRARY_PATH') },
+ redirect = '2>&1',
+})
-- Depending on trigger and hotloop values the following contexts
-- are possible:
-- * if trigger <= hotloop -> trace recording is aborted
-- * if trigger > hotloop -> trace is recorded but execution
-- leads to panic
-jit.opt.start("3", string.format("hotloop=%d", cfg.hotloop))
+local hotloop = 1
+local cases = {
+ abort = {
+ trigger = hotloop,
+ expected = '#4427 still works',
+ test = 'is',
+ message = 'Trace is aborted',
+ },
+ panic = {
+ trigger = hotloop + 1,
+ expected = 'Lua VM re%-entrancy is detected while executing the trace',
+ test = 'like',
+ message = 'Trace is compiled',
+ },
+}
-local res
-for i = 0, cfg.trigger + cfg.hotloop do
- res = ffisandwich.increment(sandwich, i)
+for _, subtest in pairs(cases) do
+ local output = script(hotloop, subtest.trigger)
+ -- XXX: explicitly pass <test> as an argument to <testf>
+ -- to emulate test:is(...), test:like(...), etc.
+ test[subtest.test](test, output, subtest.expected, subtest.message)
end
--- Check the resulting value if panic didn't occur earlier.
-print(res)
+
+os.exit(test:check() and 0 or 1)
diff --git a/test/tarantool-tests/gh-4427-ffi-sandwich/script.lua b/test/tarantool-tests/gh-4427-ffi-sandwich/script.lua
new file mode 100644
index 00000000..9ecd964e
--- /dev/null
+++ b/test/tarantool-tests/gh-4427-ffi-sandwich/script.lua
@@ -0,0 +1,25 @@
+local hotloop = assert(arg[1], 'hotloop argument is missing')
+local trigger = assert(arg[2], 'trigger argument is missing')
+
+local ffi = require('ffi')
+local ffisandwich = ffi.load('libsandwich')
+ffi.cdef('int increment(struct sandwich *state, int i)')
+
+-- Save the current coroutine and set the value to trigger
+-- <increment> call the Lua routine instead of C implementation.
+local sandwich = require('libsandwich')(trigger)
+
+-- Depending on trigger and hotloop values the following contexts
+-- are possible:
+-- * if trigger <= hotloop -> trace recording is aborted
+-- * if trigger > hotloop -> trace is recorded but execution
+-- leads to panic
+jit.opt.start("3", string.format("hotloop=%d", hotloop))
+
+local res
+for i = 0, hotloop + trigger do
+ res = ffisandwich.increment(sandwich, i)
+end
+-- Check the resulting value if panic didn't occur earlier.
+assert(res == hotloop + trigger + 1, 'res is calculated correctly')
+io.write('#4427 still works')
diff --git a/test/tarantool-tests/lj-351-print-tostring-number.test.lua b/test/tarantool-tests/lj-351-print-tostring-number.test.lua
index da5b31be..72a9ec2b 100644
--- a/test/tarantool-tests/lj-351-print-tostring-number.test.lua
+++ b/test/tarantool-tests/lj-351-print-tostring-number.test.lua
@@ -1,4 +1,9 @@
-local utils = require('utils')
+local tap = require('tap')
+
+local test = tap.test('lj-351-print-tostring-number')
+test:plan(8)
+
+local script = require('utils').makecmd(arg)
local cases = {
{typename = 'nil', value = 'nil'},
@@ -15,27 +20,10 @@ local cases = {
{typename = 'cdata', value = '1ULL'}
}
-local checks = {}
-
-for i, case in pairs(cases) do
- checks[i] = {
- arg = {('"%s"'):format(case.value), case.typename},
- msg = ('%s'):format(case.typename),
- res = ('__tostring is reloaded for %s'):format(case.typename),
- test = 'is',
- }
+for _, subtest in pairs(cases) do
+ local output = script(('"%s"'):format(subtest.value), subtest.typename)
+ test:is(output, ('__tostring is reloaded for %s'):format(subtest.typename),
+ ('subtest is OK for %s type'):format(subtest.typename))
end
-utils.selfrun(arg, checks)
-
------ Test payload. ----------------------------------------------
-
-local test = [[
- local testvar = %s
- debug.setmetatable(testvar, {__tostring = function(o)
- return ('__tostring is reloaded for %s'):format(type(o))
- end})
- print(testvar)
-]]
-
-pcall(load(test:format(unpack(arg))))
+os.exit(test:check() and 0 or 1)
diff --git a/test/tarantool-tests/lj-351-print-tostring-number/script.lua b/test/tarantool-tests/lj-351-print-tostring-number/script.lua
new file mode 100644
index 00000000..c3066f49
--- /dev/null
+++ b/test/tarantool-tests/lj-351-print-tostring-number/script.lua
@@ -0,0 +1,9 @@
+local test = [[
+ local testvar = %s
+ debug.setmetatable(testvar, {__tostring = function(o)
+ return ('__tostring is reloaded for %s'):format(type(o))
+ end})
+ print(testvar)
+]]
+
+pcall(load(test:format(unpack(arg))))
diff --git a/test/tarantool-tests/lj-586-debug-non-string-error.test.lua b/test/tarantool-tests/lj-586-debug-non-string-error.test.lua
index f02353fe..dcb730a2 100644
--- a/test/tarantool-tests/lj-586-debug-non-string-error.test.lua
+++ b/test/tarantool-tests/lj-586-debug-non-string-error.test.lua
@@ -8,7 +8,7 @@ test:plan(1)
-- that testing the debug interactive interface always ends with
-- sending commands to another instance via stdin. However, the
-- module with test helpers lacks the suitable routine.
--- `utils.selfrun()` doesn't fit for this, since `debug.debug()`
+-- `utils.makecmd()` doesn't fit for this, since `debug.debug()`
-- captures `io.stdin` and waits at `fgets()` in debug busy loop.
-- As it's already mentioned, such tests are not usual, so there
-- is no need to introduce a new helper to utils module (at least
diff --git a/test/tarantool-tests/lj-flush-on-trace.test.lua b/test/tarantool-tests/lj-flush-on-trace.test.lua
index c46b93f0..3351cc5a 100644
--- a/test/tarantool-tests/lj-flush-on-trace.test.lua
+++ b/test/tarantool-tests/lj-flush-on-trace.test.lua
@@ -3,51 +3,62 @@ local utils = require('utils')
-- Disabled on *BSD due to #4819.
utils.skipcond(jit.os == 'BSD', 'Disabled due to #4819')
-utils.selfrun(arg, {
- {
- arg = {
- 1, -- hotloop (arg[1])
- 1, -- trigger (arg[2])
- },
- msg = 'Trace is aborted',
- res = 'OK',
- test = 'is',
- },
- {
- arg = {
- 1, -- hotloop (arg[1])
- 2, -- trigger (arg[2])
- },
- msg = 'Trace is recorded',
- res = 'JIT mode change is detected while executing the trace',
- test = 'like',
- },
-})
-
------ Test payload. ----------------------------------------------
-
-local cfg = {
- hotloop = arg[1] or 1,
- trigger = arg[2] or 1,
-}
+local tap = require('tap')
-local ffi = require('ffi')
-local ffiflush = ffi.load('libflush')
-ffi.cdef('void flush(struct flush *state, int i)')
+local test = tap.test('lj-flush-on-trace')
+test:plan(2)
--- Save the current coroutine and set the value to trigger
--- <flush> call the Lua routine instead of C implementation.
-local flush = require('libflush')(cfg.trigger)
+-- <makecmd> runs %testname%/script.lua by <LUAJIT_TEST_BINARY>
+-- with the given environment, launch options and CLI arguments.
+local script = utils.makecmd(arg, {
+ -- XXX: Apple tries their best to "protect their users from
+ -- malware". As a result SIP (see the link[1] below) has been
+ -- designed and released. Now, Apple developers are so
+ -- protected, that they can load nothing being not installed in
+ -- the system, since the environment is sanitized before the
+ -- child process is launched. In particular, environment
+ -- variables starting with DYLD_ and LD_ are unset for child
+ -- process. For more info, see the docs[2] below.
+ --
+ -- The environment variable below is used by FFI machinery to
+ -- find the proper shared library.
+ --
+ -- luacheck: push no max comment line length
+ --
+ -- [1]: https://support.apple.com/en-us/HT204899
+ -- [2]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/RuntimeProtections/RuntimeProtections.html
+ --
+ -- luacheck: pop
+ env = { DYLD_LIBRARY_PATH = os.getenv('DYLD_LIBRARY_PATH') },
+ redirect = '2>&1',
+})
-- Depending on trigger and hotloop values the following contexts
-- are possible:
-- * if trigger <= hotloop -> trace recording is aborted
-- * if trigger > hotloop -> trace is recorded but execution
-- leads to panic
-jit.opt.start("3", string.format("hotloop=%d", cfg.hotloop))
+local hotloop = 1
+local cases = {
+ abort = {
+ trigger = hotloop,
+ expected = 'LJ flush still works',
+ test = 'is',
+ message = 'Trace is aborted',
+ },
+ panic = {
+ trigger = hotloop + 1,
+ expected = 'JIT mode change is detected while executing the trace',
+ test = 'like',
+ message = 'Trace is compiled',
+ },
+}
-for i = 0, cfg.trigger + cfg.hotloop do
- ffiflush.flush(flush, i)
+for _, subtest in pairs(cases) do
+ local output = script(hotloop, subtest.trigger)
+ -- XXX: explicitly pass <test> as an argument to <testf>
+ -- to emulate test:is(...), test:like(...), etc.
+ test[subtest.test](test, output, subtest.expected, subtest.message)
end
--- Panic didn't occur earlier.
-print('OK')
+
+os.exit(test:check() and 0 or 1)
diff --git a/test/tarantool-tests/lj-flush-on-trace/script.lua b/test/tarantool-tests/lj-flush-on-trace/script.lua
new file mode 100644
index 00000000..d2c35534
--- /dev/null
+++ b/test/tarantool-tests/lj-flush-on-trace/script.lua
@@ -0,0 +1,23 @@
+local hotloop = assert(arg[1], 'hotloop argument is missing')
+local trigger = assert(arg[2], 'trigger argument is missing')
+
+local ffi = require('ffi')
+local ffiflush = ffi.load('libflush')
+ffi.cdef('void flush(struct flush *state, int i)')
+
+-- Save the current coroutine and set the value to trigger
+-- <flush> call the Lua routine instead of C implementation.
+local flush = require('libflush')(trigger)
+
+-- Depending on trigger and hotloop values the following contexts
+-- are possible:
+-- * if trigger <= hotloop -> trace recording is aborted
+-- * if trigger > hotloop -> trace is recorded but execution
+-- leads to panic
+jit.opt.start("3", string.format("hotloop=%d", hotloop))
+
+for i = 0, trigger + hotloop do
+ ffiflush.flush(flush, i)
+end
+-- Panic didn't occur earlier.
+io.write('LJ flush still works')
diff --git a/test/tarantool-tests/utils.lua b/test/tarantool-tests/utils.lua
index eb11d40d..8355149b 100644
--- a/test/tarantool-tests/utils.lua
+++ b/test/tarantool-tests/utils.lua
@@ -1,7 +1,6 @@
local M = {}
local ffi = require('ffi')
-local tap = require('tap')
local bc = require('jit.bc')
local bit = require('bit')
@@ -44,55 +43,42 @@ function M.luacmd(args)
return table.concat(args, ' ', idx + 1, -1)
end
-local function unshiftenv(variable, value, sep)
- local envvar = os.getenv(variable)
- return ('%s="%s%s"'):format(variable, value,
- envvar and ('%s%s'):format(sep, envvar) or '')
+local function makeenv(tabenv)
+ if tabenv == nil then return '' end
+ local flatenv = {}
+ for var, value in pairs(tabenv) do
+ table.insert(flatenv, ('%s=%s'):format(var, value))
+ end
+ return table.concat(flatenv, ' ')
end
-function M.selfrun(arg, checks)
- -- If TEST_SELFRUN is set, it means the test has been run via
- -- <io.popen>, so just return from this routine and proceed
- -- the execution to the test payload, ...
- if os.getenv('TEST_SELFRUN') then return end
-
- -- ... otherwise initialize <tap>, setup testing environment
- -- and run this chunk via <io.popen> for each case in <checks>.
- -- XXX: The function doesn't return back from this moment. It
- -- checks whether all assertions are fine and exits.
-
- local test = tap.test(arg[0]:match('/?(.+)%.test%.lua'))
-
- test:plan(#checks)
-
- local libext = package.cpath:match('?.(%a+);')
- local vars = {
+-- <makecmd> creates a command that runs %testname%/script.lua by
+-- <LUAJIT_TEST_BINARY> with the given environment, launch options
+-- and CLI arguments. The function yields an object (i.e. table)
+-- with the aforementioned parameters. To launch the command just
+-- call the object.
+function M.makecmd(arg, opts)
+ return setmetatable({
LUABIN = M.luacmd(arg),
- SCRIPT = arg[0],
- PATH = arg[0]:gsub('%.test%.lua', ''),
- SUFFIX = libext,
- ENV = table.concat({
- unshiftenv('LUA_PATH', '<PATH>/?.lua', ';'),
- unshiftenv('LUA_CPATH', '<PATH>/?.<SUFFIX>', ';'),
- unshiftenv((libext == 'dylib' and 'DYLD' or 'LD') .. '_LIBRARY_PATH',
- '<PATH>', ':'),
- 'TEST_SELFRUN=1',
- }, ' '),
- }
-
- local cmd = string.gsub('<ENV> <LUABIN> 2>&1 <SCRIPT>', '%<(%w+)>', vars)
-
- for _, ch in pairs(checks) do
- local testf = test[ch.test]
- assert(testf, ("tap doesn't provide test.%s function"):format(ch.test))
- local proc = io.popen((cmd .. (' %s'):rep(#ch.arg)):format(unpack(ch.arg)))
- local res = proc:read('*all'):gsub('^%s+', ''):gsub('%s+$', '')
- -- XXX: explicitly pass <test> as an argument to <testf>
- -- to emulate test:is(...), test:like(...), etc.
- testf(test, res, ch.res, ch.msg)
- end
-
- os.exit(test:check() and 0 or 1)
+ SCRIPT = opts and opts.script or arg[0]:gsub('%.test%.lua$', '/script.lua'),
+ ENV = opts and makeenv(opts.env) or '',
+ REDIRECT = opts and opts.redirect or '',
+ }, {
+ __call = function(self, ...)
+ -- This line just makes the command for <io.popen> by the
+ -- following steps:
+ -- 1. Replace the placeholders with the corresponding values
+ -- given to the command constructor (e.g. script, env)
+ -- 2. Join all CLI arguments given to the __call metamethod
+ -- 3. Concatenate the results of step 1 and step 2 to obtain
+ -- the resulting command.
+ local cmd = ('<ENV> <LUABIN> <REDIRECT> <SCRIPT>'):gsub('%<(%w+)>', self)
+ .. (' %s'):rep(select('#', ...)):format(...)
+ -- Trim both leading and trailing whitespace from the output
+ -- produced by the child process.
+ return io.popen(cmd):read('*all'):gsub('^%s+', ''):gsub('%s+$', '')
+ end
+ })
end
function M.skipcond(condition, message)
--
2.30.2
More information about the Tarantool-patches
mailing list