Skip to content

Commit

Permalink
Migrate treegen module and adapt it
Browse files Browse the repository at this point in the history
The original `treegen` module (path: tarantool/test/treegen.lua) has
been moved to the current project with the following changes:
    - refactoring the public functions variables;
    - updated documentation.

Part of #364
  • Loading branch information
Oleg Chaplashkin committed Apr 17, 2024
1 parent d985997 commit bc05810
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Improve `luatest.log` function if a `nil` value is passed (gh-360).
- Added `assert_error_covers`.
- Add more logs (gh-326).
- Add `treegen` helper as a tree generator (gh-364).

## 1.0.1

Expand Down
4 changes: 4 additions & 0 deletions luatest/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ hooks.define_suite_hooks(luatest)

luatest.groups = {}

--- Working tree generator.
--
luatest.treegen = require('luatest.treegen')

--- Create group of tests.
--
-- @string[opt] name
Expand Down
197 changes: 197 additions & 0 deletions luatest/treegen.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
-- Working tree generator.
--
-- Generates a tree of Lua files using provided templates and
-- filenames.
--
-- Basic usage:
--
-- | local t = require('luatest')
-- | local treegen = require('test.treegen')
-- |
-- | local g = t.group()
-- |
-- | local SCRIPT_TEMPLATE = [[
-- | <...>
-- | ]]
-- |
-- | g.before_all(function(g)
-- | treegen.init(g)
-- | treegen.add_template(g, '^.*$', SCRIPT_TEMPLATE)
-- | end)
-- |
-- | g.after_all(function(g)
-- | treegen.clean(g)
-- | end)
-- |
-- | g.foobar_test = function(g)
-- | local dir = treegen.prepare_directory(g,
-- | {'foo/bar.lua', 'main.lua'})
-- | <..test case..>
-- | end

local fio = require('fio')
local fun = require('fun')

local log = require('luatest.log')

local treegen = {}

local function find_template(group, script)
for _, template_def in ipairs(group.templates) do
if script:match(template_def.pattern) then
return template_def.template
end
end
error(("treegen: can't find a template for script %q"):format(script))
end

-- Write provided script into the given directory.
--
-- @string directory Directory where the script will be created.
-- @string filename File to write (possible nested path: /foo/bar/main.lua).
-- @string script The body of the script to write.
-- @return string
function treegen.write_script(directory, filename, script)
local script_abspath = fio.pathjoin(directory, filename)
local flags = {'O_CREAT', 'O_WRONLY', 'O_TRUNC'}
local mode = tonumber('644', 8)

local scriptdir_abspath = fio.dirname(script_abspath)
log.info('Creating a directory: %s', scriptdir_abspath)
fio.mktree(scriptdir_abspath)

log.info('Writing a script: %s', script_abspath)
local fh = fio.open(script_abspath, flags, mode)
fh:write(script)
fh:close()
return script_abspath
end

-- Generate a script that follows a template and write it at the
-- given path in the given directory.
--
-- @table group Group of tests.
-- @string directory Directory where the script will be created.
-- @string filename File to write (possible nested path: /foo/bar/main.lua).
-- @table replacements List of replacement templates.
-- @return string
local function gen_script(group, directory, filename, replacements)
local template = find_template(group, filename)
replacements = fun.chain({filename = filename}, replacements):tomap()
local body = template:gsub('<(.-)>', replacements)
return treegen.write_script(directory, filename, body)
end

-- Initialize treegen module in the given group of tests.
--
-- @table group Group of tests.
function treegen.init(group)
group.tempdirs = {}
group.templates = {}
end

-- Remove all temporary directories created by the test
-- unless KEEP_DATA environment variable is set to a
-- non-empty value.
--
-- @table group Group of tests.
function treegen.clean(group)
local dirs = table.copy(group.tempdirs) or {}
group.tempdirs = nil

local keep_data = (os.getenv('KEEP_DATA') or '') ~= ''

for _, dir in ipairs(dirs) do
if keep_data then
log.info('Left intact due to KEEP_DATA env var: %s', dir)
else
log.info('Recursively removing: %s', dir)
fio.rmtree(dir)
end
end

group.templates = nil
end

-- Save the template in the given group of test with the given pattern.
--
-- @table group Group of tests.
-- @string pattern File name template
-- @string template A content template for creating a file.
function treegen.add_template(group, pattern, template)
table.insert(group.templates, {
pattern = pattern,
template = template,
})
end

-- Create a temporary directory with given scripts.
--
-- The scripts are generated using templates added by
-- treegen.add_template().
--
-- Example for {'foo/bar.lua', 'baz.lua'}:
--
-- /
-- + tmp/
-- + rfbWOJ/
-- + foo/
-- | + bar.lua
-- + baz.lua
--
-- The return value is '/tmp/rfbWOJ' for this example.
--
-- @table group Group of tests.
-- @table scripts List of bodies of the script to write.
-- @table replacements List of replacement templates.
-- @return string
function treegen.prepare_directory(group, scripts, replacements)
replacements = replacements or {}

assert(type(scripts) == 'table')
assert(type(replacements) == 'table')

local dir = fio.tempdir()

-- fio.tempdir() follows the TMPDIR environment variable.
-- If it ends with a slash, the return value contains a double
-- slash in the middle: for example, if TMPDIR=/tmp/, the
-- result is like `/tmp//rfbWOJ`.
--
-- It looks harmless on the first glance, but this directory
-- path may be used later to form an URI for a Unix domain
-- socket. As result the URI looks like
-- `unix/:/tmp//rfbWOJ/instance-001.iproto`.
--
-- It confuses net_box.connect(): it reports EAI_NONAME error
-- from getaddrinfo().
--
-- It seems, the reason is a peculiar of the URI parsing:
--
-- tarantool> uri.parse('unix/:/foo/bar.iproto')
-- ---
-- - host: unix/
-- service: /foo/bar.iproto
-- unix: /foo/bar.iproto
-- ...
--
-- tarantool> uri.parse('unix/:/foo//bar.iproto')
-- ---
-- - host: unix
-- path: /foo//bar.iproto
-- ...
--
-- Let's normalize the path using fio.abspath(), which
-- eliminates the double slashes.
dir = fio.abspath(dir)

table.insert(group.tempdirs, dir)

for _, script in ipairs(scripts) do
gen_script(group, dir, script, replacements)
end

return dir
end

return treegen

0 comments on commit bc05810

Please sign in to comment.