Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate treegen module and adapt it #371

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Add `cbuilder` helper as a declarative configuration builder (gh-366).
- Make `assert_error_*` additionally check error trace if required.
- Add `--list-test-cases` and `--run-test-case` CLI options.
- Introduce preloaded hooks (gh-380).

## 1.0.1

Expand Down
42 changes: 42 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,48 @@ To change default order use:
local t = require('luatest')
t.configure({shuffle = 'group'})

---------------------------------
Preloaded hooks
---------------------------------
Preloaded hooks extend base hooks. They behave like the pytest fixture with the ``autouse`` parameter.

.. code-block:: lua
-- my_helper.lua
local hooks = require('luatest.hooks')

hooks.before_all_preloaded(function() print('start foo') end)
ylobankov marked this conversation as resolved.
Show resolved Hide resolved
hooks.after_all_preloaded(function() print('stop foo') end)

hooks.before_each_preloaded(function() print('start bar') end)
hooks.after_each_preloaded(function() print('stop bar') end)

hooks.before_all_preloaded(function() print('start baz') end)
hooks.after_all_preloaded(function() print('stop baz') end)

If you run the following test:

.. code-block:: lua
local t = require('luatest')
local my_helper = require('my_helper')
local g = t.group()

g.before_all(function() print('prepare') end)
g.after_all(function() print('cleanup') end)

g.test_print = function() print('everythings is ok') end

Then the hooks are executed in the following sequence:

.. code-block:: text
|\ start foo
| \ start baz
| \ prepare
| \ start bar
| test_print (everythings is ok)
| / stop bar
| / cleanup
| / stop baz
|/ stop foo

