{"id":20564395,"url":"https://github.com/tarantool/luatest","last_synced_at":"2026-04-23T14:01:48.478Z","repository":{"id":36270383,"uuid":"189012294","full_name":"tarantool/luatest","owner":"tarantool","description":"Tarantool test framework written in Lua","archived":false,"fork":false,"pushed_at":"2024-12-20T12:16:06.000Z","size":482,"stargazers_count":39,"open_issues_count":66,"forks_count":11,"subscribers_count":28,"default_branch":"master","last_synced_at":"2024-12-22T18:05:10.587Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.tarantool.io/en/doc/latest/reference/reference_rock/luatest/luatest_overview/","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tarantool.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-28T11:08:40.000Z","updated_at":"2024-12-20T12:16:11.000Z","dependencies_parsed_at":"2023-02-17T23:01:16.542Z","dependency_job_id":"243f05eb-9ff2-47cb-9c06-dd9c68f6812c","html_url":"https://github.com/tarantool/luatest","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fluatest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fluatest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fluatest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fluatest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tarantool","download_url":"https://codeload.github.com/tarantool/luatest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248904639,"owners_count":21180835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T04:26:08.377Z","updated_at":"2026-04-23T14:01:48.471Z","avatar_url":"https://github.com/tarantool.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"-------------------------------\nOverview\n-------------------------------\n\nTool for testing tarantool applications.\n\nHighlights:\n\n- executable to run tests in directory or specific files,\n- before/after suite hooks,\n- before/after test group hooks,\n- `output capturing \u003cCapturing output_\u003e`_,\n- `helpers \u003cTest helpers_\u003e`_ for testing tarantool applications,\n- `luacov integration \u003cluacov integration_\u003e`_.\n\n---------------------------------\nRequirements\n---------------------------------\n\n- Tarantool (it requires tarantool-specific ``fio`` module and ``ffi`` from LuaJIT).\n\n---------------------------------\nInstallation\n---------------------------------\n\n.. code-block:: bash\n\n    tt rocks install luatest\n    .rocks/bin/luatest --help # list available options\n\n---------------------------------\nUsage\n---------------------------------\n\nDefine tests.\n\n.. code-block:: Lua\n\n    -- test/feature_test.lua\n    local t = require('luatest')\n    local g = t.group('feature')\n    -- Default name is inferred from caller filename when possible.\n    -- For `test/a/b/c_d_test.lua` it will be `a.b.c_d`.\n    -- So `local g = t.group()` works the same way.\n\n    -- Tests. All properties with name staring with `test` are treated as test cases.\n    g.test_example_1 = function() ... end\n    g.test_example_n = function() ... end\n\n    -- Define suite hooks\n    t.before_suite(function() ... end)\n    t.before_suite(function() ... end)\n\n    -- Hooks to run once for tests group\n    g.before_all(function() ... end)\n    g.after_all(function() ... end)\n\n    -- Hooks to run for each test in group\n    g.before_each(function() ... end)\n    g.after_each(function() ... end)\n\n    -- Hooks to run for a specified test in group\n    g.before_test('test_example_1', function() ... end)\n    g.after_test('test_example_2', function() ... end)\n    -- before_test runs after before_each\n    -- after_test runs before after_each\n\n    -- test/other_test.lua\n    local t = require('luatest')\n    local g = t.group('other')\n    -- ...\n    g.test_example_2 = function() ... end\n    g.test_example_m = function() ... end\n\n    -- Define parametrized groups\n    local pg = t.group('pgroup', {{engine = 'memtx'}, {engine = 'vinyl'}})\n    pg.test_example_3 = function(cg)\n        -- Use cg.params here\n        box.schema.space.create('test', {\n            engine = cg.params.engine,\n        })\n    end\n\n    -- Hooks can be specified for one parameter\n    pg.before_all({engine = 'memtx'}, function() ... end)\n    pg.before_each({engine = 'memtx'}, function() ... end)\n    pg.before_test('test_example_3', {engine = 'vinyl'}, function() ... end)\n\nRun tests from a path.\n\n.. code-block:: bash\n\n    luatest                               # run all tests from the ./test directory\n    luatest test/integration              # run all tests from the specified directory\n    luatest test/feature_test.lua         # run all tests from the specified file\n\nRun tests from a group.\n\n.. code-block:: bash\n\n    luatest feature                       # run all tests from the specified group\n    luatest other.test_example_2          # run one test from the specified group\n    luatest feature other.test_example_2  # run tests by group and test name\n\nNote that luatest recognizes an input parameter as a path only if it contains ``/``, otherwise, it will be considered\nas a group name.\n\n.. code-block:: bash\n\n    luatest feature                       # considered as a group name\n    luatest ./feature                     # considered as a path\n    luatest feature/                      # considered as a path\n\nYou can also use ``-p`` option in combination with the examples above for running tests matching to some name pattern.\n\n.. code-block:: bash\n\n    luatest feature -p test_example       # run all tests from the specified group matching to the specified pattern\n\nLuatest automatically requires ``test/helper.lua`` file if it's present.\nYou can configure luatest or run any bootstrap code there.\n\nSee the `getting-started example \u003chttps://github.com/tarantool/cartridge-cli/tree/master/examples/getting-started-app/test\u003e`_\nin cartridge-cli repo.\n\n---------------------------------\nTests order\n---------------------------------\n\nUse the ``--shuffle`` option to tell luatest how to order the tests.\nThe available ordering schemes are ``group``, ``all`` and ``none``.\n\n``group`` shuffles tests within the groups.\n\n``all`` randomizes execution order across all available tests.\nBe careful: ``before_all/after_all`` hooks run always when test group is changed,\nso it may run multiple time.\n\n``none`` is the default, which executes examples within the group in the order they\nare defined (eventually they are ordered by functions line numbers).\n\nWith ``group`` and ``all`` you can also specify a ``seed`` to reproduce specific order.\n\n.. code-block:: bash\n\n    --shuffle none\n    --shuffle group\n    --shuffle all --seed 123\n    --shuffle all:123 # same as above\n\nTo change default order use:\n\n.. code-block:: Lua\n\n    -- test/helper.lua\n    local t = require('luatest')\n    t.configure({shuffle = 'group'})\n\n---------------------------------\nPreloaded hooks\n---------------------------------\nPreloaded hooks extend base hooks. They behave like the pytest fixture with the ``autouse`` parameter.\n\n.. code-block:: lua\n    -- my_helper.lua\n    local hooks = require('luatest.hooks')\n\n    hooks.before_suite_preloaded(function() print('start foo') end)\n    hooks.after_suite_preloaded(function() print('stop foo') end)\n\n    hooks.before_all_preloaded(function() print('start bar') end)\n    hooks.after_all_preloaded(function() print('stop bar') end)\n\n    hooks.before_each_preloaded(function() print('start baz') end)\n    hooks.after_each_preloaded(function() print('stop baz') end)\n\nIf you run the following test:\n\n.. code-block:: lua\n    local t = require('luatest')\n    local my_helper = require('my_helper')\n    local g = t.group()\n\n    g.before_all(function() print('prepare') end)\n    g.after_all(function() print('cleanup') end)\n\n    g.test_print = function() print('everythings is ok') end\n\nThen the hooks are executed in the following sequence:\n\n.. code-block:: text\n    |\\ start foo\n    | \\ start bar\n    |  \\ prepare\n    |   \\ start baz\n    |      test_print (everythings is ok)\n    |   / stop baz\n    |  / cleanup\n    | / stop bar\n    |/ stop foo\n\n---------------------------------\nList of luatest functions\n---------------------------------\n\n+--------------------------------------------------------------------------------------------------------------------+\n| **Assertions**                                                                                                     |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert (value[, message])``                                      | Check that value is truthy.                   |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_almost_equals (actual, expected, margin[, message])``     | Check that two floats are close by margin.    |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_covers (actual, expected[, message])``                    | Checks that actual map includes expected one. |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_lt (left, right[, message])``                             | Compare numbers.                              |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_le (left, right[, message])``                             |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_gt (left, right[, message])``                             |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_ge (left, right[, message])``                             |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_equals (actual, expected[, message[, deep_analysis]])``   | Check that two values are equal.              |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error (fn, ...)``                                         | Check that calling fn raises an error.        |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error_msg_contains (expected_partial, fn, ...)``          |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error_msg_content_equals (expected, fn, ...)``            | Strips location info from message text.       |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error_msg_equals (expected, fn, ...)``                    | Checks full error: location and text.         |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error_msg_matches (pattern, fn, ...)``                    |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_error_covers (expected, fn, ...)``                        | Checks that actual error map includes expected|\n|                                                                    | one.                                          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_eval_to_false (value[, message])``                        | Alias for assert_not.                         |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_eval_to_true (value[, message])``                         | Alias for assert.                             |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_items_exclude (actual, expected[, message])``             | Checks that one table does not include any    |\n|                                                                    | items of another, irrespective of their keys. |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_items_include (actual, expected[, message])``             | Checks that one table includes all items of   |\n|                                                                    | another, irrespective of their keys.          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_is (actual, expected[, message])``                        | Check that values are the same.               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_is_not (actual, expected[, message])``                    | Check that values are not the same.           |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_items_equals (actual, expected[, message])``              | Checks that two tables contain the same items,|\n|                                                                    | irrespective of their keys.                   |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_nan (value[, message])``                                  |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not (value[, message])``                                  | Check that value is falsy.                    |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_almost_equals (actual, expected, margin[, message])`` | Check that two floats are not close by margin |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_covers (actual, expected[, message])``                | Checks that map does not contain the other    |\n|                                                                    | one.                                          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_equals (actual, expected[, message])``                | Check that two values are not equal.          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_nan (value[, message])``                              |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_str_contains (actual, expected[, is_pattern[,         | Case-sensitive strings comparison.            |\n| message]])``                                                       |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_not_str_icontains (value, expected[, message])``          | Case-insensitive strings comparison.          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_str_contains (value, expected[, is_pattern[, message]])`` | Case-sensitive strings comparison.            |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_str_icontains (value, expected[, message])``              | Case-insensitive strings comparison.          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_str_matches (value, pattern[, start=1[, final=value:len() | Verify a full match for the string.           |\n| [, message]]])``                                                   |                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``assert_type (value, expected_type[, message])``                  | Check value's type.                           |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| **Flow control**                                                                                                   |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``fail (message)``                                                 | Stops a test due to a failure.                |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``fail_if (condition, message)``                                   | Stops a test due to a failure if condition    |\n|                                                                    | is met.                                       |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``xfail (message)``                                                | Mark test as xfail.                           |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``xfail_if (condition, message)``                                  | Mark test as xfail if condition is met.       |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``skip (message)``                                                 | Skip a running test.                          |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``skip_if (condition, message)``                                   | Skip a running test if condition is met.      |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``success ()``                                                     | Stops a test with a success.                  |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``success_if (condition)``                                         | Stops a test with a success if condition      |\n|                                                                    | is met.                                       |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| **Suite and groups**                                                                                               |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``after_suite (fn)``                                               | Add after suite hook.                         |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``before_suite (fn)``                                              | Add before suite hook.                        |\n+--------------------------------------------------------------------+-----------------------------------------------+\n| ``group (name)``                                                   | Create group of tests.                        |\n+--------------------------------------------------------------------+-----------------------------------------------+\n\n.. _xfail:\n\n---------------------------------\nXFail\n---------------------------------\n\nThe ``xfail`` mark makes test results to be interpreted vice versa: it's\nthreated as passed when an assertion fails, and it fails if no errors are\nraised. It allows one to mark a test as temporarily broken due to a bug in some\nother component which can't be fixed immediately. It's also a good practice to\nkeep xfail tests in sync with an issue tracker.\n\n.. code-block:: Lua\n\n    local g = t.group()\n    g.test_fail = function()\n        t.xfail('Must fail no matter what')\n        t.assert_equals(3, 4)\n    end\n\nXFail only applies to the errors raised by the luatest assertions. Regular Lua\nerrors still cause the test failure.\n\n.. _capturing-output:\n\n---------------------------------\nCapturing output\n---------------------------------\n\nBy default runner captures all stdout/stderr output and shows it only for failed tests.\nCapturing can be disabled with ``-c`` flag.\n\n.. _repeating:\n\n---------------------------------\nTests repeating\n---------------------------------\n\nRunners can repeat tests with flags ``-r`` / ``--repeat`` (to repeat all the tests) or\n``-R`` / ``--repeat-group`` (to repeat all the tests within the group).\n\n.. _parametrization:\n\n---------------------------------\nParametrization\n---------------------------------\n\nTest group can be parametrized.\n\n.. code-block:: Lua\n\n    local g = t.group('pgroup', {{a = 1, b = 4}, {a = 2, b = 3}})\n\n    g.test_params = function(cg)\n        ...\n        log.info('a = %s', cg.params.a)\n        log.info('b = %s', cg.params.b)\n        ...\n    end\n\nGroup can be parametrized with a matrix of parameters using `luatest.helpers`:\n\n.. code-block:: Lua\n\n    local g = t.group('pgroup', t.helpers.matrix({a = {1, 2}, b = {3, 4}}))\n    -- Will run:\n    -- * a = 1, b = 3\n    -- * a = 1, b = 4\n    -- * a = 2, b = 3\n    -- * a = 2, b = 4\n\nEach test will be performed for every params combination. Hooks will work as usual\nunless there are specified params. The order of execution in the hook group is\ndetermined by the order of declaration.\n\n.. code-block:: Lua\n\n    -- called before every test\n    g.before_each(function(cg) ... end)\n\n    -- called before tests when a == 1\n    g.before_each({a = 1}, function(cg) ... end)\n\n    -- called only before the test when a == 1 and b == 3\n    g.before_each({a = 1, b = 3}, function(cg) ... end)\n\n    -- called before test named 'test_something' when a == 1\n    g.before_test('test_something', {a = 1}, function(cg) ... end)\n\n    --etc\n\nTest from a parameterized group can be called from the command line in such a way:\n\n.. code-block:: Bash\n\n    luatest pgroup.a:1.b:4.test_params\n    luatest pgroup.a:2.b:3.test_params\n\nNote that values for ``a`` and ``b`` have to match to defined group params. The command below will give you an error\nbecause such params are not defined for the group.\n\n.. code-block:: Bash\n\n    luatest pgroup.a:2.b:2.test_params  # will raise an error\n\n.. _test-helpers:\n\n---------------------------------\nTest helpers\n---------------------------------\n\nThere are helpers to run tarantool applications and perform basic interaction with it.\nIf application follows configuration conventions it is possible to use\noptions to configure server instance and helpers at the same time. For example\n``http_port`` is used to perform http request in tests and passed in ``TARANTOOL_HTTP_PORT``\nto server process.\n\n.. code-block:: Lua\n\n    local server = luatest.Server:new({\n        command = '/path/to/executable.lua',\n        -- arguments for process\n        args = {'--no-bugs', '--fast'},\n        -- additional envars to pass to process\n        env = {SOME_FIELD = 'value'},\n        -- passed as TARANTOOL_WORKDIR\n        workdir = '/path/to/test/workdir',\n        -- passed as TARANTOOL_HTTP_PORT, used in http_request\n        http_port = 8080,\n        -- passed as TARANTOOL_LISTEN, used in connect_net_box\n        net_box_port = 3030,\n        -- passed to net_box.connect in connect_net_box\n        net_box_credentials = {user = 'username', password = 'secret'},\n    })\n    server:start()\n    -- Wait until server is ready to accept connections.\n    -- This may vary from app to app: for one server:connect_net_box() is enough,\n    -- for another more complex checks are required.\n    luatest.helpers.retrying({}, function() server:http_request('get', '/ping') end)\n\n    -- http requests\n    server:http_request('get', '/path')\n    server:http_request('post', '/path', {body = 'text'})\n    server:http_request('post', '/path', {json = {field = value}, http = {\n        -- http client options\n        headers = {Authorization = 'Basic ' .. credentials},\n        timeout = 1,\n    }})\n\n    -- This method throws error when response status is outside of then range 200..299.\n    -- To change this behaviour, path `raise = false`:\n    t.assert_equals(server:http_request('get', '/not_found', {raise = false}).status, 404)\n    t.assert_error(function() server:http_request('get', '/not_found') end)\n\n    -- using net_box\n    server:connect_net_box()\n    server:eval('return do_something(...)', {arg1, arg2})\n    server:call('function_name', {arg1, arg2})\n    server:exec(function() return box.info() end)\n    server:stop()\n\n``luatest.Process:start(path, args, env)`` provides low-level interface to run any other application.\n\n``luatest.cluster`` runs a declarative configuration as a set of Tarantool instances.\nBy default clusters are registered inside the current test group and cleaned up with\npreloaded hooks (``auto_cleanup = true``). When you need to reuse the same cluster across\nmultiple tests or keep several clusters running at once, pass ``auto_cleanup = false`` and\nmanage the lifecycle manually:\n\n.. code-block:: Lua\n\n    local t = require('luatest')\n    local cluster = require('luatest.cluster')\n    local cbuilder = require('luatest.cbuilder')\n\n    local g = t.group('shared')\n\n    g.before_all(function()\n        local config = cbuilder:new()\n            :use_group('g-1')\n            :use_replicaset('rs-1')\n            :add_instance('instance-1', {})\n            :config()\n\n        g.cluster = cluster:new(config, {}, {auto_cleanup = false})\n        g.cluster:start()\n    end)\n\n    g.after_all(function()\n        g.cluster:drop()\n    end)\n\n    g.test_reuses_cluster_between_cases = function()\n        t.assert_not_equals(g.cluster['instance-1'].process, nil)\n    end\n\nThere are several small helpers for common actions:\n\n.. code-block:: Lua\n\n    luatest.helpers.uuid('ab', 2, 1) == 'abababab-0002-0000-0000-000000000001'\n\n    luatest.helpers.retrying({timeout = 1, delay = 0.1}, failing_function, arg1, arg2)\n    -- wait until server is up\n    luatest.helpers.retrying({}, function() server:http_request('get', '/status') end)\n\n.. _luacov-integration:\n\n---------------------------------\nluacov integration\n---------------------------------\n\n- Install `luacov \u003chttps://github.com/keplerproject/luacov\u003e`_ with ``tt rocks install luacov``\n- Configure it with ``.luacov`` file\n- Clean old reports ``rm -f luacov.*.out*``\n- Run luatest with ``--coverage`` option\n- Generate report with ``.rocks/bin/luacov .``\n- Show summary with ``grep -A999 '^Summary' luacov.report.out``\n\nWhen running integration tests with coverage collector enabled, luatest\nautomatically starts new tarantool instances with luacov enabled.\nSo coverage is collected from all the instances.\nHowever this has some limitations:\n\n- It works only for instances started with ``Server`` helper.\n- Process command should be executable lua file or tarantool with script argument.\n- Instance must be stopped with ``server:stop()``, because this is the point where stats are saved.\n- Don't save stats concurrently to prevent corruption.\n\n---------------------------------\nDevelopment\n---------------------------------\n\n- Check out the repo.\n- Prepare makefile with ``cmake .``.\n- Install dependencies with ``make bootstrap``.\n- Run it with ``make lint`` before committing changes.\n- Run tests with ``bin/luatest``.\n\n---------------------------------\nContributing\n---------------------------------\n\nBug reports and pull requests are welcome on at\nhttps://github.com/tarantool/luatest.\n\n---------------------------------\nLicense\n---------------------------------\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Fluatest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarantool%2Fluatest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Fluatest/lists"}