From e37931835a4c0a38781fc5bb27760fab952438c9 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Mon, 7 Aug 2023 17:41:00 +0300 Subject: [PATCH 1/4] test: wait until server is ready Current `wait_until_started` method wait till `box.info.status` is "running" and start sending requests. Such approach is wrong: status "running" [1] does not guarantees that instance is available for writing (like creating new users) [2]. It results in flaky test results (for example, see 4 restarts in [3]). This patch fixes the issue. After this patch, it is guaranteed that after `wait_until_ready` call instance had finished to run its initialization script, including box.cfg, and available for writing data if it is expected to be able to. Windows instances use a separate lock mechanism, so this patch is not related to Windows instances. 1. https://github.com/tarantool/tarantool/blob/983a7ec215d46b6d02935d1baa8bbe07fc371795/src/box/box.cc#L5425-L5426 2. https://github.com/tarantool/tarantool/blob/983a7ec215d46b6d02935d1baa8bbe07fc371795/src/box/box.cc#L5454 3. https://github.com/tarantool/tarantool/actions/runs/5759802620 --- test/suites/box.lua | 2 ++ test/suites/crud_server.lua | 2 ++ test/suites/lib/tarantool_server.py | 21 ++++++++------------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/suites/box.lua b/test/suites/box.lua index eb4330dd..c8110d18 100644 --- a/test/suites/box.lua +++ b/test/suites/box.lua @@ -19,3 +19,5 @@ box.cfg{ pid_file = "box.pid", auth_type = (auth_type:len() > 0) and auth_type or nil, } + +rawset(_G, 'ready', true) diff --git a/test/suites/crud_server.lua b/test/suites/crud_server.lua index 8bb58fcb..f939818a 100644 --- a/test/suites/crud_server.lua +++ b/test/suites/crud_server.lua @@ -91,3 +91,5 @@ if crud_imported == false or vshard_imported == false then else configure_crud_instance(primary_listen, crud, vshard) end + +rawset(_G, 'ready', true) diff --git a/test/suites/lib/tarantool_server.py b/test/suites/lib/tarantool_server.py index 1dd5e053..c8f34b37 100644 --- a/test/suites/lib/tarantool_server.py +++ b/test/suites/lib/tarantool_server.py @@ -302,27 +302,22 @@ def prepare_args(self): return shlex.split(self.binary if not self.script else self.script_dst) - def wait_until_started(self): + def wait_until_ready(self): """ - Wait until server is started. + Wait until server is configured and ready to work. Server consists of two parts: 1) wait until server is listening on sockets - 2) wait until server tells us his status + 2) wait until server finishes executing its script """ while True: try: temp = TarantoolAdmin('0.0.0.0', self.args['admin']) - while True: - ans = temp('box.info.status')[0] - if ans in ('running', 'hot_standby', 'orphan') or ans.startswith('replica'): - temp.disconnect() - return True - if ans in ('loading',): - continue - - raise ValueError(f"Strange output for `box.info.status`: {ans}") + ans = temp('ready')[0] + temp.disconnect() + if isinstance(ans, bool) and ans: + return True except socket.error as exc: if exc.errno == errno.ECONNREFUSED: time.sleep(0.1) @@ -352,7 +347,7 @@ def start(self): cwd=self.vardir, stdout=self.log_des, stderr=self.log_des) - self.wait_until_started() + self.wait_until_ready() def stop(self): """ From 43880dd4b2f188f8e5c51861d4a7a6eba4af24e9 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Mon, 7 Aug 2023 17:42:34 +0300 Subject: [PATCH 2/4] ci: use WSL with Ubuntu 22.04 Some installation certificates are outdated for Ubuntu 22.04. --- .github/workflows/packing.yml | 8 ++++---- .github/workflows/testing.yml | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/packing.yml b/.github/workflows/packing.yml index eabf5096..b5b84f32 100644 --- a/.github/workflows/packing.yml +++ b/.github/workflows/packing.yml @@ -148,16 +148,16 @@ jobs: - name: Setup WSL for tarantool uses: Vampire/setup-wsl@v1 with: - distribution: Ubuntu-20.04 + distribution: Ubuntu-22.04 - name: Install tarantool - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | curl -L https://tarantool.io/release/2/installer.sh | bash -s sudo apt install -y tarantool tarantool-dev - name: Setup test tarantool instance - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | rm -f ./tarantool.pid ./tarantool.log TNT_PID=$(tarantool ./test/suites/lib/tarantool_python_ci.lua > tarantool.log 2>&1 & echo $!) @@ -172,7 +172,7 @@ jobs: - name: Stop test tarantool instance if: ${{ always() }} - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | cat tarantool.log || true kill $(cat tarantool.pid) || true diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 199744f2..88fa08d7 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -262,16 +262,16 @@ jobs: - name: Setup WSL for tarantool uses: Vampire/setup-wsl@v2 with: - distribution: Ubuntu-20.04 + distribution: Ubuntu-22.04 - name: Install tarantool ${{ matrix.tarantool }} for WSL (2.10 and newer) - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | curl -L https://tarantool.io/release/2/installer.sh | bash -s sudo apt install -y tarantool=${{ matrix.tarantool }} tarantool-dev=${{ matrix.tarantool }} - name: Setup test tarantool instance - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | rm -f ./tarantool.pid ./tarantool.log TNT_PID=$(tarantool ./test/suites/lib/tarantool_python_ci.lua > tarantool.log 2>&1 & echo $!) @@ -286,7 +286,7 @@ jobs: - name: Stop test tarantool instance if: ${{ always() }} - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | cat tarantool.log || true kill $(cat tarantool.pid) || true @@ -334,16 +334,16 @@ jobs: - name: Setup WSL for tarantool uses: Vampire/setup-wsl@v2 with: - distribution: Ubuntu-20.04 + distribution: Ubuntu-22.04 - name: Install tarantool ${{ matrix.tarantool }} for WSL - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | curl -L https://tarantool.io/release/2/installer.sh | bash -s sudo apt install -y tarantool=${{ matrix.tarantool }} tarantool-dev=${{ matrix.tarantool }} - name: Setup test tarantool instance - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | rm -f ./tarantool.pid ./tarantool.log TNT_PID=$(tarantool ./test/suites/lib/tarantool_python_ci.lua > tarantool.log 2>&1 & echo $!) @@ -358,7 +358,7 @@ jobs: - name: Stop test tarantool instance if: ${{ always() }} - shell: wsl-bash_Ubuntu-20.04 {0} + shell: wsl-bash_Ubuntu-22.04 {0} run: | cat tarantool.log || true kill $(cat tarantool.pid) || true From 1f2e899600e9a4a59f1c027b7dd484985d6f4404 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Mon, 7 Aug 2023 19:24:25 +0300 Subject: [PATCH 3/4] test: assert admin commands success Admin command are sent through text protocol. Responses are rarely processed, especially those which sets up schema and users. But such requests can contain errors, like "already exists" or syntax ones. Having asserts on schema set up makes it easier to debug some cases. For example, it was helpful in discovering the reason behind "user not exists" fails fixed in "wait until server is ready" patchset commit [1]. 1. https://github.com/tarantool/tarantool-python/actions/runs/5784619729/job/15675655683?pr=306 --- test/suites/test_connection.py | 71 +++++++++++++-------- test/suites/test_datetime.py | 23 +++++-- test/suites/test_dbapi.py | 13 ++-- test/suites/test_decimal.py | 29 ++++++--- test/suites/test_dml.py | 62 ++++++++++-------- test/suites/test_encoding.py | 84 +++++++++++++----------- test/suites/test_error_ext.py | 20 ++++-- test/suites/test_execute.py | 13 ++-- test/suites/test_interval.py | 20 ++++-- test/suites/test_mesh.py | 29 ++++++--- test/suites/test_pool.py | 60 ++++++++++------- test/suites/test_push.py | 94 ++++++++++++--------------- test/suites/test_schema.py | 113 ++++++++++++++++++--------------- test/suites/test_uuid.py | 39 ++++++++---- test/suites/utils.py | 16 +++++ 15 files changed, 419 insertions(+), 267 deletions(-) create mode 100644 test/suites/utils.py diff --git a/test/suites/test_connection.py b/test/suites/test_connection.py index 52234608..4402f0b0 100644 --- a/test/suites/test_connection.py +++ b/test/suites/test_connection.py @@ -5,8 +5,9 @@ import sys import unittest - import decimal + +import pkg_resources import msgpack import tarantool @@ -14,6 +15,7 @@ from .lib.skip import skip_or_run_decimal_test, skip_or_run_varbinary_test from .lib.tarantool_server import TarantoolServer +from .utils import assert_admin_success class TestSuiteConnection(unittest.TestCase): @@ -26,35 +28,48 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" + resp = cls.adm(""" box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute', 'universe') - - box.schema.create_space('space_varbin') - - box.space['space_varbin']:format({ - { - 'id', - type = 'number', - is_nullable = false - }, - { - 'varbin', - type = 'varbinary', - is_nullable = false, - } - }) - - box.space['space_varbin']:create_index('id', { - type = 'tree', - parts = {1, 'number'}, - unique = true}) - - box.space['space_varbin']:create_index('varbin', { - type = 'tree', - parts = {2, 'varbinary'}, - unique = true}) + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) + + return true """) + assert_admin_success(resp) + + if cls.srv.admin.tnt_version >= pkg_resources.parse_version('2.2.1'): + resp = cls.adm(""" + box.schema.create_space('space_varbin', {if_not_exists = true}) + + box.space['space_varbin']:format({ + { + 'id', + type = 'number', + is_nullable = false + }, + { + 'varbin', + type = 'varbinary', + is_nullable = false, + } + }) + + box.space['space_varbin']:create_index('id', { + type = 'tree', + parts = {1, 'number'}, + unique = true, + if_not_exists = true}) + + box.space['space_varbin']:create_index('varbin', { + type = 'tree', + parts = {2, 'varbinary'}, + unique = true, + if_not_exists = true}) + + return true + """) + assert_admin_success(resp) + cls.con = None def setUp(self): diff --git a/test/suites/test_datetime.py b/test/suites/test_datetime.py index ae22dcfc..9f250804 100644 --- a/test/suites/test_datetime.py +++ b/test/suites/test_datetime.py @@ -16,6 +16,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_datetime_test, skip_or_run_datetime_2_11_test +from .utils import assert_admin_success class TestSuiteDatetime(unittest.TestCase): @@ -28,25 +29,28 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" + resp = cls.adm(""" _, datetime = pcall(require, 'datetime') - box.schema.space.create('test') + box.schema.space.create('test', {if_not_exists = true}) box.space['test']:create_index('primary', { type = 'tree', parts = {1, 'string'}, - unique = true}) + unique = true, + if_not_exists = true}) pcall(function() box.schema.space.create('test_pk') box.space['test_pk']:create_index('primary', { type = 'tree', parts = {1, 'datetime'}, - unique = true}) + unique = true, + if_not_exists = true}) end) box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute', 'universe') + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) local function add(arg1, arg2) return arg1 + arg2 @@ -57,7 +61,10 @@ def setUpClass(cls): return arg1 - arg2 end rawset(_G, 'sub', sub) + + return true """) + assert_admin_success(resp) cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary'], user='test', password='test') @@ -67,7 +74,11 @@ def setUp(self): if self.srv.is_started(): self.srv.touch_lock() - self.adm("box.space['test']:truncate()") + resp = self.adm(""" + box.space['test']:truncate() + return true + """) + assert_admin_success(resp) def test_datetime_class_api(self): datetime = tarantool.Datetime(year=2022, month=8, day=31, hour=18, minute=7, sec=54, diff --git a/test/suites/test_dbapi.py b/test/suites/test_dbapi.py index 83156b39..bd8c7487 100644 --- a/test/suites/test_dbapi.py +++ b/test/suites/test_dbapi.py @@ -12,6 +12,7 @@ from tarantool import dbapi from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_sql_test +from .utils import assert_admin_success class TestSuiteDBAPI(dbapi20.DatabaseAPI20Test): @@ -39,6 +40,14 @@ def setUpClass(cls): "port": cls.srv.args['primary'] } + # grant full access to guest + resp = cls.srv.admin(""" + box.schema.user.grant('guest', 'create,read,write,execute', 'universe', + nil, {if_not_exists = true}) + return true + """) + assert_admin_success(resp) + @skip_or_run_sql_test def setUp(self): # prevent a remote tarantool from clean our session @@ -46,10 +55,6 @@ def setUp(self): self.srv.touch_lock() self.con.flush_schema() - # grant full access to guest - self.srv.admin("box.schema.user.grant('guest', 'create,read,write," - "execute', 'universe')") - @classmethod def tearDownClass(cls): cls.con.close() diff --git a/test/suites/test_decimal.py b/test/suites/test_decimal.py index b880eaa3..2875a7da 100644 --- a/test/suites/test_decimal.py +++ b/test/suites/test_decimal.py @@ -16,6 +16,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_decimal_test +from .utils import assert_admin_success class TestSuiteDecimal(unittest.TestCase): @@ -28,26 +29,32 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" - _, decimal = pcall(require, 'decimal') + resp = cls.adm(""" + decimal_supported, decimal = pcall(require, 'decimal') - box.schema.space.create('test') + box.schema.space.create('test', {if_not_exists = true}) box.space['test']:create_index('primary', { type = 'tree', parts = {1, 'string'}, - unique = true}) + unique = true, + if_not_exists = true}) - pcall(function() + if decimal_supported then box.schema.space.create('test_pk') box.space['test_pk']:create_index('primary', { type = 'tree', parts = {1, 'decimal'}, - unique = true}) - end) + unique = true, + if_not_exists = true}) + end box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute', 'universe') + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) + + return true """) + assert_admin_success(resp) cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary'], user='test', password='test') @@ -57,7 +64,11 @@ def setUp(self): if self.srv.is_started(): self.srv.touch_lock() - self.adm("box.space['test']:truncate()") + resp = self.adm(""" + box.space['test']:truncate() + return true + """) + assert_admin_success(resp) valid_cases = { 'simple_decimal_1': { diff --git a/test/suites/test_dml.py b/test/suites/test_dml.py index 69293b55..f557451e 100644 --- a/test/suites/test_dml.py +++ b/test/suites/test_dml.py @@ -10,6 +10,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_error_extra_info_test +from .utils import assert_admin_success class TestSuiteRequest(unittest.TestCase): @@ -22,29 +23,35 @@ def setUpClass(cls): cls.srv.start() cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary']) cls.adm = cls.srv.admin - cls.space_created = cls.adm("box.schema.create_space('space_1')") - cls.adm(""" - box.space['space_1']:create_index('primary', { - type = 'tree', - parts = {1, 'num'}, - unique = true}) - """.replace('\n', ' ')) - cls.adm(""" - box.space['space_1']:create_index('secondary', { - type = 'tree', - parts = {2, 'num', 3, 'str'}, - unique = false}) - """.replace('\n', ' ')) - cls.space_created = cls.adm("box.schema.create_space('space_2')") - cls.adm(""" - box.space['space_2']:create_index('primary', { - type = 'hash', - parts = {1, 'num'}, - unique = true}) - """.replace('\n', ' ')) - cls.adm("json = require('json')") - cls.adm("fiber = require('fiber')") - cls.adm("uuid = require('uuid')") + cls.space_created = cls.adm("box.schema.create_space('space_1', {if_not_exists = true})") + resp = cls.adm(""" + box.space['space_1']:create_index('primary', { + type = 'tree', + parts = {1, 'num'}, + unique = true, + if_not_exists = true}) + + box.space['space_1']:create_index('secondary', { + type = 'tree', + parts = {2, 'num', 3, 'str'}, + unique = false, + if_not_exists = true}) + + box.schema.create_space('space_2', {if_not_exists = true}) + + box.space['space_2']:create_index('primary', { + type = 'hash', + parts = {1, 'num'}, + unique = true, + if_not_exists = true}) + + json = require('json') + fiber = require('fiber') + uuid = require('uuid') + + return true + """) + assert_admin_success(resp) if not sys.platform.startswith("win"): cls.sock_srv = TarantoolServer(create_unix_socket=True) @@ -60,10 +67,11 @@ def setUp(self): def test_00_00_authenticate(self): self.assertIsNone(self.srv.admin(""" - box.schema.user.create('test', { password = 'test' }) + box.schema.user.create('test', { password = 'test', if_not_exists = true }) """)) self.assertIsNone(self.srv.admin(""" - box.schema.user.grant('test', 'execute,read,write', 'universe') + box.schema.user.grant('test', 'execute,read,write', 'universe', + nil, {if_not_exists = true}) """)) self.assertEqual(self.con.authenticate('test', 'test')._data, None) @@ -311,7 +319,7 @@ def test_11_select_all_hash(self): space.select((), iterator=tarantool.const.ITERATOR_EQ) def test_12_update_fields(self): - self.srv.admin( + resp = self.srv.admin( """ do local sp = box.schema.create_space('sp', { @@ -325,7 +333,9 @@ def test_12_update_fields(self): parts = {1, 'unsigned'} }) end + return true """) + assert_admin_success(resp) self.con.insert('sp', [2, 'help', 4]) self.assertSequenceEqual( self.con.update('sp', (2,), [('+', 'thi', 3)]), diff --git a/test/suites/test_encoding.py b/test/suites/test_encoding.py index 14a08f54..dcda5983 100644 --- a/test/suites/test_encoding.py +++ b/test/suites/test_encoding.py @@ -1,16 +1,18 @@ """ This module tests various type encoding cases. """ -# pylint: disable=missing-class-docstring,missing-function-docstring +# pylint: disable=missing-class-docstring,missing-function-docstring,duplicate-code import sys import unittest +import pkg_resources import tarantool from tarantool.error import DatabaseError from .lib.skip import skip_or_run_varbinary_test, skip_or_run_error_extra_info_test from .lib.tarantool_server import TarantoolServer +from .utils import assert_admin_success class TestSuiteEncoding(unittest.TestCase): @@ -24,10 +26,14 @@ def setUpClass(cls): cls.srv.script = 'test/suites/box.lua' cls.srv.start() - cls.srv.admin(""" - box.schema.user.create('test', { password = 'test' }) - box.schema.user.grant('test', 'execute,read,write', 'universe') + resp = cls.srv.admin(""" + box.schema.user.create('test', { password = 'test', if_not_exists = true }) + box.schema.user.grant('test', 'execute,read,write', 'universe', + nil, {if_not_exists = true}) + + return true """) + assert_admin_success(resp) args = [cls.srv.host, cls.srv.args['primary']] kwargs = {'user': 'test', 'password': 'test'} @@ -35,41 +41,47 @@ def setUpClass(cls): cls.con_encoding_none = tarantool.Connection(*args, encoding=None, **kwargs) cls.conns = [cls.con_encoding_utf8, cls.con_encoding_none] - cls.srv.admin("box.schema.create_space('space_str')") - cls.srv.admin(""" + resp = cls.srv.admin(""" + box.schema.create_space('space_str', {if_not_exists = true}) box.space['space_str']:create_index('primary', { type = 'tree', parts = {1, 'str'}, - unique = true}) - """.replace('\n', ' ')) - - cls.srv.admin("box.schema.create_space('space_varbin')") - cls.srv.admin(r""" - box.space['space_varbin']:format({ - { - 'id', - type = 'number', - is_nullable = false - }, - { - 'varbin', - type = 'varbinary', - is_nullable = false, - } - }) - """.replace('\n', ' ')) - cls.srv.admin(""" - box.space['space_varbin']:create_index('id', { - type = 'tree', - parts = {1, 'number'}, - unique = true}) - """.replace('\n', ' ')) - cls.srv.admin(""" - box.space['space_varbin']:create_index('varbin', { - type = 'tree', - parts = {2, 'varbinary'}, - unique = true}) - """.replace('\n', ' ')) + unique = true, + if_not_exists = true}) + + return true + """) + assert_admin_success(resp) + + if cls.srv.admin.tnt_version >= pkg_resources.parse_version('2.2.1'): + resp = cls.srv.admin(""" + box.schema.create_space('space_varbin', {if_not_exists = true}) + box.space['space_varbin']:format({ + { + 'id', + type = 'number', + is_nullable = false + }, + { + 'varbin', + type = 'varbinary', + is_nullable = false, + } + }) + box.space['space_varbin']:create_index('id', { + type = 'tree', + parts = {1, 'number'}, + unique = true, + if_not_exists = true}) + box.space['space_varbin']:create_index('varbin', { + type = 'tree', + parts = {2, 'varbinary'}, + unique = true, + if_not_exists = true}) + + return true + """) + assert_admin_success(resp) def assertNotRaises(self, func, *args, **kwargs): try: diff --git a/test/suites/test_error_ext.py b/test/suites/test_error_ext.py index 8d1a63cf..52622794 100644 --- a/test/suites/test_error_ext.py +++ b/test/suites/test_error_ext.py @@ -15,6 +15,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_error_ext_type_test +from .utils import assert_admin_success class TestSuiteErrorExt(unittest.TestCase): @@ -27,18 +28,23 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" - box.schema.space.create('test') + resp = cls.adm(""" + box.schema.space.create('test', {if_not_exists = true}) box.space['test']:create_index('primary', { type = 'tree', parts = {1, 'string'}, - unique = true}) + unique = true, + if_not_exists = true}) box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute,create', 'universe') + box.schema.user.grant('test', 'read,write,execute,create', 'universe', + nil, {if_not_exists = true}) box.schema.user.create('no_grants', {if_not_exists = true}) + + return true """) + assert_admin_success(resp) cls.conn_encoding_utf8 = tarantool.Connection( cls.srv.host, cls.srv.args['primary'], @@ -78,7 +84,11 @@ def setUp(self): if self.srv.is_started(): self.srv.touch_lock() - self.adm("box.space['test']:truncate()") + resp = self.adm(""" + box.space['test']:truncate() + return true + """) + assert_admin_success(resp) # msgpack data for different encodings are actually the same, # but sometimes python msgpack module use different string diff --git a/test/suites/test_execute.py b/test/suites/test_execute.py index 66fe0982..46e85ce7 100644 --- a/test/suites/test_execute.py +++ b/test/suites/test_execute.py @@ -9,6 +9,7 @@ import tarantool from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_sql_test +from .utils import assert_admin_success class TestSuiteExecute(unittest.TestCase): @@ -32,6 +33,14 @@ def setUpClass(cls): cls.srv.start() cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary']) + # grant full access to guest + resp = cls.srv.admin(""" + box.schema.user.grant('guest', 'create,read,write,execute', 'universe', + nil, {if_not_exists = true}) + return true + """) + assert_admin_success(resp) + @skip_or_run_sql_test def setUp(self): # prevent a remote tarantool from clean our session @@ -39,10 +48,6 @@ def setUp(self): self.srv.touch_lock() self.con.flush_schema() - # grant full access to guest - self.srv.admin("box.schema.user.grant('guest', 'create,read,write," - "execute', 'universe')") - @classmethod def tearDownClass(cls): cls.con.close() diff --git a/test/suites/test_interval.py b/test/suites/test_interval.py index b2726776..c241b312 100644 --- a/test/suites/test_interval.py +++ b/test/suites/test_interval.py @@ -26,6 +26,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_datetime_test +from .utils import assert_admin_success class TestSuiteInterval(unittest.TestCase): @@ -38,17 +39,19 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" + resp = cls.adm(""" _, datetime = pcall(require, 'datetime') - box.schema.space.create('test') + box.schema.space.create('test', {if_not_exists = true}) box.space['test']:create_index('primary', { type = 'tree', parts = {1, 'string'}, - unique = true}) + unique = true, + if_not_exists = true}) box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute', 'universe') + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) local function add(arg1, arg2) return arg1 + arg2 @@ -59,7 +62,10 @@ def setUpClass(cls): return arg1 - arg2 end rawset(_G, 'sub', sub) + + return true """) + assert_admin_success(resp) cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary'], user='test', password='test') @@ -69,7 +75,11 @@ def setUp(self): if self.srv.is_started(): self.srv.touch_lock() - self.adm("box.space['test']:truncate()") + resp = self.adm(""" + box.space['test']:truncate() + return true + """) + assert_admin_success(resp) def test_interval_positional_init(self): self.assertRaisesRegex( diff --git a/test/suites/test_mesh.py b/test/suites/test_mesh.py index b82ccc0e..606cc7d1 100644 --- a/test/suites/test_mesh.py +++ b/test/suites/test_mesh.py @@ -16,18 +16,23 @@ ClusterDiscoveryWarning, ) from .lib.tarantool_server import TarantoolServer +from .utils import assert_admin_success def create_server(_id): srv = TarantoolServer() srv.script = 'test/suites/box.lua' srv.start() - srv.admin("box.schema.user.create('test', {password = 'test', " - "if_not_exists = true})") - srv.admin("box.schema.user.grant('test', 'execute', 'universe')") + resp = srv.admin(f""" + box.schema.user.create('test', {{password = 'test', if_not_exists = true}}) + box.schema.user.grant('test', 'execute', 'universe', + nil, {{if_not_exists = true}}) - # Create srv_id function (for testing purposes). - srv.admin(f"function srv_id() return {_id} end") + function srv_id() return {_id} end + + return true + """) + assert_admin_success(resp) return srv @@ -43,18 +48,22 @@ def define_cluster_function(self, func_name, servers): function {func_name}() return {{{addresses_lua}}} end + return true """ for srv in self.servers: - srv.admin(func_body) + resp = srv.admin(func_body) + assert_admin_success(resp) def define_custom_cluster_function(self, func_name, retval): func_body = f""" function {func_name}() return {retval} end + return true """ for srv in self.servers: - srv.admin(func_body) + resp = srv.admin(func_body) + assert_admin_success(resp) @classmethod def setUpClass(cls): @@ -99,7 +108,11 @@ def assert_srv_id(con, srv_id): # Start instance#1, stop instance#2 -- response from # instance#1 again. self.srv.start() - self.srv.admin('function srv_id() return 1 end') + resp = self.srv.admin(""" + function srv_id() return 1 end + return true + """) + assert_admin_success(resp) self.srv2.stop() assert_srv_id(con, 1) diff --git a/test/suites/test_pool.py b/test/suites/test_pool.py index 7134f220..e15bcbbf 100644 --- a/test/suites/test_pool.py +++ b/test/suites/test_pool.py @@ -20,31 +20,46 @@ from .lib.skip import skip_or_run_sql_test from .lib.tarantool_server import TarantoolServer +from .utils import assert_admin_success def create_server(_id): srv = TarantoolServer() srv.script = 'test/suites/box.lua' srv.start() - srv.admin("box.schema.user.create('test', {password = 'test', " - "if_not_exists = true})") - srv.admin("box.schema.user.grant('test', 'execute', 'universe')") - srv.admin("box.schema.space.create('test')") - srv.admin(r"box.space.test:format({" - r" { name = 'pk', type = 'string' }," - r" { name = 'id', type = 'number', is_nullable = true }" - r"})") - srv.admin(r"box.space.test:create_index('pk'," - r"{ unique = true," - r" parts = {{field = 1, type = 'string'}}})") - srv.admin(r"box.space.test:create_index('id'," - r"{ unique = true," - r" parts = {{field = 2, type = 'number', is_nullable=true}}})") - srv.admin("box.schema.user.grant('test', 'read,write', 'space', 'test')") - srv.admin("json = require('json')") - - # Create srv_id function (for testing purposes). - srv.admin(f"function srv_id() return {_id} end") + resp = srv.admin(f""" + box.schema.user.create('test', {{password = 'test', if_not_exists = true}}) + box.schema.user.grant('test', 'execute', 'universe', + nil, {{if_not_exists = true}}) + box.schema.space.create('test', {{if_not_exists = true}}) + box.space.test:format({{ + {{ name = 'pk', type = 'string' }}, + {{ name = 'id', type = 'number', is_nullable = true }} + }}) + box.space.test:create_index('pk', + {{ + unique = true, + parts = {{ + {{field = 1, type = 'string'}} + }}, + if_not_exists = true, + }}) + box.space.test:create_index('id', + {{ + unique = true, + parts = {{ + {{field = 2, type = 'number', is_nullable=true}} + }}, + if_not_exists = true, + }}) + box.schema.user.grant('test', 'read,write', 'space', 'test', {{if_not_exists = true}}) + json = require('json') + + function srv_id() return {_id} end + + return true + """) + assert_admin_success(resp) return srv @@ -53,11 +68,12 @@ def create_server(_id): class TestSuitePool(unittest.TestCase): def set_ro(self, srv, read_only): if read_only: - req = r'box.cfg{read_only = true}' + req = r'box.cfg{read_only = true}; return true' else: - req = r'box.cfg{read_only = false}' + req = r'box.cfg{read_only = false}; return true' - srv.admin(req) + resp = srv.admin(req) + assert_admin_success(resp) def set_cluster_ro(self, read_only_list): assert len(self.servers) == len(read_only_list) diff --git a/test/suites/test_push.py b/test/suites/test_push.py index bd14455b..24a1ae7d 100644 --- a/test/suites/test_push.py +++ b/test/suites/test_push.py @@ -7,68 +7,58 @@ import unittest import tarantool from .lib.tarantool_server import TarantoolServer +from .utils import assert_admin_success def create_server(): srv = TarantoolServer() srv.script = 'test/suites/box.lua' srv.start() - srv.admin("box.schema.user.create('test', {password = 'test', " - "if_not_exists = true})") - srv.admin("box.schema.user.grant('test', 'read,write,execute', 'universe')") - - # Create server_function (for testing purposes). - srv.admin(""" - function server_function() - x = {0,0} - while x[1] < 3 do - x[1] = x[1] + 1 - box.session.push(x) + resp = srv.admin(""" + box.schema.user.create('test', {password = 'test', if_not_exists = true}) + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) + + function server_function() + x = {0,0} + while x[1] < 3 do + x[1] = x[1] + 1 + box.session.push(x) + end + return x end - return x - end - """) - # Create tester space and on_replace trigger (for testing purposes). - srv.admin(""" - box.schema.create_space( - 'tester', { - format = { - {name = 'id', type = 'unsigned'}, - {name = 'name', type = 'string'}, - } - }) - """) - srv.admin(""" - box.space.tester:create_index( - 'primary_index', { - parts = { - {field = 1, type = 'unsigned'}, - } - }) - """) - srv.admin(""" - box.space.tester:create_index( - 'primary_index', { - parts = { - {field = 1, type = 'unsigned'}, - } - }) - """) - srv.admin(""" - function on_replace_callback() - x = {0,0} - while x[1] < 300 do - x[1] = x[1] + 100 - box.session.push(x) + box.schema.create_space( + 'tester', { + format = { + {name = 'id', type = 'unsigned'}, + {name = 'name', type = 'string'}, + } + }) + + box.space.tester:create_index( + 'primary_index', { + parts = { + {field = 1, type = 'unsigned'}, + }, + if_not_exists = true, + }) + + function on_replace_callback() + x = {0,0} + while x[1] < 300 do + x[1] = x[1] + 100 + box.session.push(x) + end end - end - """) - srv.admin(""" - box.space.tester:on_replace( - on_replace_callback - ) + + box.space.tester:on_replace( + on_replace_callback + ) + + return true """) + assert_admin_success(resp) return srv diff --git a/test/suites/test_schema.py b/test/suites/test_schema.py index 1402616d..6175c958 100644 --- a/test/suites/test_schema.py +++ b/test/suites/test_schema.py @@ -1,7 +1,7 @@ """ This module tests space and index schema fetch. """ -# pylint: disable=missing-class-docstring,missing-function-docstring,fixme,too-many-public-methods,too-many-branches,too-many-statements +# pylint: disable=missing-class-docstring,missing-function-docstring,fixme,too-many-public-methods,too-many-branches,too-many-statements,duplicate-code import sys import unittest @@ -12,6 +12,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_constraints_test +from .utils import assert_admin_success # FIXME: I'm quite sure that there is a simpler way to count @@ -54,29 +55,35 @@ def setUpClass(cls): cls.srv = TarantoolServer() cls.srv.script = 'test/suites/box.lua' cls.srv.start() - cls.srv.admin("box.schema.user.create('test', {password = 'test', if_not_exists = true})") - cls.srv.admin("box.schema.user.grant('test', 'read,write,execute', 'universe')") - - # Create server_function and tester space (for fetch_schema opt testing purposes). - cls.srv.admin("function server_function() return 2+2 end") - cls.srv.admin(""" - box.schema.create_space( - 'tester', { - format = { - {name = 'id', type = 'unsigned'}, - {name = 'name', type = 'string', is_nullable = true}, - } - }) - """) - cls.srv.admin(""" - box.space.tester:create_index( - 'primary_index', { - parts = { - {field = 1, type = 'unsigned'}, - } - }) + resp = cls.srv.admin(""" + box.schema.user.create('test', {password = 'test', if_not_exists = true}) + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) + + function server_function() return 2+2 end + + box.schema.create_space( + 'tester', { + format = { + {name = 'id', type = 'unsigned'}, + {name = 'name', type = 'string', is_nullable = true}, + }, + if_not_exists = true, + }) + + box.space.tester:create_index( + 'primary_index', { + parts = { + {field = 1, type = 'unsigned'}, + }, + if_not_exists = true, + }) + + box.space.tester:insert({1, null}) + + return true """) - cls.srv.admin("box.space.tester:insert({1, null})") + assert_admin_success(resp) cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary'], encoding=cls.encoding, user='test', password='test') @@ -112,31 +119,34 @@ def setUpClass(cls): """) if cls.srv.admin.tnt_version >= pkg_resources.parse_version('2.10.0'): - cls.srv.admin(""" - box.schema.create_space( - 'constr_tester_1', { - format = { - { name = 'id', type = 'unsigned' }, - { name = 'payload', type = 'number' }, - } - }) - box.space.constr_tester_1:create_index('I1', { parts = {'id'} }) - - box.space.constr_tester_1:replace({1, 999}) - - box.schema.create_space( - 'constr_tester_2', { - format = { - { name = 'id', type = 'unsigned' }, - { name = 'table1_id', type = 'unsigned', - foreign_key = { fk_video = { space = 'constr_tester_1', field = 'id' } }, - }, - { name = 'payload', type = 'number' }, - } - }) - box.space.constr_tester_2:create_index('I1', { parts = {'id'} }) - box.space.constr_tester_2:create_index('I2', { parts = {'table1_id'} }) + resp = cls.srv.admin(""" + box.schema.create_space( + 'constr_tester_1', { + format = { + { name = 'id', type = 'unsigned' }, + { name = 'payload', type = 'number' }, + } + }) + box.space.constr_tester_1:create_index('I1', { parts = {'id'} }) + + box.space.constr_tester_1:replace({1, 999}) + + box.schema.create_space( + 'constr_tester_2', { + format = { + { name = 'id', type = 'unsigned' }, + { name = 'table1_id', type = 'unsigned', + foreign_key = { fk_video = { space = 'constr_tester_1', field = 'id' } }, + }, + { name = 'payload', type = 'number' }, + } + }) + box.space.constr_tester_2:create_index('I1', { parts = {'id'} }) + box.space.constr_tester_2:create_index('I2', { parts = {'table1_id'} }) + + return true """) + assert_admin_success(resp) def setUp(self): # prevent a remote tarantool from clean our session @@ -603,10 +613,13 @@ def tearDownClass(cls): # We need to drop spaces with foreign keys with predetermined order, # otherwise remote server clean() will fail to clean up resources. if cls.srv.admin.tnt_version >= pkg_resources.parse_version('2.10.0'): - cls.srv.admin(""" - box.space.constr_tester_2:drop() - box.space.constr_tester_1:drop() + resp = cls.srv.admin(""" + box.space.constr_tester_2:drop() + box.space.constr_tester_1:drop() + + return true """) + assert_admin_success(resp) cls.con.close() cls.con_schema_disable.close() diff --git a/test/suites/test_uuid.py b/test/suites/test_uuid.py index 0a9ef06b..90943fcb 100644 --- a/test/suites/test_uuid.py +++ b/test/suites/test_uuid.py @@ -7,6 +7,7 @@ import unittest import uuid +import pkg_resources import msgpack import tarantool @@ -15,6 +16,7 @@ from .lib.tarantool_server import TarantoolServer from .lib.skip import skip_or_run_uuid_test +from .utils import assert_admin_success class TestSuiteUUID(unittest.TestCase): @@ -27,26 +29,35 @@ def setUpClass(cls): cls.srv.start() cls.adm = cls.srv.admin - cls.adm(r""" + resp = cls.adm(""" _, uuid = pcall(require, 'uuid') - box.schema.space.create('test') + box.schema.space.create('test', {if_not_exists = true}) box.space['test']:create_index('primary', { type = 'tree', parts = {1, 'string'}, - unique = true}) + unique = true, + if_not_exists = true}) - pcall(function() - box.schema.space.create('test_pk') + box.schema.user.create('test', {password = 'test', if_not_exists = true}) + box.schema.user.grant('test', 'read,write,execute', 'universe', + nil, {if_not_exists = true}) + + return true + """) + assert_admin_success(resp) + + if cls.srv.admin.tnt_version >= pkg_resources.parse_version('2.4.1'): + resp = cls.adm(""" + box.schema.space.create('test_pk', {if_not_exists = true}) box.space['test_pk']:create_index('primary', { type = 'tree', parts = {1, 'uuid'}, - unique = true}) - end) - - box.schema.user.create('test', {password = 'test', if_not_exists = true}) - box.schema.user.grant('test', 'read,write,execute', 'universe') - """) + unique = true, + if_not_exists = true}) + return true + """) + assert_admin_success(resp) cls.con = tarantool.Connection(cls.srv.host, cls.srv.args['primary'], user='test', password='test') @@ -56,7 +67,11 @@ def setUp(self): if self.srv.is_started(): self.srv.touch_lock() - self.adm("box.space['test']:truncate()") + resp = self.adm(""" + box.space['test']:truncate() + return true + """) + assert_admin_success(resp) cases = { 'uuid_1': { diff --git a/test/suites/utils.py b/test/suites/utils.py new file mode 100644 index 00000000..65e68b4c --- /dev/null +++ b/test/suites/utils.py @@ -0,0 +1,16 @@ +""" +Various test utilities. +""" + + +def assert_admin_success(resp): + """ + Util to assert admin text request response. + It is expected that request last line is `return true`. + If something went wrong on executing, Tarantool throws an error + which would be a part of return values. + """ + + assert isinstance(resp, list), f'got unexpected resp type: {type(resp)}' + assert len(resp) > 0, 'got unexpected empty resp' + assert resp[0] is True, f'got unexpected resp: {resp}' From a6db2d45ff5a156a9239e48ba3894bad19134450 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Tue, 8 Aug 2023 11:14:47 +0300 Subject: [PATCH 4/4] test: fix confusing tuple value `null` is a common variable in Lua. Since the variable is not declared and strict mode is off, it is essentially `nil`. --- test/suites/test_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suites/test_schema.py b/test/suites/test_schema.py index 6175c958..c90ddbff 100644 --- a/test/suites/test_schema.py +++ b/test/suites/test_schema.py @@ -79,7 +79,7 @@ def setUpClass(cls): if_not_exists = true, }) - box.space.tester:insert({1, null}) + box.space.tester:insert({1, nil}) return true """)