Skip to content

Commit

Permalink
Add testcase for a list of nested blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark90 committed Feb 24, 2022
1 parent 1d38365 commit c3c4d25
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 11 deletions.
9 changes: 9 additions & 0 deletions test/unit_tests/domain/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from test.unit_tests.domain.products.product_blocks.product_block_list_nested import ( # noqa: F401 # noqa: F401
test_product_block_list_nested,
test_product_block_list_nested_db_parent,
)
from test.unit_tests.domain.products.product_blocks.product_block_one import ( # noqa: F401 # noqa: F401
test_product_block_one,
test_product_block_one_db,
Expand All @@ -22,6 +26,11 @@
test_product_sub_block_two,
test_product_sub_block_two_db,
)
from test.unit_tests.domain.products.product_types.product_type_list_nested import ( # noqa: F401
test_product_list_nested,
test_product_model_list_nested,
test_product_type_list_nested,
)
from test.unit_tests.domain.products.product_types.product_type_list_union import ( # noqa: F401
test_product_list_union,
test_product_type_list_union,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import List, Optional

import pytest

from orchestrator.db import ProductBlockTable, db
from orchestrator.domain.base import ProductBlockModel
from orchestrator.types import SubscriptionLifecycle


class ProductBlockListNestedForTestInactive(ProductBlockModel, product_block_name="ProductBlockListNestedForTest"):
sub_block_list: List["ProductBlockListNestedForTestInactive"]
int_field: Optional[int] = None


class ProductBlockListNestedForTestProvisioning(
ProductBlockListNestedForTestInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]
):
sub_block_list: List["ProductBlockListNestedForTestProvisioning"] # type: ignore
int_field: int


class ProductBlockListNestedForTest(
ProductBlockListNestedForTestProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]
):
sub_block_list: List["ProductBlockListNestedForTest"] # type: ignore
int_field: int


@pytest.fixture
def test_product_block_list_nested():
# Classes defined at module level, otherwise they remain in local namespace and
# `get_type_hints()` can't evaluate the ForwardRefs
return (
ProductBlockListNestedForTestInactive,
ProductBlockListNestedForTestProvisioning,
ProductBlockListNestedForTest,
)


@pytest.fixture
def test_product_block_list_nested_db_parent(resource_type_list, resource_type_int, resource_type_str):
parent_block = ProductBlockTable(
name="ProductBlockListNestedForTest", description="Test Block Parent", tag="TEST", status="active"
)
parent_block.resource_types = [resource_type_int]

db.session.add(parent_block)
db.session.commit()

return parent_block
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,20 @@
from orchestrator.types import SubscriptionLifecycle


# TODO also test List
class ProductBlockOneNestedForTestInactive(ProductBlockModel, product_block_name="ProductBlockOneNestedForTest"):
sub_block: Optional["ProductBlockOneNestedForTestInactive"] = None
# sub_block_list: List[ForwardRef("ProductBlockOneNestedForTestInactive")] = []
int_field: Optional[int] = None


class ProductBlockOneNestedForTestProvisioning(
ProductBlockOneNestedForTestInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]
):
sub_block: Optional["ProductBlockOneNestedForTestProvisioning"] = None
# sub_block_list: List[ForwardRef("ProductBlockOneNestedForTestProvisioning")]
int_field: int


class ProductBlockOneNestedForTest(ProductBlockOneNestedForTestProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
sub_block: Optional["ProductBlockOneNestedForTest"] = None
# sub_block_list: List[ForwardRef("ProductBlockOneNestedForTest")]
int_field: int


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest

from orchestrator.db import FixedInputTable, ProductTable, db
from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY
from orchestrator.domain.base import ProductModel, SubscriptionModel
from orchestrator.domain.lifecycle import ProductLifecycle
from orchestrator.types import SubscriptionLifecycle
from test.unit_tests.domain.products.product_blocks.product_block_list_nested import (
ProductBlockListNestedForTest,
ProductBlockListNestedForTestInactive,
ProductBlockListNestedForTestProvisioning,
)


@pytest.fixture
def test_product_type_list_nested():
class ProductTypeListNestedForTestInactive(SubscriptionModel, is_base=True):
test_fixed_input: bool
block: ProductBlockListNestedForTestInactive

class ProductTypeListNestedForTestProvisioning(
ProductTypeListNestedForTestInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]
):
test_fixed_input: bool
block: ProductBlockListNestedForTestProvisioning

