Exemple #1
0
def test_model_cannot_add_two_software_systems_with_same_name(empty_model: Model):
    """Ensure duplicate software systems are not allowed."""
    empty_model.add_software_system(name="Bob")
    with pytest.raises(
        ValueError,
        match="A software system with the name 'Bob' already exists in the model.",
    ):
        empty_model.add_software_system(name="Bob")
Exemple #2
0
def test_create_implied_relationships_unless_same_exists():
    """Check logic of create_implied_relationships_unless_same_exists."""
    model = Model(implied_relationship_strategy=create_unless_same_exists)

    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")
    system2 = model.add_software_system(name="system2")

    system1.uses(system2, "Reads from")
    assert len(list(system1.get_relationships())) == 1
    container1.uses(system2, "Reads from")
    assert len(list(system1.get_relationships())) == 1
    container1.uses(system2, "Writes to")
    assert len(list(system1.get_relationships())) == 2
Exemple #3
0
def test_ignore_implied_relationship_strategy():
    """Check that by default no implied relationships are added."""
    model = Model(implied_relationship_strategy=ignore)
    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")
    system2 = model.add_software_system(name="system2")
    container2 = system2.add_container(name="container2", description="test")

    rel = container1.uses(container2, "Uses")

    assert len(list(container1.get_relationships())) == 1
    assert len(list(system1.get_relationships())) == 0
    assert set(container1.get_relationships()) == {rel}
    assert set(system1.get_relationships()) == set()
Exemple #4
0
def test_add_nearest_neighbours():
    """Test basic behaviour of add_nearest_neighbours."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    person = model.add_person(name="Person 1")
    sys1.uses(sys2)
    person.uses(sys1)

    # Check neighbours from outbound relationships
    view = DerivedView(software_system=sys1, description="")
    view.add_nearest_neighbours(sys1, SoftwareSystem)
    assert any((elt_view.element is sys1 for elt_view in view.element_views))
    assert any((elt_view.element is sys2 for elt_view in view.element_views))
    assert not any(
        (elt_view.element is person for elt_view in view.element_views))
    assert len(view.relationship_views) == 1

    # Check neighbours from inbound relationships
    view = DerivedView(software_system=sys1, description="")
    view.add_nearest_neighbours(sys2, SoftwareSystem)
    assert any((elt_view.element is sys1 for elt_view in view.element_views))
    assert any((elt_view.element is sys2 for elt_view in view.element_views))
    assert not any(
        (elt_view.element is person for elt_view in view.element_views))
    assert len(view.relationship_views) == 1
def test_model_add_element_with_existing_id_raises_error(empty_model: Model):
    """Test you can't add an element with the same ID as an existing one."""
    system1 = empty_model.add_software_system(name="System")
    system2 = SoftwareSystem(name="System2", id=system1.id)

    with pytest.raises(ValueError, match="The element .* has an existing ID"):
        empty_model += system2
Exemple #6
0
def test_suppressing_implied_relationships():
    """Ensure you can explicitly suppress the current strategy."""
    model = Model(implied_relationship_strategy=create_unless_any_exist)
    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")
    system2 = model.add_software_system(name="system2")
    container2 = system2.add_container(name="container2", description="test")

    rel = container1.uses(container2,
                          "Uses",
                          create_implied_relationships=False)

    assert len(list(container1.get_relationships())) == 1
    assert len(list(system1.get_relationships())) == 0
    assert set(container1.get_relationships()) == {rel}
    assert set(system1.get_relationships()) == set()
Exemple #7
0
def test_model_add_relationship_twice_ignored(empty_model: Model):
    """Ensure that adding an existing relationship to the Model makes no difference."""
    sys1 = empty_model.add_software_system(name="sys1")
    sys2 = empty_model.add_software_system(name="sys2")
    relationship = empty_model.add_relationship(source=sys1, destination=sys2)
    assert set(empty_model.get_relationships()) == {relationship}
    empty_model.add_relationship(relationship)
    assert set(empty_model.get_relationships()) == {relationship}
def test_default_element_tags_order(empty_model: Model):
    """
    Test that the default tags get added in the right order.

    Based on test_getTags_WhenThereAreNoTags() from the Java API.
    """
    element = empty_model.add_software_system(name="Name", description="Description")
    assert list(element.tags) == ["Element", "Software System"]
def test_model_get_relationship_by_id(empty_model: Model):
    """Test retrieving relationships by their IDs."""
    sys1 = empty_model.add_software_system(name="sys1")
    sys2 = empty_model.add_software_system(name="sys2")
    relationship = empty_model.add_relationship(source=sys1,
                                                destination=sys2,
                                                id="r1")
    assert empty_model.get_relationship("r1") is relationship
