From d8378977cf60f5237d2980f8c6e96e4fad8dcf14 Mon Sep 17 00:00:00 2001 From: Mark90 Date: Fri, 7 Jun 2024 13:52:01 +0200 Subject: [PATCH] Add generator testcase for a product with a nested product block Signed-off-by: Mark90 --- test/unit_tests/cli/data/generate.sh | 2 +- .../2024-06-07_380a5b0c928c_add_example4.py | 101 ++++++++++++++++++ .../cli/data/generate/products/__init__.py | 7 ++ .../products/product_blocks/example4.py | 26 +++++ .../products/product_blocks/example4sub.py | 21 ++++ .../products/product_types/example4.py | 16 +++ .../domain/product_types/test_example4.py | 53 +++++++++ .../example4/test_create_example4.py | 32 ++++++ .../example4/test_modify_example4.py | 33 ++++++ .../example4/test_terminate_example4.py | 26 +++++ .../example4/test_validate_example4.py | 16 +++ .../cli/data/generate/translations/en-GB.json | 6 +- .../cli/data/generate/workflows/__init__.py | 4 + .../workflows/example4/create_example4.py | 77 +++++++++++++ .../workflows/example4/modify_example4.py | 70 ++++++++++++ .../workflows/example4/shared/forms.py | 1 + .../workflows/example4/terminate_example4.py | 39 +++++++ test/unit_tests/cli/data/product_config4.yaml | 32 ++++++ test/unit_tests/cli/test_generate_code.py | 17 ++- 19 files changed, 573 insertions(+), 6 deletions(-) create mode 100644 test/unit_tests/cli/data/generate/migrations/versions/schema/2024-06-07_380a5b0c928c_add_example4.py create mode 100644 test/unit_tests/cli/data/generate/products/product_blocks/example4.py create mode 100644 test/unit_tests/cli/data/generate/products/product_blocks/example4sub.py create mode 100644 test/unit_tests/cli/data/generate/products/product_types/example4.py create mode 100644 test/unit_tests/cli/data/generate/test/unit_tests/domain/product_types/test_example4.py create mode 100644 test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_create_example4.py create mode 100644 test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_modify_example4.py create mode 100644 test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_terminate_example4.py create mode 100644 test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_validate_example4.py create mode 100644 test/unit_tests/cli/data/generate/workflows/example4/create_example4.py create mode 100644 test/unit_tests/cli/data/generate/workflows/example4/modify_example4.py create mode 100644 test/unit_tests/cli/data/generate/workflows/example4/shared/forms.py create mode 100644 test/unit_tests/cli/data/generate/workflows/example4/terminate_example4.py create mode 100644 test/unit_tests/cli/data/product_config4.yaml diff --git a/test/unit_tests/cli/data/generate.sh b/test/unit_tests/cli/data/generate.sh index 065644903..7cb63e60a 100644 --- a/test/unit_tests/cli/data/generate.sh +++ b/test/unit_tests/cli/data/generate.sh @@ -15,7 +15,7 @@ export PYTHONPATH=../../../../.. python main.py db init # generate code for the two sample products -for YAML in ../product_config2.yaml ../product_config1.yaml +for YAML in ../product_config2.yaml ../product_config1.yaml ../product_config4.yaml do python main.py generate product-blocks --config-file $YAML --no-dryrun --force python main.py generate product --config-file $YAML --no-dryrun --force diff --git a/test/unit_tests/cli/data/generate/migrations/versions/schema/2024-06-07_380a5b0c928c_add_example4.py b/test/unit_tests/cli/data/generate/migrations/versions/schema/2024-06-07_380a5b0c928c_add_example4.py new file mode 100644 index 000000000..fa8e0f51a --- /dev/null +++ b/test/unit_tests/cli/data/generate/migrations/versions/schema/2024-06-07_380a5b0c928c_add_example4.py @@ -0,0 +1,101 @@ +"""Add example4 product. + +Revision ID: 380a5b0c928c +Revises: 44667c4d16cd +Create Date: 2024-06-07 10:23:26.761903 + +""" + +from uuid import uuid4 + +from alembic import op +from orchestrator.migrations.helpers import create, create_workflow, delete, delete_workflow, ensure_default_workflows +from orchestrator.targets import Target + +# revision identifiers, used by Alembic. +revision = "380a5b0c928c" +down_revision = "ea9e6c9de75c" +branch_labels = None +depends_on = None + +new_products = { + "products": { + "example4": { + "product_id": uuid4(), + "product_type": "Example4", + "description": "Product example 4", + "tag": "EXAMPLE4", + "status": "active", + "root_product_block": "Example4", + "fixed_inputs": {}, + }, + }, + "product_blocks": { + "Example4Sub": { + "product_block_id": uuid4(), + "description": "example 4 sub product block", + "tag": "EXAMPLE4SUB", + "status": "active", + "resources": { + "str_val": "", + }, + "depends_on_block_relations": [], + }, + "Example4": { + "product_block_id": uuid4(), + "description": "Example 4 root product block", + "tag": "EXAMPLE4", + "status": "active", + "resources": { + "num_val": "", + }, + "depends_on_block_relations": [ + "Example4Sub", + ], + }, + }, + "workflows": {}, +} + +new_workflows = [ + { + "name": "create_example4", + "target": Target.CREATE, + "description": "Create example4", + "product_type": "Example4", + }, + { + "name": "modify_example4", + "target": Target.MODIFY, + "description": "Modify example4", + "product_type": "Example4", + }, + { + "name": "terminate_example4", + "target": Target.TERMINATE, + "description": "Terminate example4", + "product_type": "Example4", + }, + { + "name": "validate_example4", + "target": Target.SYSTEM, + "description": "Validate example4", + "product_type": "Example4", + }, +] + + +def upgrade() -> None: + conn = op.get_bind() + create(conn, new_products) + for workflow in new_workflows: + create_workflow(conn, workflow) + ensure_default_workflows(conn) + + +def downgrade() -> None: + conn = op.get_bind() + for workflow in new_workflows: + delete_workflow(conn, workflow["name"]) + + delete(conn, new_products) diff --git a/test/unit_tests/cli/data/generate/products/__init__.py b/test/unit_tests/cli/data/generate/products/__init__.py index 9b754e195..f54671141 100644 --- a/test/unit_tests/cli/data/generate/products/__init__.py +++ b/test/unit_tests/cli/data/generate/products/__init__.py @@ -17,3 +17,10 @@ "example1 1000": Example1, }, ) # fmt:skip +from products.product_types.example4 import Example4 + +SUBSCRIPTION_MODEL_REGISTRY.update( + { + "example4": Example4, + }, +) # fmt:skip diff --git a/test/unit_tests/cli/data/generate/products/product_blocks/example4.py b/test/unit_tests/cli/data/generate/products/product_blocks/example4.py new file mode 100644 index 000000000..99b389328 --- /dev/null +++ b/test/unit_tests/cli/data/generate/products/product_blocks/example4.py @@ -0,0 +1,26 @@ +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle +from pydantic import computed_field + +from products.product_blocks.example4sub import Example4SubBlock, Example4SubBlockInactive, Example4SubBlockProvisioning + + +class Example4BlockInactive(ProductBlockModel, product_block_name="Example4"): + num_val: int | None = None + sub_block: Example4SubBlockInactive | None = None + + +class Example4BlockProvisioning(Example4BlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + num_val: int | None = None + sub_block: Example4SubBlockProvisioning + + @computed_field + @property + def title(self) -> str: + # TODO: format correct title string + return f"{self.name}" + + +class Example4Block(Example4BlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + num_val: int | None = None + sub_block: Example4SubBlock diff --git a/test/unit_tests/cli/data/generate/products/product_blocks/example4sub.py b/test/unit_tests/cli/data/generate/products/product_blocks/example4sub.py new file mode 100644 index 000000000..ce943a38e --- /dev/null +++ b/test/unit_tests/cli/data/generate/products/product_blocks/example4sub.py @@ -0,0 +1,21 @@ +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle +from pydantic import computed_field + + +class Example4SubBlockInactive(ProductBlockModel, product_block_name="Example4 Sub"): + str_val: str | None = None + + +class Example4SubBlockProvisioning(Example4SubBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + str_val: str | None = None + + @computed_field + @property + def title(self) -> str: + # TODO: format correct title string + return f"{self.name}" + + +class Example4SubBlock(Example4SubBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + str_val: str | None = None diff --git a/test/unit_tests/cli/data/generate/products/product_types/example4.py b/test/unit_tests/cli/data/generate/products/product_types/example4.py new file mode 100644 index 000000000..1c1381c36 --- /dev/null +++ b/test/unit_tests/cli/data/generate/products/product_types/example4.py @@ -0,0 +1,16 @@ +from orchestrator.domain.base import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from products.product_blocks.example4 import Example4Block, Example4BlockInactive, Example4BlockProvisioning + + +class Example4Inactive(SubscriptionModel, is_base=True): + example4: Example4BlockInactive + + +class Example4Provisioning(Example4Inactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + example4: Example4BlockProvisioning + + +class Example4(Example4Provisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + example4: Example4Block diff --git a/test/unit_tests/cli/data/generate/test/unit_tests/domain/product_types/test_example4.py b/test/unit_tests/cli/data/generate/test/unit_tests/domain/product_types/test_example4.py new file mode 100644 index 000000000..c888581ec --- /dev/null +++ b/test/unit_tests/cli/data/generate/test/unit_tests/domain/product_types/test_example4.py @@ -0,0 +1,53 @@ +from uuid import uuid4 + +from orchestrator.db import ProductTable, db +from orchestrator.types import SubscriptionLifecycle + +from products.product_types.example4 import Example4, Example4Inactive + + +def test_example4_new(): + product = ProductTable.query.filter(ProductTable.name == "example4").one() + + diff = Example4.diff_product_in_database(product.product_id) + assert diff == {} + + example4 = Example4Inactive.from_product_id( + product_id=product.product_id, + customer_id=uuid4(), + status=SubscriptionLifecycle.INITIAL, + ) + + assert example4.subscription_id is not None + assert example4.insync is False + + # TODO: Add more product specific asserts + + assert example4.description == f"Initial subscription of {product.description}" + example4.save() + + example42 = Example4Inactive.from_subscription(example4.subscription_id) + assert example4 == example42 + + +def test_example4_load_and_save_db(example4_subscription): + example4 = Example4.from_subscription(example4_subscription) + + assert example4.insync is True + + # TODO: Add more product specific asserts + + example4.description = "Changed description" + + # TODO: add a product specific change + + example4.save() + + # Explicit commit here as we are not running in the context of a step + db.session.commit() + + example4 = Example4.from_subscription(example4_subscription) + + # TODO: Add more product specific asserts + + assert example4.description == "Changed description" diff --git a/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_create_example4.py b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_create_example4.py new file mode 100644 index 000000000..ad60cd55b --- /dev/null +++ b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_create_example4.py @@ -0,0 +1,32 @@ +import pytest +from orchestrator.db import ProductTable + +from products.product_types.example4 import Example4 +from test.unit_tests.workflows import assert_complete, extract_state, run_workflow + + +@pytest.mark.workflow() +def test_happy_flow(responses): + # given + + # TODO insert additional mocks, if needed (ImsMocks) + + product = db.session.scalars(select(ProductTable).where(ProductTable.name == "example4")).one() + + # when + + init_state = { + "customer_id": customer_id, + # TODO add initial state + } + + result, process, step_log = run_workflow("create_example4", [{"product": product.product_id}, init_state]) + + # then + + assert_complete(result) + state = extract_state(result) + + subscription = Example4.from_subscription(state["subscription_id"]) + assert subscription.status == "active" + assert subscription.description == "TODO add correct description" diff --git a/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_modify_example4.py b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_modify_example4.py new file mode 100644 index 000000000..c1f32b837 --- /dev/null +++ b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_modify_example4.py @@ -0,0 +1,33 @@ +import pytest +from orchestrator.types import SubscriptionLifecycle + +from products.product_types.example4 import Example4 +from test.unit_tests.workflows import assert_complete, extract_state, run_workflow + + +@pytest.mark.workflow() +def test_happy_flow(responses, example4_subscription): + # given + + customer_id = "3f4fc287-0911-e511-80d0-005056956c1a" + crm = CrmMocks(responses) + crm.get_customer_by_uuid(customer_id) + + # TODO insert additional mocks, if needed (ImsMocks) + + # when + + init_state = {} + + result, process, step_log = run_workflow( + "modify_example4", + [{"subscription_id": example4_subscription}, init_state, {}], + ) + + # then + + assert_complete(result) + state = extract_state(result) + + example4 = Example4.from_subscription(state["subscription_id"]) + assert example4.status == SubscriptionLifecycle.ACTIVE diff --git a/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_terminate_example4.py b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_terminate_example4.py new file mode 100644 index 000000000..c3e28c970 --- /dev/null +++ b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_terminate_example4.py @@ -0,0 +1,26 @@ +import pytest +from orchestrator.types import SubscriptionLifecycle + +from products.product_types.example4 import Example4 +from test.unit_tests.workflows import assert_complete, extract_state, run_workflow + + +@pytest.mark.workflow() +def test_happy_flow(responses, example4_subscription): + # when + + # TODO: insert mocks here if needed + + result, _, _ = run_workflow("terminate_example4", [{"subscription_id": example4_subscription}, {}]) + + # then + + assert_complete(result) + state = extract_state(result) + assert "subscription" in state + + # Check subscription in DB + + example4 = Example4.from_subscription(example4_subscription) + assert example4.end_date is not None + assert example4.status == SubscriptionLifecycle.TERMINATED diff --git a/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_validate_example4.py b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_validate_example4.py new file mode 100644 index 000000000..761e6f8d0 --- /dev/null +++ b/test/unit_tests/cli/data/generate/test/unit_tests/workflows/example4/test_validate_example4.py @@ -0,0 +1,16 @@ +import pytest + +from test.unit_tests.workflows import assert_complete, extract_state, run_workflow + + +@pytest.mark.workflow() +def test_happy_flow(responses, example4_subscription): + # when + + result, _, _ = run_workflow("validate_example4", {"subscription_id": example4_subscription}) + + # then + + assert_complete(result) + state = extract_state(result) + assert state["check_core_db"] is True diff --git a/test/unit_tests/cli/data/generate/translations/en-GB.json b/test/unit_tests/cli/data/generate/translations/en-GB.json index 46558a16e..ed05d39e5 100644 --- a/test/unit_tests/cli/data/generate/translations/en-GB.json +++ b/test/unit_tests/cli/data/generate/translations/en-GB.json @@ -2,11 +2,15 @@ "workflow": { "create_example1": "Create example1", "create_example2": "Create example2", + "create_example4": "Create example4", "modify_example1": "Modify example1", "modify_example2": "Modify example2", + "modify_example4": "Modify example4", "terminate_example1": "Terminate example1", "terminate_example2": "Terminate example2", + "terminate_example4": "Terminate example4", "validate_example1": "Validate example1", - "validate_example2": "Validate example2" + "validate_example2": "Validate example2", + "validate_example4": "Validate example4" } } diff --git a/test/unit_tests/cli/data/generate/workflows/__init__.py b/test/unit_tests/cli/data/generate/workflows/__init__.py index 15d4895c6..6578e9470 100644 --- a/test/unit_tests/cli/data/generate/workflows/__init__.py +++ b/test/unit_tests/cli/data/generate/workflows/__init__.py @@ -8,3 +8,7 @@ LazyWorkflowInstance("workflows.example1.modify_example1", "modify_example1") LazyWorkflowInstance("workflows.example1.terminate_example1", "terminate_example1") LazyWorkflowInstance("workflows.example1.validate_example1", "validate_example1") +LazyWorkflowInstance("workflows.example4.create_example4", "create_example4") +LazyWorkflowInstance("workflows.example4.modify_example4", "modify_example4") +LazyWorkflowInstance("workflows.example4.terminate_example4", "terminate_example4") +LazyWorkflowInstance("workflows.example4.validate_example4", "validate_example4") diff --git a/test/unit_tests/cli/data/generate/workflows/example4/create_example4.py b/test/unit_tests/cli/data/generate/workflows/example4/create_example4.py new file mode 100644 index 000000000..c34e39da2 --- /dev/null +++ b/test/unit_tests/cli/data/generate/workflows/example4/create_example4.py @@ -0,0 +1,77 @@ +import structlog +from orchestrator.domain import SubscriptionModel +from orchestrator.forms import FormPage +from orchestrator.forms.validators import CustomerId, Divider, Label +from orchestrator.targets import Target +from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr +from orchestrator.workflow import StepList, begin, step +from orchestrator.workflows.steps import store_process_subscription +from orchestrator.workflows.utils import create_workflow +from pydantic import ConfigDict + +from products.product_types.example4 import Example4Inactive, Example4Provisioning + + +def subscription_description(subscription: SubscriptionModel) -> str: + """Generate subscription description. + + The suggested pattern is to implement a subscription service that generates a subscription specific + description, in case that is not present the description will just be set to the product name. + """ + return f"{subscription.product.name} subscription" + + +logger = structlog.get_logger(__name__) + + +def initial_input_form_generator(product_name: str) -> FormGenerator: + # TODO add additional fields to form if needed + + class CreateExample4Form(FormPage): + model_config = ConfigDict(title=product_name) + + customer_id: CustomerId + + example4_settings: Label + divider_1: Divider + + num_val: int | None = None + + user_input = yield CreateExample4Form + user_input_dict = user_input.dict() + + return user_input_dict + + +@step("Construct Subscription model") +def construct_example4_model( + product: UUIDstr, + customer_id: UUIDstr, + num_val: int | None, +) -> State: + example4 = Example4Inactive.from_product_id( + product_id=product, + customer_id=customer_id, + status=SubscriptionLifecycle.INITIAL, + ) + example4.example4.num_val = num_val + + example4 = Example4Provisioning.from_other_lifecycle(example4, SubscriptionLifecycle.PROVISIONING) + example4.description = subscription_description(example4) + + return { + "subscription": example4, + "subscription_id": example4.subscription_id, # necessary to be able to use older generic step functions + "subscription_description": example4.description, + } + + +additional_steps = begin + + +@create_workflow("Create example4", initial_input_form=initial_input_form_generator, additional_steps=additional_steps) +def create_example4() -> StepList: + return ( + begin >> construct_example4_model >> store_process_subscription(Target.CREATE) + # TODO add provision step(s) + ) diff --git a/test/unit_tests/cli/data/generate/workflows/example4/modify_example4.py b/test/unit_tests/cli/data/generate/workflows/example4/modify_example4.py new file mode 100644 index 000000000..b8d4e0fb7 --- /dev/null +++ b/test/unit_tests/cli/data/generate/workflows/example4/modify_example4.py @@ -0,0 +1,70 @@ +import structlog +from orchestrator.domain import SubscriptionModel +from orchestrator.forms import FormPage +from orchestrator.forms.validators import CustomerId, Divider +from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr +from orchestrator.workflow import StepList, begin, step +from orchestrator.workflows.steps import set_status +from orchestrator.workflows.utils import modify_workflow +from pydantic_forms.validators import ReadOnlyField + +from products.product_types.example4 import Example4, Example4Provisioning + + +def subscription_description(subscription: SubscriptionModel) -> str: + """The suggested pattern is to implement a subscription service that generates a subscription specific + description, in case that is not present the description will just be set to the product name. + """ + return f"{subscription.product.name} subscription" + + +logger = structlog.get_logger(__name__) + + +def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: + subscription = Example4.from_subscription(subscription_id) + example4 = subscription.example4 + + # TODO fill in additional fields if needed + + class ModifyExample4Form(FormPage): + customer_id: CustomerId = subscription.customer_id # type: ignore + + divider_1: Divider + + num_val: ReadOnlyField(example4.num_val) + + user_input = yield ModifyExample4Form + user_input_dict = user_input.dict() + + return user_input_dict | {"subscription": subscription} + + +@step("Update subscription") +def update_subscription( + subscription: Example4Provisioning, +) -> State: + # TODO: get all modified fields + + return {"subscription": subscription} + + +@step("Update subscription description") +def update_subscription_description(subscription: Example4) -> State: + subscription.description = subscription_description(subscription) + return {"subscription": subscription} + + +additional_steps = begin + + +@modify_workflow("Modify example4", initial_input_form=initial_input_form_generator, additional_steps=additional_steps) +def modify_example4() -> StepList: + return ( + begin + >> set_status(SubscriptionLifecycle.PROVISIONING) + >> update_subscription + >> update_subscription_description + # TODO add additional steps if needed + >> set_status(SubscriptionLifecycle.ACTIVE) + ) diff --git a/test/unit_tests/cli/data/generate/workflows/example4/shared/forms.py b/test/unit_tests/cli/data/generate/workflows/example4/shared/forms.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/test/unit_tests/cli/data/generate/workflows/example4/shared/forms.py @@ -0,0 +1 @@ + diff --git a/test/unit_tests/cli/data/generate/workflows/example4/terminate_example4.py b/test/unit_tests/cli/data/generate/workflows/example4/terminate_example4.py new file mode 100644 index 000000000..03d9c9c6f --- /dev/null +++ b/test/unit_tests/cli/data/generate/workflows/example4/terminate_example4.py @@ -0,0 +1,39 @@ +import structlog +from orchestrator.forms import FormPage +from orchestrator.forms.validators import DisplaySubscription +from orchestrator.types import InputForm, State, UUIDstr +from orchestrator.workflow import StepList, begin, step +from orchestrator.workflows.utils import terminate_workflow + +from products.product_types.example4 import Example4 + +logger = structlog.get_logger(__name__) + + +def terminate_initial_input_form_generator(subscription_id: UUIDstr, customer_id: UUIDstr) -> InputForm: + temp_subscription_id = subscription_id + + class TerminateExample4Form(FormPage): + subscription_id: DisplaySubscription = temp_subscription_id # type: ignore + + return TerminateExample4Form + + +@step("Delete subscription from OSS/BSS") +def delete_subscription_from_oss_bss(subscription: Example4) -> State: + # TODO: add actual call to OSS/BSS to delete subscription + + return {} + + +additional_steps = begin + + +@terminate_workflow( + "Terminate example4", initial_input_form=terminate_initial_input_form_generator, additional_steps=additional_steps +) +def terminate_example4() -> StepList: + return ( + begin >> delete_subscription_from_oss_bss + # TODO: fill in additional steps if needed + ) diff --git a/test/unit_tests/cli/data/product_config4.yaml b/test/unit_tests/cli/data/product_config4.yaml new file mode 100644 index 000000000..88e6d5485 --- /dev/null +++ b/test/unit_tests/cli/data/product_config4.yaml @@ -0,0 +1,32 @@ +# Testcase for multiple product blocks defined in the same file +config: + summary_forms: False +name: example4 +type: Example4 +tag: EXAMPLE4 +description: "Product example 4" +product_blocks: + - name: example4 + type: Example4 + tag: EXAMPLE4 + description: "Example 4 root product block" + fields: + - name: num_val + type: int + - name: sub_block + type: Example4Sub + description: "example 4 sub product block" + required: provisioning + - name: example4sub + type: Example4Sub + tag: EXAMPLE4SUB + description: "example 4 sub product block" + fields: + - name: str_val + type: str + + +workflows: + - name: terminate + - name: validate + enabled: false diff --git a/test/unit_tests/cli/test_generate_code.py b/test/unit_tests/cli/test_generate_code.py index 7c5414d97..af2be0f5e 100644 --- a/test/unit_tests/cli/test_generate_code.py +++ b/test/unit_tests/cli/test_generate_code.py @@ -2,6 +2,7 @@ import sys from difflib import context_diff from filecmp import dircmp +from functools import partial from pathlib import Path import pytest @@ -46,11 +47,19 @@ def actual_folder(tmp_path_factory, monkey_module) -> Path: sys.path.append(str(tmp_path)) create_main() runner = CliRunner() - runner.invoke(db_app, ["init"]) - for config_file in (absolute_path("product_config2.yaml"), absolute_path("product_config1.yaml")): + + # Don't catch exceptions because this will cost you grey hair. + invoke = partial(runner.invoke, catch_exceptions=False) + invoke(db_app, ["init"]) + 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"): - runner.invoke(generate_app, [cmd, "--config-file", config_file, "--no-dryrun", "--force"]) - runner.invoke(generate_app, ["migration", "--config-file", config_file]) + invoke(generate_app, [cmd, "--config-file", config_file, "--no-dryrun", "--force"]) + + invoke(generate_app, ["migration", "--config-file", config_file]) return tmp_path