From 58b0aef05a33417832dae0e3ed85a1b5b0f82379 Mon Sep 17 00:00:00 2001 From: Vitaly Samigullin Date: Tue, 21 Nov 2023 22:40:26 +0100 Subject: [PATCH] Use testcontainers for integration testing --- setup.py | 4 +- tests/test_integration.py | 77 ++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/setup.py b/setup.py index ef9fc98b..12e4dc1b 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,9 @@ def read(path): extras_require=dict( test=[ 'crate[test]', - 'zc.customdoctests<2' + 'zc.customdoctests<2', + # FIXME once tested and merged, fix the name + 'cratedb-toolkit[test] @ git+https://github.com/pilosus/cratedb-toolkit@tech/18-adapt-testcontainers-to-unittest', ], devel=[ 'coverage<8', diff --git a/tests/test_integration.py b/tests/test_integration.py index 85244504..aea932d1 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1,3 +1,4 @@ +import logging import os import ssl import sys @@ -7,6 +8,9 @@ from unittest import SkipTest, TestCase from unittest.mock import Mock, patch +import sqlalchemy as sa +from cratedb_toolkit.testing.testcontainers.cratedb import CrateDBFixture, TestDrive +from cratedb_toolkit.util.common import setup_logging from urllib3.exceptions import LocationParseError from crate.client.exceptions import ProgrammingError @@ -22,36 +26,61 @@ from crate.crash.commands import Command from crate.crash.outputs import _val_len as val_len from crate.crash.printer import ColorPrinter -from crate.testing.layer import CrateLayer from tests import ftouch if sys.platform != "linux": raise SkipTest("Integration tests only supported on Linux") -crate_version = os.getenv("CRATEDB_VERSION", "5.5.0") -crate_http_port = 44209 -crate_transport_port = 44309 -crate_settings = { - 'cluster.name': 'Testing44209', - 'node.name': 'crate', - 'psql.port': 45441, - 'lang.js.enabled': True, - 'http.port': crate_http_port, - 'transport.tcp.port': crate_transport_port -} -node = CrateLayer.from_uri( - f'https://cdn.crate.io/downloads/releases/cratedb/x64_linux/crate-{crate_version}.tar.gz', - 'crate', - settings=crate_settings -) +class EntrypointOpts: + version = os.getenv("CRATEDB_VERSION", "5.4.5") + psql_port = 45441 + http_port = 44209 + transport_port = 44309 + settings = { + "cluster.name": "Testing44209", + "node.name": "crate", + "lang.js.enabled": True, + "psql.port": psql_port, + "http.port": http_port, + "transport.tcp.port": transport_port, + } + + +node = CrateDBFixture(crate_version=EntrypointOpts.version) def setUpModule(): - node.start() + node.setup(cmd_opts=EntrypointOpts.settings, port=EntrypointOpts.http_port) + node.reset() def tearDownModule(): - node.stop() + node.finalize() + +@patch.dict("os.environ", {"CRATEDB_EXT_SCHEMA": TestDrive.EXT_SCHEMA}) +class MyTest(TestCase): + def setUp(self): + node.reset() + + def test_conn_url(self): + http_url = node.http_url + self.assertIn("localhost", http_url) + + def test_cratedb_summits(self): + """ + Just to verify communication with CrateDB works. + """ + database_url = node.get_connection_url() + + sa_engine = sa.create_engine(database_url) + with sa_engine.connect() as conn: + sql = "SELECT mountain, region, prominence FROM sys.summits ORDER BY prominence DESC LIMIT 3;" + with conn.execute(sa.text(sql)) as result: + self.assertEqual(result.fetchall(), [ + ("Mont Blanc", "Mont Blanc massif", 4695), + ("Großglockner", "Glockner Group", 2428), + ("Finsteraarhorn", "Bernese Alps", 2280), + ]) def fake_stdin(data): @@ -61,7 +90,6 @@ def fake_stdin(data): stdin.seek(0) return stdin - class RaiseOnceSideEffect: """ A callable class used for mock side_effect. @@ -92,6 +120,8 @@ def test_connect(self): class CommandTest(TestCase): + def setUp(self): + node.reset() def _output_format(self, format, func, query="select name from sys.cluster"): orig_argv = sys.argv[:] @@ -286,7 +316,7 @@ def test_multiple_hosts(self): output = output.getvalue() lines = output.split('\n') self.assertRegex(lines[3], r'^\| http://[\d\.:]+ .*\| NULL .*\| FALSE .*\| Server not available') - self.assertRegex(lines[4], r'^\| http://[\d\.:]+. *\| crate .*\| TRUE .*\| OK') + self.assertRegex(lines[4], r'^\| http://.*@?localhost:\d+ *\| crate .*\| TRUE .*\| OK') finally: try: os.remove(tmphistory) @@ -699,7 +729,7 @@ def test_command_timeout(self): timeout=timeout) as crash: crash.logger = Mock() crash.process(slow_query) - crash.logger.warn.assert_any_call("No more Servers available, exception from last server: HTTPConnectionPool(host='127.0.0.1', port=44209): Read timed out. (read timeout=0.1)") + crash.logger.warn.assert_any_call("No more Servers available, exception from last server: HTTPConnectionPool(host='localhost', port=44209): Read timed out. (read timeout=0.1)") crash.logger.warn.assert_any_call("Use \\connect to connect to one or more servers first.") def test_username_param(self): @@ -831,3 +861,6 @@ def test_connect_info_not_available(self, is_conn_available): schema='test') as crash: self.assertEqual(crash.connect_info.user, None) self.assertEqual(crash.connect_info.schema, None) + + +setup_logging(level=logging.INFO)