Exemple #10
0
def test_model_cannot_add_relationship_with_same_id_as_element(empty_model: Model):
    """Ensure you can't add a relationship with the same ID as an element."""
    sys1 = empty_model.add_software_system(name="sys1")
    sys2 = empty_model.add_software_system(name="sys2")
    with pytest.raises(
        ValueError, match="Relationship.* has the same ID as SoftwareSystem.*"
    ):
        empty_model.add_relationship(source=sys1, destination=sys2, id=sys1.id)
Exemple #11
0
def test_model_cannot_add_relationship_with_same_id_as_existing(empty_model: Model):
    """Ensure you can't add two relationships with the same ID."""
    sys1 = empty_model.add_software_system(name="sys1")
    sys2 = empty_model.add_software_system(name="sys2")
    empty_model.add_relationship(source=sys1, destination=sys2, id="r1")
    with pytest.raises(
        ValueError, match="Relationship.* has the same ID as Relationship.*"
    ):
        empty_model.add_relationship(source=sys1, destination=sys2, id="r1")
Exemple #12
0
def test_self_references_are_not_implied(strategy):
    """Ensure references from an element to itself don't get implied to parents."""
    model = Model(implied_relationship_strategy=strategy)
    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")

    container1.uses(container1, "Uses")

    assert len(list(container1.get_relationships())) == 1
    assert len(list(system1.get_relationships())) == 0
def test_tag_order_is_preserved_to_and_from_io(empty_model: Model):
    """Test that when serializing via IO classes or back, tag ordering is preserved."""
    element = empty_model.add_software_system(name="Name", description="Description")
    element.tags.update(["tag3", "tag2", "tag1"])  # Deliberately not ascending

    element_io = SoftwareSystemIO.from_orm(element)
    assert element_io.tags == ["Element", "Software System", "tag3", "tag2", "tag1"]
    assert element_io.dict()["tags"] == "Element,Software System,tag3,tag2,tag1"
    element2 = SoftwareSystem.hydrate(element_io, Model())
    assert list(element2.tags) == ["Element", "Software System", "tag3", "tag2", "tag1"]
Exemple #14
0
def test_adding_all_relationships():
    """Test adding all relationships for elements in the view."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    sys3 = model.add_software_system(name="System 3")
    rel1 = sys1.uses(sys2)
    rel2 = sys3.uses(sys1)

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)
    view._add_element(sys2, False)
    view._add_element(sys3, False)
    assert view.relationship_views == set()

    view._add_relationships(sys1)
    assert len(view.relationship_views) == 2
    assert rel1 in [vr.relationship for vr in view.relationship_views]
    assert rel2 in [vr.relationship for vr in view.relationship_views]
Exemple #15
0
def test_create_implied_relationships_unless_any_exist():
    """Check logic of create_implied_relationships_unless_any_exist."""
    model = Model(implied_relationship_strategy=create_unless_any_exist)
    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")
    component1 = container1.add_component(name="component1",
                                          description="test")
    system2 = model.add_software_system(name="system2")
    container2 = system2.add_container(name="container2", description="test")
    component2 = container2.add_component(name="component2",
                                          description="test")

    component1.uses(component2, "Uses")

    # We should now have every *1 element related to every *2 element
    assert len(list(component1.get_relationships())) == 3
    assert len(list(container1.get_relationships())) == 3
    assert len(list(system1.get_relationships())) == 3
    assert any(rel.destination is component2
               for rel in component1.get_relationships())
    assert any(rel.destination is container2
               for rel in component1.get_relationships())
    assert any(rel.destination is system2
               for rel in component1.get_relationships())
    assert any(rel.destination is component2
               for rel in container1.get_relationships())
    assert any(rel.destination is container2
               for rel in container1.get_relationships())
    assert any(rel.destination is system2
               for rel in container1.get_relationships())
    assert any(rel.destination is component2
               for rel in system1.get_relationships())
    assert any(rel.destination is container2
               for rel in system1.get_relationships())
    assert any(rel.destination is system2
               for rel in system1.get_relationships())

    # Now add another relationship, which shouldn't copy upwards as some already exist
    container1.uses(container2, "Uses differently")
    assert len(list(
        container1.get_relationships())) == 4  # 3 from before plus new one
    assert len(list(system1.get_relationships())) == 3  # Same as before
def test_default_and_custom_tags(empty_model: Model):
    """
    Test that tags are in the order that they were added.

    Based on test_getTags_ReturnsTheListOfTags_WhenThereAreSomeTags from the Java API.

    See https://github.com/Midnighter/structurizr-python/issues/22
    """
    element = empty_model.add_software_system(name="Name", description="Description")
    element.tags.update(["tag3", "tag2", "tag1"])  # Deliberately not ascending
    assert list(element.tags) == ["Element", "Software System", "tag3", "tag2", "tag1"]
Exemple #17
0
def test_is_element_in_view():
    """Test check for an element being in the view."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)

    assert view.is_element_in_view(sys1)
    assert not view.is_element_in_view(sys2)
