diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 62bca231..c1ad3718 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,10 +14,17 @@ jobs: fail-fast: false matrix: python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.8-dev] + tarantool-version: [2.6, 2.7] steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} + - name: update git submodules + run: git submodule update --init --recursive + - name: set up Tarantool ${{ matrix.tarantool-version }} + uses: tarantool/setup-tarantool@v1 + with: + tarantool-version: ${{ matrix.tarantool-version }} + - name: set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -28,6 +35,19 @@ jobs: sudo apt update -y sudo apt-get -y install lua5.1 luarocks sudo luarocks install luacheck + - name: set default pip to pip3 + run: | + sudo rm -f /usr/local/bin/pip + sudo ln -s /usr/bin/pip3 /usr/local/bin/pip + - name: set default python and pip to v2.7 + if: ${{ matrix.python-version }} == 2.7 + run: | + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py + sudo python2 get-pip.py + sudo rm -f /usr/bin/python + sudo ln -s /usr/bin/python2 /usr/bin/python + sudo rm -f /usr/local/bin/pip + sudo ln -s /usr/local/bin/pip2 /usr/local/bin/pip - name: setup python dependencies run: | pip install -r requirements.txt @@ -35,3 +55,6 @@ jobs: - name: run static analysis run: | make lint + - name: run regression tests + run: | + make test diff --git a/.luacheckrc b/.luacheckrc index e19adbed..8df2789f 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -26,4 +26,5 @@ include_files = { exclude_files = { "lib/tarantool-python", + "test/test-tarantool/*.test.lua", } diff --git a/Makefile b/Makefile index 9e8b6f5c..5fb4c2a1 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,20 @@ +TEST_RUN_EXTRA_PARAMS?= +PYTHON?=python + default: false -.PHONY: lint flake8 luacheck lint: flake8 luacheck flake8: - python -m flake8 *.py lib/*.py + $(PYTHON) -m flake8 *.py lib/*.py luacheck: luacheck --config .luacheckrc . + +test_integration: + $(PYTHON) test/test-run.py --force $(TEST_RUN_EXTRA_PARAMS) + +test: test_integration + +.PHONY: lint flake8 luacheck test test_integration diff --git a/test/test-app/cfg.test.lua b/test/test-app/cfg.test.lua new file mode 100755 index 00000000..ca557138 --- /dev/null +++ b/test/test-app/cfg.test.lua @@ -0,0 +1,19 @@ +#!/usr/bin/env tarantool + +-- Test is an example of TAP test + +local tap = require('tap') +local test = tap.test('cfg') +test:plan(4) + +box.cfg{listen = box.NULL} +test:is(nil, box.info.listen, 'no cfg.listen - no info.listen') + +box.cfg{listen = '127.0.0.1:0'} +test:ok(box.info.listen:match('127.0.0.1'), 'real IP in info.listen') +test:ok(not box.info.listen:match(':0'), 'real port in info.listen') + +box.cfg{listen = box.NULL} +test:is(nil, box.info.listen, 'cfg.listen reset drops info.listen') + +os.exit(test:check() and 0 or 1) diff --git a/test/test-app/suite.ini b/test/test-app/suite.ini new file mode 100644 index 00000000..5b18ac67 --- /dev/null +++ b/test/test-app/suite.ini @@ -0,0 +1,6 @@ +[default] +core = app +description = application tests +is_parallel = True +pretest_clean = True +use_unix_sockets_iproto = True diff --git a/test/test-run.py b/test/test-run.py new file mode 120000 index 00000000..3cd9faff --- /dev/null +++ b/test/test-run.py @@ -0,0 +1 @@ +../test-run.py \ No newline at end of file diff --git a/test/test-tarantool/box.lua b/test/test-tarantool/box.lua new file mode 100644 index 00000000..35a087de --- /dev/null +++ b/test/test-tarantool/box.lua @@ -0,0 +1,12 @@ +#!/usr/bin/env tarantool +local os = require('os') + +box.cfg{ + listen = os.getenv("LISTEN"), + memtx_memory = 107374182, + pid_file = "tarantool.pid", + force_recovery = true, + wal_max_size = 500 +} + +require('console').listen(os.getenv('ADMIN')) diff --git a/test/test-tarantool/engine.cfg b/test/test-tarantool/engine.cfg new file mode 100644 index 00000000..b8b138b4 --- /dev/null +++ b/test/test-tarantool/engine.cfg @@ -0,0 +1,15 @@ +{ + "set_language.test.sql": { + "memtx": {"engine": "memtx"} + }, + "setopt_delimeter.test.lua": { + "memtx": {"engine": "memtx"} + }, + "worker_hang_when_gc_triggered_inside_colorer.test.lua": { + "vinyl": {"engine": "vinyl"} + }, + "*": { + "memtx": {"engine": "memtx"}, + "vinyl": {"engine": "vinyl"} + } +} diff --git a/test/test-tarantool/iproto.result b/test/test-tarantool/iproto.result new file mode 100644 index 00000000..0cc1a355 --- /dev/null +++ b/test/test-tarantool/iproto.result @@ -0,0 +1,7 @@ +IPROTO_UPDATE +query [('IPROTO_CODE', 4)] [('IPROTO_SPACE_ID', 280)] +True +query [('IPROTO_CODE', 4)] [('IPROTO_KEY', (1,)), ('IPROTO_SPACE_ID', 280)] +True + + diff --git a/test/test-tarantool/iproto.test.py b/test/test-tarantool/iproto.test.py new file mode 100644 index 00000000..31a6742d --- /dev/null +++ b/test/test-tarantool/iproto.test.py @@ -0,0 +1,55 @@ +""" +Original Tarantool's test box-py/iproto.test.py had a problem when output with +running under Python 2 was not the same as with running under Python 3. + +Fixed in commit 697b79781cc63e2d87d86d43713998261d602334 +"test: make output of box-py/iproto.test.py deterministic". +""" + +from __future__ import print_function + +import msgpack +from tarantool.const import * +from tarantool import Connection +from tarantool.response import Response +from lib.tarantool_connection import TarantoolConnection + +# Note re IPROTO_SQL_INFO_* keys: they cannot appear in the +# response map at the top level, but have the same codes as other +# IPROTO_* constants. Exclude those names so. +key_names = {} +for (k,v) in list(globals().items()): + if type(k) == str and k.startswith("IPROTO_") and \ + not k.startswith("IPROTO_SQL_INFO_") and type(v) == int: + key_names[v] = k + +def repr_dict(todump): + d = {} + for (k, v) in todump.items(): + k_name = key_names.get(k, k) + d[k_name] = v + return repr(sorted(d.items())) + + +def test(header, body): + # Connect and authenticate + c = Connection("localhost", server.iproto.port) + c.connect() + print("query", repr_dict(header), repr_dict(body)) + header = msgpack.dumps(header) + body = msgpack.dumps(body) + query = msgpack.dumps(len(header) + len(body)) + header + body + # Send raw request using connected socket + s = c._socket + try: + s.send(query) + except OSError as e: + print(" => ", "Failed to send request") + c.close() + print(iproto.py_con.ping() > 0) + +print("IPROTO_UPDATE") +test({ IPROTO_CODE : REQUEST_TYPE_UPDATE }, { IPROTO_SPACE_ID: 280 }) +test({ IPROTO_CODE : REQUEST_TYPE_UPDATE }, + { IPROTO_SPACE_ID: 280, IPROTO_KEY: (1, )}) +print("\n") diff --git a/test/test-tarantool/replica.lua b/test/test-tarantool/replica.lua new file mode 100644 index 00000000..d5367173 --- /dev/null +++ b/test/test-tarantool/replica.lua @@ -0,0 +1,21 @@ +#!/usr/bin/env tarantool + +local repl_include_self = arg[1] and arg[1] == 'true' or false +local repl_list + +if repl_include_self then + repl_list = {os.getenv("MASTER"), os.getenv("LISTEN")} +else + repl_list = os.getenv("MASTER") +end + +-- Start the console first to allow test-run to attach even before +-- box.cfg is finished. +require('console').listen(os.getenv('ADMIN')) + +box.cfg({ + listen = os.getenv("LISTEN"), + replication = repl_list, + memtx_memory = 107374182, + replication_timeout = 0.1, +}) diff --git a/test/test-tarantool/set_language.result b/test/test-tarantool/set_language.result new file mode 100644 index 00000000..d40345cd --- /dev/null +++ b/test/test-tarantool/set_language.result @@ -0,0 +1,50 @@ +-- test-run result file version 2 +-- Simple SQL test that uses '\set language' command. +-- Command introduced in commit 6e38b88eb6bbe543a1e3ba0a6a0be2f6f58abc86 +-- ('Implement SQL driver') + +-- Create table for tests +CREATE TABLE t (a BOOLEAN PRIMARY KEY); + | --- + | - row_count: 1 + | ... +INSERT INTO t VALUES (true), (false); + | --- + | - row_count: 2 + | ... + +-- Create user-defined function. +\set language lua + | --- + | - true + | ... +test_run = require('test_run').new() + | --- + | ... +\set language sql + | --- + | - true + | ... + +SELECT a FROM t WHERE a; + | --- + | - metadata: + | - name: A + | type: boolean + | rows: + | - [true] + | ... +SELECT a FROM t WHERE a != true; + | --- + | - metadata: + | - name: A + | type: boolean + | rows: + | - [false] + | ... + +-- Cleaning. +DROP TABLE t; + | --- + | - row_count: 1 + | ... diff --git a/test/test-tarantool/set_language.test.sql b/test/test-tarantool/set_language.test.sql new file mode 100644 index 00000000..66c0ac74 --- /dev/null +++ b/test/test-tarantool/set_language.test.sql @@ -0,0 +1,18 @@ +-- Simple SQL test that uses '\set language' command. +-- Command introduced in commit 6e38b88eb6bbe543a1e3ba0a6a0be2f6f58abc86 +-- ('Implement SQL driver') + +-- Create table for tests +CREATE TABLE t (a BOOLEAN PRIMARY KEY); +INSERT INTO t VALUES (true), (false); + +-- Create user-defined function. +\set language lua +test_run = require('test_run').new() +\set language sql + +SELECT a FROM t WHERE a; +SELECT a FROM t WHERE a != true; + +-- Cleaning. +DROP TABLE t; diff --git a/test/test-tarantool/setopt_delimeter.result b/test/test-tarantool/setopt_delimeter.result new file mode 100644 index 00000000..426c66d8 --- /dev/null +++ b/test/test-tarantool/setopt_delimeter.result @@ -0,0 +1,35 @@ +-- test-run result file version 2 +-- Simple test that uses 'setopt delimiter' command. +-- Command introduced in commit 6e38b88eb6bbe543a1e3ba0a6a0be2f6f58abc86 +-- ('Implement SQL driver') + +test_run = require('test_run').new() + | --- + | ... + +-- Using delimiter +_ = test_run:cmd("setopt delimiter ';'") + | --- + | ... +function test_a() + local a = 1 +end; + | --- + | ... +_ = test_run:cmd("setopt delimiter ''"); + | --- + | ... + +box.cfg{} + | --- + | ... + +-- Using multiline +box.cfg{ \ + coredump = false, \ + log_format = 'plain', \ + log_level = 5, \ + strip_core = true \ +} + | --- + | ... diff --git a/test/test-tarantool/setopt_delimeter.test.lua b/test/test-tarantool/setopt_delimeter.test.lua new file mode 100644 index 00000000..bba791af --- /dev/null +++ b/test/test-tarantool/setopt_delimeter.test.lua @@ -0,0 +1,22 @@ +-- Simple test that uses 'setopt delimiter' command. +-- Command introduced in commit 6e38b88eb6bbe543a1e3ba0a6a0be2f6f58abc86 +-- ('Implement SQL driver') + +test_run = require('test_run').new() + +-- Using delimiter +_ = test_run:cmd("setopt delimiter ';'") +function test_a() + local a = 1 +end; +_ = test_run:cmd("setopt delimiter ''"); + +box.cfg{} + +-- Using multiline +box.cfg{ \ + coredump = false, \ + log_format = 'plain', \ + log_level = 5, \ + strip_core = true \ +} diff --git a/test/test-tarantool/suite.ini b/test/test-tarantool/suite.ini new file mode 100644 index 00000000..1bfddc35 --- /dev/null +++ b/test/test-tarantool/suite.ini @@ -0,0 +1,7 @@ +[default] +core = tarantool +description = tarantool tests +script = box.lua +use_unix_sockets = True +pretest_clean = True +config = engine.cfg diff --git a/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.result b/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.result new file mode 100644 index 00000000..f5de30e1 --- /dev/null +++ b/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.result @@ -0,0 +1,43 @@ +-- test-run result file version 2 +-- regression test for the problem fixed in [1] that was a part +-- of more common issue [2]. It's worth to mention that original +-- problem has more chances to reproduce with applied patch to +-- multiprocessing source code (multiprocessing/connection.py). +-- +-- 1. https://github.com/tarantool/test-run/pull/275 +-- 2. https://github.com/tarantool/tarantool-qa/issues/96 + +-- Setup +box.schema.user.grant('guest', 'replication') + | --- + | ... + +-- Setup and teardown cluster, manage separate instances. +test_run = require('test_run').new() + | --- + | ... +test_run:cmd('create server replica with rpl_master=default, script="test-tarantool/replica.lua"') + | --- + | - true + | ... +test_run:cmd('start server replica') + | --- + | - true + | ... +test_run:cmd('stop server replica') + | --- + | - true + | ... +test_run:cmd('cleanup server replica') + | --- + | - true + | ... +test_run:cmd('delete server replica') + | --- + | - true + | ... + +-- Teardown +box.schema.user.revoke('guest', 'replication') + | --- + | ... diff --git a/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.test.lua b/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.test.lua new file mode 100644 index 00000000..f1b10036 --- /dev/null +++ b/test/test-tarantool/worker_hang_when_gc_triggered_inside_colorer.test.lua @@ -0,0 +1,21 @@ +-- regression test for the problem fixed in [1] that was a part +-- of more common issue [2]. It's worth to mention that original +-- problem has more chances to reproduce with applied patch to +-- multiprocessing source code (multiprocessing/connection.py). +-- +-- 1. https://github.com/tarantool/test-run/pull/275 +-- 2. https://github.com/tarantool/tarantool-qa/issues/96 + +-- Setup +box.schema.user.grant('guest', 'replication') + +-- Setup and teardown cluster, manage separate instances. +test_run = require('test_run').new() +test_run:cmd('create server replica with rpl_master=default, script="test-tarantool/replica.lua"') +test_run:cmd('start server replica') +test_run:cmd('stop server replica') +test_run:cmd('cleanup server replica') +test_run:cmd('delete server replica') + +-- Teardown +box.schema.user.revoke('guest', 'replication') diff --git a/test/test-unit/broken_unicode.result b/test/test-unit/broken_unicode.result new file mode 100644 index 00000000..aece3075 --- /dev/null +++ b/test/test-unit/broken_unicode.result @@ -0,0 +1,5 @@ +TAP version 13 +1..3 +ok 1 -  +ok 2 -  +ok 3 - ☠ diff --git a/test/test-unit/broken_unicode.test b/test/test-unit/broken_unicode.test new file mode 100755 index 00000000..e856c228 --- /dev/null +++ b/test/test-unit/broken_unicode.test @@ -0,0 +1,15 @@ +#!/bin/sh + +# Test is needed to check how test-run handle +# tests with result files. Since commit +# 395edeb6b743c4479a62dd2183062124973d2b2a +# 'python3: decouple bytes and strings' test-run +# reads test output and result files in byte mode. +# Output of this test contains broken UTF-8 sequences +# and test-run will fail if it will try to decode output. + +printf 'TAP version 13\n' +printf '1..3\n' +printf 'ok 1 - \302\302\n' +printf 'ok 2 - \302\302\n' +printf 'ok 3 - \342\230\240\n' diff --git a/test/test-unit/suite.ini b/test/test-unit/suite.ini new file mode 100644 index 00000000..75c80ece --- /dev/null +++ b/test/test-unit/suite.ini @@ -0,0 +1,4 @@ +[default] +core = unittest +description = unit tests +is_parallel = True