diff --git a/cratedb_toolkit/cfr/systable.py b/cratedb_toolkit/cfr/systable.py index 42665eed..b4a7b70b 100644 --- a/cratedb_toolkit/cfr/systable.py +++ b/cratedb_toolkit/cfr/systable.py @@ -91,13 +91,11 @@ def ddl(self, tablename_in: str, tablename_out: str, out_schema: str = None, wit class PathProvider: - def __init__(self, path: t.Union[Path]): self.path = path class Archive: - def __init__(self, path_provider: PathProvider): self.path_provider = path_provider self.temp_dir = tempfile.TemporaryDirectory() diff --git a/tests/conftest.py b/tests/conftest.py index a1d05df8..73787d3b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,8 @@ import pytest import responses +import sqlalchemy as sa +from verlib2 import Version from cratedb_toolkit.testing.testcontainers.cratedb import CrateDBTestAdapter from cratedb_toolkit.util.common import setup_logging @@ -114,4 +116,40 @@ def cloud_cluster_mock(): ) +IS_SQLALCHEMY1 = Version(sa.__version__) < Version("2") +IS_SQLALCHEMY2 = Version(sa.__version__) >= Version("2") + + +@pytest.fixture(scope="module") +def needs_sqlalchemy1_module(): + """ + Use this for annotating pytest test case functions testing subsystems which need SQLAlchemy 1.x. + """ + check_sqlalchemy1() + + +def check_sqlalchemy1(**kwargs): + """ + Skip pytest test cases or modules testing subsystems which need SQLAlchemy 1.x. + """ + if not IS_SQLALCHEMY1: + raise pytest.skip("This feature or subsystem needs SQLAlchemy 1.x", **kwargs) + + +@pytest.fixture +def needs_sqlalchemy2(): + """ + Use this for annotating pytest test case functions testing subsystems which need SQLAlchemy 2.x. + """ + check_sqlalchemy2() + + +def check_sqlalchemy2(**kwargs): + """ + Skip pytest test cases or modules testing subsystems which need SQLAlchemy 2.x. + """ + if not IS_SQLALCHEMY2: + raise pytest.skip("This feature or subsystem needs SQLAlchemy 2.x", **kwargs) + + setup_logging() diff --git a/tests/io/influxdb/test_cli.py b/tests/io/influxdb/test_cli.py index 63399310..1fa346c4 100644 --- a/tests/io/influxdb/test_cli.py +++ b/tests/io/influxdb/test_cli.py @@ -15,7 +15,7 @@ from influxio.adapter import InfluxDbApiAdapter -def test_influxdb2_load_table(caplog, cratedb, influxdb): +def test_influxdb2_load_table(caplog, cratedb, influxdb, needs_sqlalchemy2): """ CLI test: Invoke `ctk load table` for InfluxDB. """ diff --git a/tests/io/mongodb/conftest.py b/tests/io/mongodb/conftest.py index 5ff938eb..2361000e 100644 --- a/tests/io/mongodb/conftest.py +++ b/tests/io/mongodb/conftest.py @@ -2,6 +2,8 @@ import pytest +from tests.conftest import check_sqlalchemy2 + logger = logging.getLogger(__name__) @@ -53,6 +55,7 @@ def mongodb_service(): """ Provide an MongoDB service instance to the test suite. """ + check_sqlalchemy2() db = MongoDBFixture() db.reset() yield db diff --git a/tests/io/mongodb/test_cli.py b/tests/io/mongodb/test_cli.py index 11d42133..0398000f 100644 --- a/tests/io/mongodb/test_cli.py +++ b/tests/io/mongodb/test_cli.py @@ -5,6 +5,7 @@ from pueblo.testing.dataframe import DataFrameFactory from cratedb_toolkit.cli import cli +from tests.conftest import check_sqlalchemy2 pytestmark = pytest.mark.mongodb @@ -12,6 +13,14 @@ pytest.importorskip("rich", reason="Skipping tests because rich is not installed") +@pytest.fixture(scope="module", autouse=True) +def check_prerequisites(): + """ + This subsystem needs SQLAlchemy 2.x. + """ + check_sqlalchemy2() + + def test_version(): """ CLI test: Invoke `migr8 --version`. diff --git a/tests/io/mongodb/test_integration.py b/tests/io/mongodb/test_integration.py index 0515d5fd..7574e7d3 100644 --- a/tests/io/mongodb/test_integration.py +++ b/tests/io/mongodb/test_integration.py @@ -6,15 +6,24 @@ import pytest -from tests.io.mongodb.conftest import RESET_DATABASES +from tests.conftest import check_sqlalchemy2 pytestmark = pytest.mark.mongodb pymongo = pytest.importorskip("pymongo", reason="Skipping tests because pymongo is not installed") pytest.importorskip("rich", reason="Skipping tests because rich is not installed") -from cratedb_toolkit.io.mongodb.core import gather_collections + +@pytest.fixture(scope="module", autouse=True) +def check_prerequisites(): + """ + This subsystem needs SQLAlchemy 2.x. + """ + check_sqlalchemy2() + + from cratedb_toolkit.testing.testcontainers.mongodb import MongoDbContainerWithKeepalive +from tests.io.mongodb.conftest import RESET_DATABASES logger = logging.getLogger(__name__) @@ -65,6 +74,8 @@ def test_gather_collections(self): """ Verify if core method `gather_collections` works as expected. """ + from cratedb_toolkit.io.mongodb.core import gather_collections + self.db.create_collection("foobar") with mock.patch("builtins.input", return_value="unknown"): collections = gather_collections(database=self.db) diff --git a/tests/io/test_import.py b/tests/io/test_import.py index 9eeaa3d3..fa34566c 100644 --- a/tests/io/test_import.py +++ b/tests/io/test_import.py @@ -24,7 +24,7 @@ def test_import_csv_pandas(cratedb, dummy_csv): assert result == [(2,)] -def test_import_csv_dask(cratedb, dummy_csv): +def test_import_csv_dask(cratedb, dummy_csv, needs_sqlalchemy2): """ Invoke convenience function `import_csv_dask`, and verify database content. """ @@ -36,7 +36,7 @@ def test_import_csv_dask(cratedb, dummy_csv): assert result == [(2,)] -def test_import_csv_dask_with_progressbar(cratedb, dummy_csv): +def test_import_csv_dask_with_progressbar(cratedb, dummy_csv, needs_sqlalchemy2): """ Invoke convenience function `import_csv_dask`, and verify database content. This time, use `progress=True` to make Dask display a progress bar. diff --git a/tests/retention/conftest.py b/tests/retention/conftest.py index 8460adbe..5b3d5046 100644 --- a/tests/retention/conftest.py +++ b/tests/retention/conftest.py @@ -9,7 +9,7 @@ from cratedb_toolkit.testing.testcontainers.azurite import ExtendedAzuriteContainer from cratedb_toolkit.testing.testcontainers.minio import ExtendedMinioContainer from cratedb_toolkit.util.database import DatabaseAdapter, run_sql -from tests.conftest import TESTDRIVE_DATA_SCHEMA, TESTDRIVE_EXT_SCHEMA +from tests.conftest import TESTDRIVE_DATA_SCHEMA, TESTDRIVE_EXT_SCHEMA, check_sqlalchemy2 @pytest.fixture() @@ -26,6 +26,7 @@ def store(database, settings): Provide a client database adapter, which is connected to the test database instance. The retention policy database table schema has been established. """ + check_sqlalchemy2() setup_schema(settings=settings) rps = RetentionPolicyStore(settings=settings) yield rps diff --git a/tests/retention/test_cli.py b/tests/retention/test_cli.py index 01b7487c..f74bfb60 100644 --- a/tests/retention/test_cli.py +++ b/tests/retention/test_cli.py @@ -191,7 +191,7 @@ def test_run_delete_dryrun(caplog, store, database, raw_metrics, policies): assert database.count_records(raw_metrics) == 6 -def test_run_delete_with_tags_match(store, database, sensor_readings, policies): +def test_run_delete_with_tags_match(store, database, sensor_readings, policies, needs_sqlalchemy2): """ Verify a basic DELETE retention policy through the CLI, with using correct (matching) tags. """ @@ -214,7 +214,7 @@ def test_run_delete_with_tags_match(store, database, sensor_readings, policies): assert database.count_records(f'"{TESTDRIVE_DATA_SCHEMA}"."sensor_readings"') == 0 -def test_run_delete_with_tags_unknown(caplog, store, database, sensor_readings, policies): +def test_run_delete_with_tags_unknown(caplog, store, database, sensor_readings, policies, needs_sqlalchemy2): """ Verify a basic DELETE retention policy through the CLI, with using wrong (not matching) tags. """ @@ -266,7 +266,9 @@ def test_run_reallocate(store, database, raw_metrics, raw_metrics_reallocate_pol assert database.count_records(raw_metrics) == 6 -def test_run_snapshot_aws_s3(caplog, store, database, sensor_readings, sensor_readings_snapshot_policy, minio): +def test_run_snapshot_aws_s3( + caplog, store, database, sensor_readings, sensor_readings_snapshot_policy, minio, needs_sqlalchemy2 +): """ Verify the "SNAPSHOT" strategy using an object storage with AWS S3 API. Invokes `cratedb-retention run --strategy=snapshot`. diff --git a/tests/retention/test_examples.py b/tests/retention/test_examples.py index 95d2be8c..f6c4122c 100644 --- a/tests/retention/test_examples.py +++ b/tests/retention/test_examples.py @@ -5,7 +5,7 @@ import responses -def test_example_edit(store): +def test_example_edit(store, needs_sqlalchemy2): """ Verify that the program `examples/retention_edit.py` works. """ diff --git a/tests/retention/test_store.py b/tests/retention/test_store.py index f868ff2a..e146396b 100644 --- a/tests/retention/test_store.py +++ b/tests/retention/test_store.py @@ -84,7 +84,7 @@ def test_list_tags(store): assert tags == ["bar", "foo"] -def test_delete_by_tag(store): +def test_delete_by_tag(store, needs_sqlalchemy2): """ Verify deleting a retention policy by single tag. """ @@ -122,7 +122,7 @@ def test_delete_by_tag(store): assert len(store.retrieve()) == 1 -def test_delete_by_all_tags(store): +def test_delete_by_all_tags(store, needs_sqlalchemy2): """ Verify deleting a retention policy by multiple tags. @@ -178,7 +178,7 @@ def test_delete_unknown(caplog, store): assert "Retention policy not found with id: unknown" in caplog.messages -def test_delete_by_tag_unknown(caplog, store): +def test_delete_by_tag_unknown(caplog, store, needs_sqlalchemy2): """ Verify behavior when deleting items by unknown tag """ @@ -194,7 +194,7 @@ def test_delete_by_tag_unknown(caplog, store): assert "No retention policies found with tags: ['unknown']" in caplog.messages -def test_delete_by_all_tags_unknown(caplog, store): +def test_delete_by_all_tags_unknown(caplog, store, needs_sqlalchemy2): """ Verify behavior when deleting items by unknown tag """ diff --git a/tests/sqlalchemy/test_patch.py b/tests/sqlalchemy/test_patch.py index 3eb9ab70..d6539869 100644 --- a/tests/sqlalchemy/test_patch.py +++ b/tests/sqlalchemy/test_patch.py @@ -8,7 +8,7 @@ from tests.conftest import TESTDRIVE_DATA_SCHEMA -def test_inspector_vanilla(database): +def test_inspector_vanilla(database, needs_sqlalchemy2): """ Vanilla SQLAlchemy Inspector tests. """ @@ -28,7 +28,7 @@ def test_inspector_vanilla(database): assert indexes == [] -def test_inspector_patched(database): +def test_inspector_patched(database, needs_sqlalchemy2): """ Patched SQLAlchemy Inspector tests. diff --git a/tests/sqlalchemy/test_polyfill.py b/tests/sqlalchemy/test_polyfill.py index 74ae6ef7..50c57f90 100644 --- a/tests/sqlalchemy/test_polyfill.py +++ b/tests/sqlalchemy/test_polyfill.py @@ -62,7 +62,7 @@ class FooBarComposite(Base): return FooBarComposite -def test_autoincrement_vanilla(database): +def test_autoincrement_vanilla(database, needs_sqlalchemy2): """ When using a model including an autoincrement column, and not assigning a value, CrateDB will fail. """ @@ -77,7 +77,7 @@ def test_autoincrement_vanilla(database): ) -def test_autoincrement_polyfill(database): +def test_autoincrement_polyfill(database, needs_sqlalchemy2): """ When using a model including an autoincrement column, and the corresponding polyfill is installed, the procedure will succeed. diff --git a/tests/testing/test_cratedb_sqlalchemy.py b/tests/testing/test_cratedb_sqlalchemy.py index 81792cb8..46db0d32 100644 --- a/tests/testing/test_cratedb_sqlalchemy.py +++ b/tests/testing/test_cratedb_sqlalchemy.py @@ -5,7 +5,7 @@ from tests.conftest import TESTDRIVE_DATA_SCHEMA -def test_cratedb_summits(cratedb): +def test_cratedb_summits(cratedb, needs_sqlalchemy2): """ Just to verify communication with CrateDB works. """ @@ -22,7 +22,7 @@ def test_cratedb_summits(cratedb): ] -def test_database_insert(cratedb): +def test_database_insert(cratedb, needs_sqlalchemy2): """ Verify that inserting two records and reading them back works well. """