Exemple #18
0
def test_find_element_view():
    """Test behaviour of find_element_view."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)

    assert view.find_element_view(element=sys1).element is sys1
    assert view.find_element_view(element=sys2) is None
Exemple #19
0
def test_adding_relationship_via_uses_adds_to_elements():
    """Ensure uses() adds relationships to the model and elements."""
    model = Model()
    sys1 = model.add_software_system(name="sys1")
    sys2 = model.add_software_system(name="sys2")

    relationship = sys1.uses(sys2, "uses")
    assert sys1.relationships == {relationship}
    assert set(sys1.get_relationships()) == {relationship}
    assert set(model.get_relationships()) == {relationship}
    assert sys2.relationships == set()  # relationships only contains outbound
    assert set(sys2.get_relationships()) == {relationship}
Exemple #20
0
def test_cloning_to_implied_relationship_copies_attributes_across():
    """Make sure that attributes carry over to implied relationships."""
    model = Model(implied_relationship_strategy=create_unless_any_exist)
    system1 = model.add_software_system(name="system1")
    container1 = system1.add_container(name="container1", description="test")
    system2 = model.add_software_system(name="system2")
    container2 = system2.add_container(name="container2", description="test")

    rel = container1.uses(
        container2,
        "Uses",
        technology="tech1",
        interaction_style=InteractionStyle.Asynchronous,
        tags="tag1,tag2",
        properties={"prop1": "val1"},
    )

    new_rel = next(system1.get_relationships())

    assert new_rel.description == "Uses"
    assert new_rel.technology == "tech1"
    assert new_rel.tags == rel.tags
    assert new_rel.properties == rel.properties
Exemple #21
0
def test_add_relationship_for_element_not_in_view():
    """Ensures relationships for elements outside the view are ignored."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    rel = sys1.uses(sys2)

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)

    # This relationship should be ignored as sys2 isn't in the view
    rel_view1 = view._add_relationship(rel)
    assert rel_view1 is None
    assert view.relationship_views == set()
def test_hydration(empty_model: Model):
    """Check dehydrating and hydrating."""
    system = empty_model.add_software_system(name="system", id="sys1")

    view = DynamicView(key="dyn1", description="Description", element=system)
    view.set_model(empty_model)

    io = DynamicViewIO.from_orm(view)
    d = io.dict()
    assert d["elementId"] == "sys1"

    view2 = DynamicView.hydrate(io, element=system)
    assert view2.key == "dyn1"
    assert view2.description == "Description"
    assert view2.element is system
