diff --git a/test/unit_tests/cli/conftest.py b/test/unit_tests/cli/conftest.py new file mode 100644 index 000000000..3c727c3dc --- /dev/null +++ b/test/unit_tests/cli/conftest.py @@ -0,0 +1,33 @@ +import sys +from functools import partial + +import pytest +from typer.testing import CliRunner + +from orchestrator.cli.database import app as db_app +from test.unit_tests.cli.helpers import create_main + + +@pytest.fixture(scope="module") +def monkey_module(): + with pytest.MonkeyPatch.context() as mp: + yield mp + + +@pytest.fixture(scope="module") +def tmp_generate_path(tmp_path_factory): + yield tmp_path_factory.mktemp("generate") + + +@pytest.fixture(scope="module") +def cli_invoke(tmp_generate_path, monkey_module): + monkey_module.chdir(tmp_generate_path) + sys.path.append(str(tmp_generate_path)) + create_main() + + runner = CliRunner() + # Don't catch exceptions because this will cost you grey hair. + invoke = partial(runner.invoke, catch_exceptions=False) + invoke(db_app, ["init"]) + + yield invoke diff --git a/test/unit_tests/cli/data/invalid_product_config1.yaml b/test/unit_tests/cli/data/invalid_product_config1.yaml new file mode 100644 index 000000000..8f5451eff --- /dev/null +++ b/test/unit_tests/cli/data/invalid_product_config1.yaml @@ -0,0 +1,20 @@ +# Testcase for invalid config: multiple root product blocks +config: + summary_forms: False +name: invalidexample1 +type: InvalidExample4 +tag: INVALIDEXAMPLE1 +description: "Invalid Product example 1" +product_blocks: + - name: block1 + type: Block1 + tag: BLOCK1 + fields: + - name: num_val + type: int + - name: block2 + type: Block2 + tag: BLOCK2 + fields: + - name: str_val + type: str diff --git a/test/unit_tests/cli/data/invalid_product_config2.yaml b/test/unit_tests/cli/data/invalid_product_config2.yaml new file mode 100644 index 000000000..1059b2b75 --- /dev/null +++ b/test/unit_tests/cli/data/invalid_product_config2.yaml @@ -0,0 +1,24 @@ +# Testcase for invalid config: cyclic product blocks +config: + summary_forms: False +name: invalidexample1 +type: InvalidExample4 +tag: INVALIDEXAMPLE1 +description: "Invalid Product example 1" +product_blocks: + - name: block1 + type: Block1 + tag: BLOCK1 + fields: + - name: num_val + type: int + - name: sub_block + type: Block2 + - name: block2 + type: Block2 + tag: BLOCK2 + fields: + - name: str_val + type: str + - name: sub_block + type: Block1 diff --git a/test/unit_tests/cli/helpers.py b/test/unit_tests/cli/helpers.py new file mode 100644 index 000000000..4f6977e4a --- /dev/null +++ b/test/unit_tests/cli/helpers.py @@ -0,0 +1,19 @@ +from pathlib import Path + + +def absolute_path(path: str) -> str: + file = Path(__file__).resolve().parent / "data" / path + return str(file) + + +def create_main(): + with open("main.py", "w") as fp: + fp.write( + "from orchestrator import OrchestratorCore\n" + "from orchestrator.cli.main import app as core_cli\n" + "from orchestrator.settings import AppSettings\n" + "\n" + "app = OrchestratorCore(base_settings=AppSettings())\n" + 'if __name__ == "__main__":\n' + " core_cli()\n" + ) diff --git a/test/unit_tests/cli/test_config_validation.py b/test/unit_tests/cli/test_config_validation.py new file mode 100644 index 000000000..b5e43f5a4 --- /dev/null +++ b/test/unit_tests/cli/test_config_validation.py @@ -0,0 +1,20 @@ +import pytest +import structlog + +from orchestrator.cli.generate import app as generate_app +from test.unit_tests.cli.helpers import absolute_path + +logger = structlog.get_logger() + + +@pytest.mark.parametrize( + "config_file,expected_exception,expected_message", + [ + ("invalid_product_config1.yaml", ValueError, "found multiple"), + ("invalid_product_config2.yaml", ValueError, "Cycle detected"), + ], +) +def test_product_block_validation(config_file, expected_exception, expected_message, cli_invoke): + config_file = absolute_path(config_file) + with pytest.raises(expected_exception, match=expected_message): + cli_invoke(generate_app, ["product-blocks", "--config-file", config_file]) diff --git a/test/unit_tests/cli/test_generate_code.py b/test/unit_tests/cli/test_generate_code.py index af2be0f5e..37d4906b6 100644 --- a/test/unit_tests/cli/test_generate_code.py +++ b/test/unit_tests/cli/test_generate_code.py @@ -1,66 +1,31 @@ import re -import sys from difflib import context_diff from filecmp import dircmp -from functools import partial from pathlib import Path import pytest import structlog from more_itertools import one -from typer.testing import CliRunner -from orchestrator.cli.database import app as db_app from orchestrator.cli.generate import app as generate_app +from test.unit_tests.cli.helpers import absolute_path logger = structlog.get_logger() -def absolute_path(path: str) -> str: - file = Path(__file__).resolve().parent / "data" / path - return str(file) - - -def create_main(): - with open("main.py", "w") as fp: - fp.write( - "from orchestrator import OrchestratorCore\n" - "from orchestrator.cli.main import app as core_cli\n" - "from orchestrator.settings import AppSettings\n" - "\n" - "app = OrchestratorCore(base_settings=AppSettings())\n" - 'if __name__ == "__main__":\n' - " core_cli()\n" - ) - - @pytest.fixture(scope="module") -def monkey_module(): - with pytest.MonkeyPatch.context() as mp: - yield mp - - -@pytest.fixture(scope="module") -def actual_folder(tmp_path_factory, monkey_module) -> Path: - tmp_path = tmp_path_factory.mktemp("generate") - monkey_module.chdir(tmp_path) - sys.path.append(str(tmp_path)) - create_main() - runner = CliRunner() - - # Don't catch exceptions because this will cost you grey hair. - invoke = partial(runner.invoke, catch_exceptions=False) - invoke(db_app, ["init"]) +def actual_folder(cli_invoke, tmp_generate_path) -> Path: for config_file in ( absolute_path("product_config2.yaml"), absolute_path("product_config1.yaml"), absolute_path("product_config4.yaml"), ): for cmd in ("product-blocks", "product", "workflows", "unit-tests"): - invoke(generate_app, [cmd, "--config-file", config_file, "--no-dryrun", "--force"]) + cli_invoke(generate_app, [cmd, "--config-file", config_file, "--no-dryrun", "--force"]) + + cli_invoke(generate_app, ["migration", "--config-file", config_file]) - invoke(generate_app, ["migration", "--config-file", config_file]) - return tmp_path + return tmp_generate_path @pytest.fixture(scope="module")