From 30c35eee1b888b2b4f85a17e6aabf7e4d64b1860 Mon Sep 17 00:00:00 2001 From: Sophia Castellarin Date: Wed, 30 Oct 2024 13:04:06 -0700 Subject: [PATCH] Add tests - storage + worker (#926) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../tests/_internal/worker/__init__.py | 3 + .../tests/_internal/worker/test_app.py | 89 ++++++++++++ conda-store-server/tests/conftest.py | 1 + conda-store-server/tests/test_storage.py | 130 ++++++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 conda-store-server/tests/_internal/worker/__init__.py create mode 100644 conda-store-server/tests/_internal/worker/test_app.py create mode 100644 conda-store-server/tests/test_storage.py diff --git a/conda-store-server/tests/_internal/worker/__init__.py b/conda-store-server/tests/_internal/worker/__init__.py new file mode 100644 index 000000000..b559bd2ff --- /dev/null +++ b/conda-store-server/tests/_internal/worker/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) conda-store development team. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. diff --git a/conda-store-server/tests/_internal/worker/test_app.py b/conda-store-server/tests/_internal/worker/test_app.py new file mode 100644 index 000000000..a1c2b6adb --- /dev/null +++ b/conda-store-server/tests/_internal/worker/test_app.py @@ -0,0 +1,89 @@ +# Copyright (c) conda-store development team. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +import logging +import sys + +from unittest.mock import patch + +import pytest + +from traitlets.config import Config + +from conda_store_server._internal.worker.app import CondaStoreWorker + + +class MockCeleryApp: + def worker_main(argv): + pass + + +@pytest.mark.skipif( + sys.platform == "win32", reason="celery beat is not supported on windows" +) +@patch("conda_store_server.app.CondaStore.celery_app") +def test_start_worker(mock_celery_app, conda_store_config): + """Test that the celery worker is started with the right arguments""" + mock_celery_app.return_value = MockCeleryApp() + conda_store_config["CondaStoreWorker"] = Config( + dict( + log_level=logging.WARN, + watch_paths=["/opt/environments"], + concurrency=4, + ) + ) + worker = CondaStoreWorker(config=conda_store_config) + worker.initialize() + worker.start() + mock_celery_app.worker_main.assert_called_with( + [ + "worker", + "--loglevel=WARNING", + "--max-tasks-per-child=10", + "--beat", + "--concurrency=4", + ] + ) + + +def test_initialize_worker_with_valid_config_file(conda_store_config, tmp_path): + """Test that a worker is able to init when the provided config file exists""" + config_file_contents = """ +import logging +c.CondaStoreWorker.log_level = logging.INFO +c.CondaStoreWorker.watch_paths = ["/opt/environments"] +c.CondaStoreWorker.concurrency = 4 +""" + test_config_file = str(tmp_path / "config1") + with open(test_config_file, "w") as file: + file.write(config_file_contents) + + worker = CondaStoreWorker(config=conda_store_config) + worker.config_file = test_config_file + worker.initialize() + + +def test_initialize_worker_with_invalid_config(conda_store_config): + """Test that a worker is not able to init if the provided config file does not exist""" + worker = CondaStoreWorker(config=conda_store_config) + with pytest.raises(SystemExit) as exc_info: + worker.config_file = "/i/dont/exist" + worker.initialize() + + assert exc_info.value.code == 1 + + +@pytest.mark.parametrize( + "logging_level,output", + [ + (logging.INFO, "INFO"), + (logging.CRITICAL, "CRITICAL"), + (logging.FATAL, "CRITICAL"), + (logging.WARN, "WARNING"), + ], +) +def test_logger_to_celery_logging_level(logging_level, output): + worker = CondaStoreWorker() + celery_logging_level = worker.logger_to_celery_logging_level(logging_level) + assert celery_logging_level == output diff --git a/conda-store-server/tests/conftest.py b/conda-store-server/tests/conftest.py index a3aba05e9..7cd98d462 100644 --- a/conda-store-server/tests/conftest.py +++ b/conda-store-server/tests/conftest.py @@ -162,6 +162,7 @@ def seed_conda_store(db, conda_store): build.ended_on = datetime.datetime.utcnow() build.status = schema.BuildStatus.COMPLETED db.commit() + yield db @pytest.fixture diff --git a/conda-store-server/tests/test_storage.py b/conda-store-server/tests/test_storage.py new file mode 100644 index 000000000..1dd3e3a5e --- /dev/null +++ b/conda-store-server/tests/test_storage.py @@ -0,0 +1,130 @@ +import os + +import pytest + +from conda_store_server import api, storage +from conda_store_server._internal import schema + + +@pytest.fixture() +def local_file_store(tmp_path): + """Setup a tmp dir with 2 test files and a logs dir""" + tf_one = str(tmp_path / "testfile1") + with open(tf_one, "w") as file: + file.write("testfile1") + + tf_two = str(tmp_path / "testfile2") + with open(tf_two, "w") as file: + file.write("testfile2") + + logs_path = tmp_path / "logs" + os.mkdir(logs_path) + + yield tmp_path + + +class TestStorage: + def test_fset_new_package(self, db): + store = storage.Storage() + store.fset(db, 123, "new_build_key", "", schema.BuildArtifactType.YAML) + assert len(api.list_build_artifacts(db).all()) == 1 + + def test_fset_existing_package(self, seed_conda_store): + store = storage.Storage() + db = seed_conda_store + + inital_artifacts = api.list_build_artifacts(db).all() + artifact = inital_artifacts[0] + + store.fset(db, artifact.build_id, artifact.key, "", artifact.artifact_type) + assert len(api.list_build_artifacts(db).all()) == len(inital_artifacts) + + def test_delete_existing_artifact(self, seed_conda_store): + store = storage.Storage() + db = seed_conda_store + + inital_artifacts = api.list_build_artifacts(db).all() + artifact = inital_artifacts[0] + + store.delete(db, artifact.build_id, artifact.key) + assert len(api.list_build_artifacts(db).all()) == len(inital_artifacts) - 1 + + +class TestLocalStorage: + def test_fset_new_package(self, db, local_file_store): + store = storage.LocalStorage() + store.storage_path = local_file_store + + filename = str(local_file_store / "testfile1") + store.fset( + db, + 123, + "new_build_key", + filename, + "contenttype", + schema.BuildArtifactType.YAML, + ) + assert len(api.list_build_artifacts(db).all()) == 1 + + target_file = str(local_file_store / "new_build_key") + assert os.path.exists(target_file) + target_content = open(target_file, "r").read() + assert target_content == "testfile1" + + def test_fset_dont_overwrite_file(self, db, local_file_store): + store = storage.LocalStorage() + store.storage_path = local_file_store + + filename = str(local_file_store / "testfile1") + store.fset( + db, 123, "testfile2", filename, "contenttype", schema.BuildArtifactType.YAML + ) + assert len(api.list_build_artifacts(db).all()) == 1 + + target_file = str(local_file_store / "testfile2") + assert os.path.exists(target_file) + target_content = open(target_file, "r").read() + assert target_content == "testfile1" + + def test_set_new_package(self, db, local_file_store): + store = storage.LocalStorage() + store.storage_path = local_file_store + + store.set( + db, + 123, + "new_build_key", + b"somestuff", + "contenttype", + schema.BuildArtifactType.YAML, + ) + assert len(api.list_build_artifacts(db).all()) == 1 + + target_file = str(local_file_store / "new_build_key") + assert os.path.exists(target_file) + target_content = open(target_file, "r").read() + assert target_content == "somestuff" + + def test_get(self, local_file_store): + store = storage.LocalStorage() + store.storage_path = local_file_store + + content = store.get("testfile1") + assert content == b"testfile1" + + def test_delete(self, seed_conda_store, local_file_store): + store = storage.LocalStorage() + store.storage_path = local_file_store + db = seed_conda_store + + inital_artifacts = api.list_build_artifacts(db).all() + artifact = inital_artifacts[0] + target_file = str(local_file_store / artifact.key) + + with open(target_file, "w") as file: + file.write("testfile2") + + store.delete(db, artifact.build_id, artifact.key) + assert len(api.list_build_artifacts(db).all()) == len(inital_artifacts) - 1 + + assert not os.path.exists(target_file)