Exemple #23
0
def test_add_relationship_doesnt_duplicate():
    """Test that adding a relationships twice doesn't duplicate it."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    rel = sys1.uses(sys2)

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)
    view._add_element(sys2, False)

    rel_view1 = view._add_relationship(rel)
    assert len(view.relationship_views) == 1
    rel_view2 = view._add_relationship(rel)
    assert len(view.relationship_views) == 1
    assert rel_view2 is rel_view1
Exemple #24
0
def test_add_nearest_neighbours_doesnt_dupe_relationships():
    """Test relationships aren't duplicated if neighbours added more than once.

    See https://github.com/Midnighter/structurizr-python/issues/63.
    """
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    sys1.uses(sys2)
    view = DerivedView(software_system=sys1, description="")
    view.add_nearest_neighbours(sys1, SoftwareSystem)
    assert len(view.relationship_views) == 1

    # The next line should not add any new relationships
    view.add_nearest_neighbours(sys1, Person)
    assert len(view.relationship_views) == 1
Exemple #25
0
def test_adding_relationship_to_model_adds_to_element():
    """Ensure relationships are added to elements.

    Make sure that when a relationship is added via Model.add_relationship it also
    gets added to the elements.
    """
    model = Model()
    sys1 = model.add_software_system(name="sys1")
    sys2 = model.add_software_system(name="sys2")

    relationship = model.add_relationship(source=sys1,
                                          destination=sys2,
                                          description="uses")
    assert sys1.relationships == {relationship}
    assert set(sys1.get_relationships()) == {relationship}
    assert set(model.get_relationships()) == {relationship}
    assert sys2.relationships == set()  # relationships only contains outbound
    assert set(sys2.get_relationships()) == {relationship}
def test_relationships_are_ordered(empty_model: Model):
    """Check that relationships are ordered for DynamicView."""
    system1 = empty_model.add_software_system(name="System 1")
    container1 = system1.add_container(name="Container 1")
    container2 = system1.add_container(name="Container 2")
    container1.uses(container2)

    view = DynamicView(key="dyn1", description="test", element=system1)
    view.set_model(empty_model)

    # Test using 10 items, so we can check 1 < 2 < 10 (i.e. not string ordering)
    for i in range(10):
        view.add(container1, container2, description=f"rel {i}")

    relationship_views = list(view.relationship_views)

    assert len(relationship_views) == 10
    for i in range(10):
        assert relationship_views[i].order == str(i + 1)
def test_relationships_with_subsequences_are_ordered(empty_model: Model):
    """Test ordering works with subsequences."""
    system1 = empty_model.add_software_system(name="System 1")
    container1 = system1.add_container(name="Container 1")
    container2 = system1.add_container(name="Container 2")
    container1.uses(container2)

    view = DynamicView(key="dyn1", description="test", element=system1)
    view.set_model(empty_model)

    view.add(container1, container2, description="test 1")
    with view.subsequence():
        view.add(container1, container2, description="test 1.1")
        view.add(container1, container2, description="test 1.2")
    for i in range(2, 11):
        view.add(container1, container2, description=f"test {i}")

    relationship_views = list(view.relationship_views)

    assert relationship_views[0].order == "1"
    assert relationship_views[1].order == "1.1"
    assert relationship_views[2].order == "1.2"
    assert relationship_views[3].order == "2"
    assert relationship_views[11].order == "10"
Exemple #28
0
def test_find_relationship_view():
    """Test behaviour of find_element_view."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    rel1 = sys1.uses(sys2, "Uses")
    rel2 = sys2.uses(sys1, "Also uses")
    rel3 = sys2.uses(sys1, "Returns")

    view = DerivedView(software_system=sys1, description="")
    view._add_element(sys1, False)
    view._add_element(sys2, False)
    view._add_relationship(rel1).description = "Override"
    view._add_relationship(rel3).response = True

    assert view.find_relationship_view(relationship=rel1).relationship is rel1
    assert view.find_relationship_view(relationship=rel2) is None
    assert view.find_relationship_view(
        description="Override").relationship is rel1
    assert view.find_relationship_view(description="Uses") is None
    assert view.find_relationship_view(
        description="Returns").relationship is rel3
    assert view.find_relationship_view(response=True).relationship is rel3
    assert view.find_relationship_view(response=False).relationship is rel1
Exemple #29
0
def test_copy_layout():
    """Ensure that layout is copied over, including sub-views."""
    model = Model()
    sys1 = model.add_software_system(name="System 1")
    sys2 = model.add_software_system(name="System 2")
    rel1 = sys1.uses(sys2)

    view1 = DerivedView(software_system=sys1, description="")
    view1._add_element(sys1, False).paper_size = PaperSize.A1_Portrait
    view1._add_element(sys2, False).paper_size = PaperSize.A2_Portrait
    view1._add_relationship(rel1).paper_size = PaperSize.A3_Portrait
    view1.paper_size = PaperSize.A4_Portrait

    view2 = DerivedView(software_system=sys1, description="")
    view2._add_element(sys1, False).paper_size = PaperSize.A1_Portrait
    view2._add_element(sys2, False).paper_size = PaperSize.A2_Portrait
    view2._add_relationship(rel1).paper_size = PaperSize.A3_Portrait
    view2.copy_layout_information_from(view1)

    assert view2.paper_size == PaperSize.A4_Portrait
    assert view2.find_element_view(
        element=sys1).paper_size == PaperSize.A1_Portrait
    rv = view2.find_relationship_view(description="Uses")
    assert rv.paper_size == PaperSize.A3_Portrait
def test_model_add_element_twice_is_ignored(empty_model: Model):
    """Test you can't add an element with the same ID as an existing one."""
    system1 = empty_model.add_software_system(name="System")
    empty_model += system1
    assert empty_model.software_systems == {system1}