class ProductTypeListNestedForTest(
ProductTypeListNestedForTestProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]
):
test_fixed_input: bool
block: ProductBlockListNestedForTest

SUBSCRIPTION_MODEL_REGISTRY["TestProductListNested"] = ProductTypeListNestedForTest
yield ProductTypeListNestedForTestInactive, ProductTypeListNestedForTestProvisioning, ProductTypeListNestedForTest
del SUBSCRIPTION_MODEL_REGISTRY["TestProductListNested"]


@pytest.fixture
def test_product_list_nested(test_product_block_list_nested_db_parent):
product = ProductTable(
name="TestProductListNested", description="Test ProductTable", product_type="Test", tag="TEST", status="active"
)

fixed_input = FixedInputTable(name="test_fixed_input", value="False")

product_block = test_product_block_list_nested_db_parent
product.fixed_inputs = [fixed_input]
product.product_blocks = [product_block]

db.session.add(product)
db.session.commit()

return product.product_id


@pytest.fixture
def test_product_model_list_nested(test_product_list_nested):
return ProductModel(
product_id=test_product_list_nested,
name="TestProductListNested",
description="Test ProductTable",
product_type="Test",
tag="TEST",
status=ProductLifecycle.ACTIVE,
)
170 changes: 163 additions & 7 deletions test/unit_tests/domain/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
)
from orchestrator.domain.lifecycle import ProductLifecycle
from orchestrator.types import SubscriptionLifecycle
from test.unit_tests.domain.products.product_blocks.product_block_one_nested import (
ProductBlockOneNestedForTest,
ProductBlockOneNestedForTestInactive,
from test.unit_tests.domain.products.product_blocks.product_block_list_nested import (
ProductBlockListNestedForTestInactive,
)
from test.unit_tests.domain.products.product_blocks.product_block_one_nested import ProductBlockOneNestedForTestInactive


def test_product_block_metadata(test_product_block_one, test_product_one, test_product_block_one_db):
Expand All @@ -48,7 +48,7 @@ def test_product_block_metadata(test_product_block_one, test_product_one, test_p
assert ProductBlockOneForTestInactive.tag == "TEST"


def test_product_block_nested(test_product_model_nested, test_product_type_one_nested):
def test_product_block_one_nested(test_product_model_nested, test_product_type_one_nested):
"""Test the behavior of nesting (self-referencing) product blocks.
Notes:
Expand Down Expand Up @@ -82,7 +82,7 @@ def test_product_block_nested(test_product_model_nested, test_product_type_one_n
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model20.block = ProductBlockOneNestedForTest.new(
model20.block = ProductBlockOneNestedForTestInactive.new(
subscription_id=model20.subscription_id,
int_field=20,
sub_block=model30.block,
Expand Down Expand Up @@ -169,8 +169,164 @@ def test_product_block_nested(test_product_model_nested, test_product_type_one_n
assert newmodel11.block.sub_block.sub_block.sub_block is None


# TODO add test for List of nested blocks
# def test_product_block_nested_list(test_product_model_nested, test_product_type_one_nested):
def test_product_block_list_nested(test_product_model_list_nested, test_product_type_list_nested):
"""Test the behavior of nesting (self-referencing) a list of product blocks.
Notes:
- nesting only works when each block is attached to a different subscription
"""
ProductTypeListNestedForTestInactive, _, ProductTypeListNestedForTest = test_product_type_list_nested

customer_id = uuid4()
# Create productblocks 30 and 31 that will both be nested in block 20 and 21
model30 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model30.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model30.subscription_id,
int_field=30,
sub_block_list=[],
)
model30 = SubscriptionModel.from_other_lifecycle(model30, SubscriptionLifecycle.ACTIVE)
model30.save()
model31 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model31.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model31.subscription_id,
int_field=31,
sub_block_list=[],
)
model31 = SubscriptionModel.from_other_lifecycle(model31, SubscriptionLifecycle.ACTIVE)
model31.save()
db.session.commit()

# Create productblocks 20 and 21 that both
# - refer to blocks 30 and 31
# - will be nested in blocks 10 and 11
model20 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model20.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model20.subscription_id,
int_field=20,
sub_block_list=[model30.block, model31.block],
)
model20 = SubscriptionModel.from_other_lifecycle(model20, SubscriptionLifecycle.ACTIVE)
model20.save()
model21 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model21.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model21.subscription_id,
int_field=21,
sub_block_list=[model30.block, model31.block],
)
model21 = SubscriptionModel.from_other_lifecycle(model21, SubscriptionLifecycle.ACTIVE)
model21.save()
db.session.commit()

# Create productblocks 10 and 11 that both refer to blocks 20 and 21
model10 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model10.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model10.subscription_id,
int_field=10,
sub_block_list=[model20.block, model21.block],
)
model10 = SubscriptionModel.from_other_lifecycle(model10, SubscriptionLifecycle.ACTIVE)
model10.save()
model11 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model11.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model11.subscription_id,
int_field=11,
sub_block_list=[model20.block, model21.block],
)
model11 = SubscriptionModel.from_other_lifecycle(model11, SubscriptionLifecycle.ACTIVE)
model11.save()
db.session.commit()

# Load blocks 10 and 11 and verify the nested blocks
newmodel10 = ProductTypeListNestedForTest.from_subscription(model10.subscription_id)
newmodel11 = ProductTypeListNestedForTest.from_subscription(model11.subscription_id)
assert newmodel10.block.int_field == 10
assert newmodel11.block.int_field == 11
assert newmodel10.block.sub_block_list[0].int_field == 20
assert newmodel10.block.sub_block_list[1].int_field == 21
assert newmodel11.block.sub_block_list[0].int_field == 20
assert newmodel11.block.sub_block_list[1].int_field == 21
assert sorted(
level3.int_field for level2 in newmodel10.block.sub_block_list for level3 in level2.sub_block_list
) == [30, 30, 31, 31]
assert sorted(
level3.int_field for level2 in newmodel11.block.sub_block_list for level3 in level2.sub_block_list
) == [30, 30, 31, 31]
# Assert a few blocks at deepest level to have an empty list
assert newmodel10.block.sub_block_list[0].sub_block_list[0].sub_block_list == []
assert newmodel11.block.sub_block_list[1].sub_block_list[1].sub_block_list == []

# Load block 20 and verify nested blocks
newmodel20 = ProductTypeListNestedForTest.from_subscription(model20.subscription_id)
assert newmodel20.block.int_field == 20
assert newmodel20.block.sub_block_list[0].int_field == 30
assert newmodel20.block.sub_block_list[1].int_field == 31
assert newmodel20.block.sub_block_list[0].sub_block_list == []

# Create productblock 32 and nest it in block 20 (but not 21!)
model32 = ProductTypeListNestedForTestInactive.from_product_id(
product_id=test_product_model_list_nested.product_id,
customer_id=customer_id,
insync=True,
start_date=None,
status=SubscriptionLifecycle.INITIAL,
)
model32.block = ProductBlockListNestedForTestInactive.new(
subscription_id=model30.subscription_id,
int_field=32,
sub_block_list=[],
)
model32 = SubscriptionModel.from_other_lifecycle(model32, SubscriptionLifecycle.ACTIVE)
model32.save()
newmodel20.block.sub_block_list.append(model32.block)
newmodel20.save()
db.session.commit()

# (again) Load blocks 10 and 11 and verify block 32 is present once
newmodel10 = ProductTypeListNestedForTest.from_subscription(model10.subscription_id)
newmodel11 = ProductTypeListNestedForTest.from_subscription(model11.subscription_id)
assert sorted(
level3.int_field for level2 in newmodel10.block.sub_block_list for level3 in level2.sub_block_list
) == [30, 30, 31, 31, 32]
assert sorted(
level3.int_field for level2 in newmodel11.block.sub_block_list for level3 in level2.sub_block_list
) == [30, 30, 31, 31, 32]


def test_lifecycle(test_product_model, test_product_type_one, test_product_block_one):
Expand Down

0 comments on commit c3c4d25

Please sign in to comment.