---------------------------------
List of luatest functions
Expand Down
3 changes: 2 additions & 1 deletion config.ld
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ file = {
'luatest/server.lua',
'luatest/replica_set.lua',
'luatest/justrun.lua',
'luatest/cbuilder.lua'
'luatest/cbuilder.lua',
'luatest/hooks.lua'
}
topics = {
'CHANGELOG.md',
Expand Down
2 changes: 1 addition & 1 deletion luatest/group.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function Group.mt:initialize(name)
error('Group name must not contain `/`: ' .. name)
end
self.name = name
hooks.define_group_hooks(self)
hooks._define_group_hooks(self)
end

return Group
131 changes: 121 additions & 10 deletions luatest/hooks.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,88 @@
--- Provide extra methods for hooks.
--
-- Preloaded hooks extend base hooks.
-- They behave like the pytest fixture with the `autouse` parameter.
--
-- @usage
--
-- local hooks = require('luatest.hooks')
--
-- hooks.before_suite_preloaded(...)
-- hooks.after_suite_preloaded(...)
--
-- hooks.before_all_preloaded(...)
-- hooks.after_all_preloaded(...)
--
-- hooks.before_each_preloaded(...)
-- hooks.after_each_preloaded(...)
--
-- @module luatest.hooks

local log = require('luatest.log')
local utils = require('luatest.utils')
local comparator = require('luatest.comparator')

local export = {}

local preloaded_hooks = {
before_suite = {},
after_suite = {},

before_all = {},
after_all = {},

before_each = {},
after_each = {}
}

--- Register preloaded before hook in the `suite` scope.
-- It will be done before the classic before_suite() hook in the tests.
--
-- @func fn The function where you will be preparing for the test.
function export.before_suite_preloaded(fn)
Totktonada marked this conversation as resolved.
Show resolved Hide resolved
table.insert(preloaded_hooks.before_suite, {fn, {}})
end

--- Register preloaded after hook in the `suite` scope.
-- It will be done after the classic after_suite() hook in the tests.
--
-- @func fn The function where you will be cleaning up for the test.
function export.after_suite_preloaded(fn)
table.insert(preloaded_hooks.after_suite, {fn, {}})
end

--- Register preloaded before hook in the `all` scope.
-- It will be done before the classic before_all() hook in the tests.
--
-- @func fn The function where you will be preparing for the test.
function export.before_all_preloaded(fn)
table.insert(preloaded_hooks.before_all, {fn, {}})
end

--- Register preloaded after hook in the `all` scope.
-- It will be done after the classic after_all() hook in the tests.
--
-- @func fn The function where you will be cleaning up for the test.
function export.after_all_preloaded(fn)
table.insert(preloaded_hooks.after_all, {fn, {}})
end

--- Register preloaded before hook in the `each` scope.
-- It will be done before the classic before_each() hook in the tests.
--
-- @func fn The function where you will be preparing for the test.
function export.before_each_preloaded(fn)
table.insert(preloaded_hooks.before_each, {fn, {}})
end

--- Register preloaded after hook in the `each` scope.
-- It will be done after the classic after_each() hook in the tests.
--
-- @func fn The function where you will be cleaning up for the test.
function export.after_each_preloaded(fn)
table.insert(preloaded_hooks.after_each, {fn, {}})
end

local function check_params(required, actual)
for param_name, param_val in pairs(required) do
if not comparator.equals(param_val, actual[param_name]) then
Expand All @@ -14,7 +93,7 @@ local function check_params(required, actual)
return true
end

local function define_hooks(object, hooks_type)
local function define_hooks(object, hooks_type, preloaded_hook)
local hooks = {}
object[hooks_type .. '_hooks'] = hooks

Expand All @@ -35,13 +114,45 @@ local function define_hooks(object, hooks_type)
end
object['_original_' .. hooks_type] = object[hooks_type] -- for leagacy hooks support

local function run_preloaded_hooks()
if preloaded_hook == nil then
return
end

-- before_* -- direct order
-- after_* -- reverse order
local from = 1
local to = #preloaded_hook
local step = 1
if hooks_type:startswith('after_') then
from, to = to, from
step = -step
end

for i = from, to, step do
local hook = preloaded_hook[i]
if check_params(hook[2], object.params) then
hook[1](object)
end
end
end

object['run_' .. hooks_type] = function()
-- before_* -- run before test hooks
if hooks_type:startswith('before_') then
run_preloaded_hooks()
end

local active_hooks = object[hooks_type .. '_hooks']
for _, hook in ipairs(active_hooks) do
if check_params(hook[2], object.params) then
hook[1](object)
end
end
-- after_* -- run after test hooks
if hooks_type:startswith('after_') then
run_preloaded_hooks()
end
end
end

Expand Down Expand Up @@ -97,21 +208,21 @@ local function define_named_hooks(object, hooks_type)
end

-- Define hooks on group.
function export.define_group_hooks(group)
define_hooks(group, 'before_each')
define_hooks(group, 'after_each')
define_hooks(group, 'before_all')
define_hooks(group, 'after_all')
function export._define_group_hooks(group)
define_hooks(group, 'before_each', preloaded_hooks.before_each)
define_hooks(group, 'after_each', preloaded_hooks.after_each)
define_hooks(group, 'before_all', preloaded_hooks.before_all)
define_hooks(group, 'after_all', preloaded_hooks.after_all)

define_named_hooks(group, 'before_test')
define_named_hooks(group, 'after_test')
return group
end

-- Define suite hooks on luatest.
function export.define_suite_hooks(luatest)
define_hooks(luatest, 'before_suite')
define_hooks(luatest, 'after_suite')
function export._define_suite_hooks(luatest)
define_hooks(luatest, 'before_suite', preloaded_hooks.before_suite)
define_hooks(luatest, 'after_suite', preloaded_hooks.after_suite)
end

local function run_group_hooks(runner, group, hooks_type)
Expand Down Expand Up @@ -153,7 +264,7 @@ local function run_named_test_hooks(self, test, hooks_type)
end
end

function export.patch_runner(Runner)
function export._patch_runner(Runner)
-- Last run test to set error for when group.after_all hook fails.
local last_test = nil

Expand Down
7 changes: 6 additions & 1 deletion luatest/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ luatest.cbuilder = require('luatest.cbuilder')
--
-- @function after_suite
-- @func fn
hooks.define_suite_hooks(luatest)
hooks._define_suite_hooks(luatest)

--- Add extra hooks methods.
--
-- @see luatest.hooks
luatest.hooks = hooks

luatest.groups = {}

Expand Down
2 changes: 1 addition & 1 deletion luatest/runner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ function Runner.mt:all_test_names()
return result
end

hooks.patch_runner(Runner)
hooks._patch_runner(Runner)
capturing(Runner)

return Runner
67 changes: 67 additions & 0 deletions test/hooks_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,73 @@ g.test_hooks = function()
t.assert_equals(hooks, expected)
end

g.test_predefined_hooks = function()
local _hooks = require('luatest.hooks')
local hooks = {}

_hooks.before_suite_preloaded(function() table.insert(hooks, 'before_suite') end)
_hooks.after_suite_preloaded(function() table.insert(hooks, 'after_suite') end)
_hooks.before_suite_preloaded(function() table.insert(hooks, 'before_suite2') end)
_hooks.after_suite_preloaded(function() table.insert(hooks, 'after_suite2') end)

_hooks.before_all_preloaded(function() table.insert(hooks, 'before_all') end)
_hooks.after_all_preloaded(function() table.insert(hooks, 'after_all') end)
_hooks.before_all_preloaded(function() table.insert(hooks, 'before_all2') end)
_hooks.after_all_preloaded(function() table.insert(hooks, 'after_all2') end)

_hooks.before_each_preloaded(function() table.insert(hooks, 'before_each') end)
_hooks.after_each_preloaded(function() table.insert(hooks, 'after_each') end)
_hooks.before_each_preloaded(function() table.insert(hooks, 'before_each2') end)
_hooks.after_each_preloaded(function() table.insert(hooks, 'after_each2') end)

_hooks.before_suite_preloaded(function() table.insert(hooks, 'before_suite3') end)
_hooks.before_all_preloaded(function() table.insert(hooks, 'before_all3') end)
_hooks.before_all_preloaded(function() table.insert(hooks, 'before_all4') end)
_hooks.after_suite_preloaded(function() table.insert(hooks, 'after_suite3') end)
_hooks.after_all_preloaded(function() table.insert(hooks, 'after_all3') end)
_hooks.after_all_preloaded(function() table.insert(hooks, 'after_all4') end)

local result = helper.run_suite(function(lu2)
local t2 = lu2.group('test')
t2.before_all(function() table.insert(hooks, 'before_all_inner') end)
lu2.before_suite(function() table.insert(hooks, 'before_suite_inner') end)
lu2.after_suite(function() table.insert(hooks, 'after_suite_inner') end)
t2.after_all(function() table.insert(hooks, 'after_all_inner') end)
t2.before_each(function() table.insert(hooks, 'before_each_inner') end)
t2.after_each(function() table.insert(hooks, 'after_each_inner') end)
t2.test = function() table.insert(hooks, 'test') end
end)

t.assert_equals(result, 0)
t.assert_equals(hooks, {
"before_suite",
"before_suite2",
"before_suite3",
"before_suite_inner",
"before_all",
"before_all2",
"before_all3",
"before_all4",
"before_all_inner",
"before_each",
"before_each2",
"before_each_inner",
"test",
"after_each_inner",
"after_each2",
"after_each",
"after_all_inner",
"after_all4",
"after_all3",
"after_all2",
"after_all",
"after_suite_inner",
"after_suite3",
"after_suite2",
"after_suite",
})
end

g.test_hooks_legacy = function()
local hooks = {}
local expected = {}
Expand Down