Example #1
0
    def test_kept_contract(self):
        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
            whitelisted_paths=mock.sentinel.whitelisted_paths,
        )
        dep_graph = mock.Mock()
        dep_graph.find_path.return_value = None
        dep_graph.get_descendants.return_value = []

        contract.check_dependencies(dep_graph)

        assert contract.is_kept is True

        # Check that each of the possible disallowed imports were checked
        dep_graph.find_path.assert_has_calls((
            mock.call(downstream='foo.one',
                      upstream='foo.two',
                      ignore_paths=mock.sentinel.whitelisted_paths),
            mock.call(downstream='foo.one',
                      upstream='foo.three',
                      ignore_paths=mock.sentinel.whitelisted_paths),
            mock.call(downstream='foo.two',
                      upstream='foo.three',
                      ignore_paths=mock.sentinel.whitelisted_paths),
        ))
Example #2
0
    def test_broken_contract(self):
        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
        )
        dep_graph = mock.Mock()
        dep_graph.get_descendants.return_value = []
        # Mock that one imports two and three, and two imports three
        dep_graph.find_path.side_effect = [
            None, ['foo.one', 'foo.two'], ['foo.one', 'foo.three'],
            ['foo.two', 'foo.three']
        ]

        contract.check_dependencies(dep_graph)

        assert contract.is_kept is False

        # Check that each of the possible disallowed imports are checked
        dep_graph.find_path.assert_has_calls((
            mock.call(downstream='foo.one',
                      upstream='foo.two',
                      ignore_paths=[]),
            mock.call(downstream='foo.one',
                      upstream='foo.three',
                      ignore_paths=[]),
            mock.call(downstream='foo.two',
                      upstream='foo.three',
                      ignore_paths=[]),
        ))
Example #3
0
    def test_broken_contract_via_other_layer(self):
        # If an illegal import happens via another layer, we don't want to report it
        # (as it will already be reported).

        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
        )
        dep_graph = mock.Mock()
        dep_graph.get_descendants.return_value = []
        # Mock that one imports two, and two imports three
        dep_graph.find_path.side_effect = [
            ['foo.one', 'foo.two'],
            ['foo.one', 'foo.two', 'foo.three'],
            ['foo.two', 'foo.three'],
        ]

        contract.check_dependencies(dep_graph)

        assert contract.illegal_dependencies == [
            ['foo.one', 'foo.two'],
            ['foo.two', 'foo.three'],
        ]
Example #4
0
    def test_only_shortest_violation_is_reported(self, longer_first):
        contract = Contract(
            name='Foo contract',
            containers=(
                'foo',
            ),
            layers=(
                Layer('two'),
                Layer('one'),
            ),
        )

        # These are both dependency violations, but it's more useful just to report
        # the more direct violation.
        if longer_first:
            paths = {
                Module('foo.two'): {
                    Module('foo.one.alpha'): [
                        Module('foo.one.alpha'), Module('foo.one.alpha.green'),
                        Module('foo.another'), Module('foo.two'),
                    ],
                    Module('foo.one.alpha.green'): [
                        Module('foo.one.alpha.green'), Module('foo.another'), Module('foo.two'),
                    ],

                },
            }
        else:
            paths = {
                Module('foo.two'): {
                    Module('foo.one.alpha'): [
                        Module('foo.one.alpha'), Module('foo.another'), Module('foo.two'),
                    ],
                    Module('foo.one.alpha.green'): [
                        Module('foo.one.alpha.green'), Module('foo.one.alpha'),
                        Module('foo.another'), Module('foo.two'),
                    ],

                },
            }
        graph = StubDependencyGraph(
            descendants={
                Module('foo.one'): [Module('foo.one.alpha'), Module('foo.one.beta'),
                                    Module('foo.one.alpha.blue'), Module('foo.one.alpha.green')],
            },
            paths=paths,
            modules=[Module('foo.one'), Module('foo.two')]
        )

        contract.check_dependencies(graph)

        if longer_first:
            assert contract.illegal_dependencies == [
                [Module('foo.one.alpha.green'), Module('foo.another'), Module('foo.two')],
            ]
        else:
            assert contract.illegal_dependencies == [
                [Module('foo.one.alpha'), Module('foo.another'), Module('foo.two')],
            ]
Example #5
0
    def test_broken_contract(self):
        contract = Contract(
            name='Foo contract',
            containers=(
                Module('foo.blue'),
                Module('foo.green'),
            ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
        )
        graph = StubDependencyGraph(
            descendants={
                Module('foo.green.one'): [
                    Module('foo.green.one.alpha'),
                    Module('foo.green.one.beta'),
                ],
                Module('foo.green.three'): [
                    Module('foo.green.three.alpha'),
                    Module('foo.green.three.beta'),
                ],
            },
            paths={
                Module('foo.blue.two'): {
                    # An allowed path: layer directly importing a layer below it.
                    Module('foo.blue.three'): [Module('foo.blue.three'), Module('foo.blue.two')],
                    # Disallowed path: layer directly importing a layer above it.
                    Module('foo.blue.one'): [Module('foo.blue.one'), Module('foo.blue.two')],
                },
                Module('foo.green.three.alpha'): {
                    # Module inside layer importing a module inside a higher layer.
                    Module('foo.green.one.alpha'): [Module('foo.green.one.alpha'),
                                                    Module('foo.green.three.alpha')],
                },
            },
            modules=[
                Module('foo.green'),
                Module('foo.green.one'),
                Module('foo.green.one.alpha'),
                Module('foo.green.one.beta'),
                Module('foo.green.two'),
                Module('foo.green.three'),
                Module('foo.blue'),
                Module('foo.blue.one'),
                Module('foo.blue.two'),
                Module('foo.blue.three'),
            ]
        )

        contract.check_dependencies(graph)

        assert contract.is_kept is False
        assert contract.illegal_dependencies == [
            [Module('foo.blue.one'), Module('foo.blue.two')],
            [Module('foo.green.one.alpha'), Module('foo.green.three.alpha')]
        ]
Example #6
0
    def test_unchecked_contract_raises_exception(self):
        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
        )

        with pytest.raises(RuntimeError) as excinfo:
            contract.is_kept
        assert 'Cannot check whether contract is ' \
            'kept until check_dependencies is called.' in str(excinfo.value)
Example #7
0
    def test_broken_contract_children(self):
        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('two'),
                Layer('one'),
            ),
        )
        dep_graph = mock.Mock()
        # Mock some deeper submodules
        dep_graph.get_descendants.side_effect = [
            # For foo.one
            [
                'foo.one.alpha', 'foo.one.alpha.red', 'foo.one.alpha.green',
                'foo.one.beta'
            ],
            # For foo.two
            [],
        ]

        # Mock that foo.one.alpha.red imports foo.two
        dep_graph.find_path.side_effect = [
            None, None, ['foo.one.alpha.red', 'foo.two'], None, None
        ]

        contract.check_dependencies(dep_graph)

        assert contract.is_kept is False

        # Check that each of the possible disallowed imports are checked
        dep_graph.find_path.assert_has_calls((
            mock.call(downstream='foo.one',
                      upstream='foo.two',
                      ignore_paths=[]),
            mock.call(downstream='foo.one.alpha',
                      upstream='foo.two',
                      ignore_paths=[]),
            mock.call(downstream='foo.one.alpha.red',
                      upstream='foo.two',
                      ignore_paths=[]),
            mock.call(downstream='foo.one.alpha.green',
                      upstream='foo.two',
                      ignore_paths=[]),
            mock.call(downstream='foo.one.beta',
                      upstream='foo.two',
                      ignore_paths=[]),
        ))
Example #8
0
    def test_broken_contract_via_other_layer(self):
        # If an illegal import happens via another layer, we don't want to report it
        # (as it will already be reported).

        contract = Contract(
            name='Foo contract',
            containers=(
                'foo',
            ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
        )
        graph = StubDependencyGraph(
            descendants={},
            paths={
                Module('foo.three'): {
                    Module('foo.two'): [Module('foo.two'), Module('foo.three')],
                    Module('foo.one'): [Module('foo.one'), Module('foo.two'), Module('foo.three')],
                },
                Module('foo.two'): {
                    Module('foo.one'): [Module('foo.one'), Module('foo.two')],
                },
            },
            modules=[
                Module('foo.one'),
                Module('foo.two'),
                Module('foo.three'),
            ]
        )

        contract.check_dependencies(graph)

        assert contract.illegal_dependencies == [
            [Module('foo.one'), Module('foo.two')],
            [Module('foo.two'), Module('foo.three')],
        ]
Example #9
0
    def test_missing_contract(self, is_optional):
        contract = Contract(
            name='Foo contract',
            containers=(
                'foo.one',
                'foo.two',
            ),
            layers=(
                Layer('blue'),
                Layer('yellow', is_optional=is_optional),  # Missing from foo.two.
                Layer('green'),
            ),
        )
        graph = StubDependencyGraph(
            modules=[
                Module('foo.one'),
                Module('foo.one.blue'),
                Module('foo.one.blue.alpha'),
                Module('foo.one.yellow'),
                Module('foo.one.green'),
                Module('foo.two'),
                Module('foo.two.blue'),
                Module('foo.two.blue.alpha'),
                Module('foo.two.green'),
            ]
        )

        if is_optional:
            # Should pass.
            contract.check_dependencies(graph)
        else:
            with pytest.raises(ValueError) as e:
                contract.check_dependencies(graph)

            assert str(e.value) == (
                "Missing layer in container 'foo.two': module foo.two.yellow does not exist."
            )
Example #10
0
    def test_only_shortest_violation_is_reported(self, longer_first):
        contract = Contract(
            name='Foo contract',
            packages=('foo', ),
            layers=(
                Layer('two'),
                Layer('one'),
            ),
        )
        dep_graph = mock.Mock()
        dep_graph.get_descendants.side_effect = [
            # For foo.one
            [
                'foo.one.alpha', 'foo.one.alpha.red', 'foo.one.alpha.green',
                'foo.one.beta'
            ],
            # For foo.two
            [],
        ]
        # These are both dependency violations, but it's more useful just to report
        # the more direct violation (the second one in this case).
        if longer_first:
            dep_graph.find_path.side_effect = [
                # foo.one <- foo.two
                None,
                # foo.one.alpha <- foo.two
                [
                    'foo.one.alpha', 'foo.one.alpha.green', 'foo.x.alpha',
                    'foo.two'
                ],
                # foo.one.alpha.red <- foo.two
                [
                    'foo.one.alpha.red', 'foo.one.alpha.green', 'foo.x.alpha',
                    'foo.two'
                ],
                # foo.one.alhpa.green <- foo.two
                ['foo.one.alpha.green', 'foo.x.alpha', 'foo.two'],
                # foo.one.beta <- foo.two
                None,
            ]
        else:
            dep_graph.find_path.side_effect = [
                None,
                ['foo.one.alpha', 'foo.x.alpha', 'foo.two'],
                None,
                [
                    'foo.one.alpha.green', 'foo.one.alpha', 'foo.x.alpha',
                    'foo.two'
                ],
                None,
            ]

        contract.check_dependencies(dep_graph)

        if longer_first:
            assert contract.illegal_dependencies == [
                ['foo.one.alpha.green', 'foo.x.alpha', 'foo.two'],
            ]
        else:
            assert contract.illegal_dependencies == [
                ['foo.one.alpha', 'foo.x.alpha', 'foo.two'],
            ]
Example #11
0
    def test_kept_contract(self):
        contract = Contract(
            name='Foo contract',
            containers=(
                Module('foo.blue'),
                Module('foo.green'),
            ),
            layers=(
                Layer('three'),
                Layer('two'),
                Layer('one'),
            ),
            whitelisted_paths=mock.sentinel.whitelisted_paths,
        )
        graph = StubDependencyGraph(
            descendants={
                Module('foo.green.one'): [
                    Module('foo.green.one.alpha'),
                    Module('foo.green.one.beta'),
                ],
                Module('foo.green.three'): [
                    Module('foo.green.three.alpha'),
                    Module('foo.green.three.beta'),
                ],
            },
            paths={
                # Include some allowed paths.
                Module('foo.blue.two'): {
                    # Layer directly importing a layer below it.
                    Module('foo.blue.three'): [Module('foo.blue.three'), Module('foo.blue.two')],
                },
                Module('foo.blue.one'): {
                    # Layer directly importing two layers below.
                    Module('foo.blue.three'): [Module('foo.blue.three'), Module('foo.blue.one')],
                },
                Module('foo.green.three'): {
                    # Layer importing higher up layer, but from another container.
                    Module('foo.blue.one'): [Module('foo.blue.one'), Module('foo.green.three')],
                },
                Module('foo.green.three.beta'): {
                    # Module inside layer importing another module in same layer.
                    Module('foo.green.three.alpha'): [Module('foo.green.three.alpha'),
                                                      Module('foo.green.three.beta')],
                },
                Module('foo.green.one.alpha'): {
                    # Module inside layer importing a module inside a lower layer.
                    Module('foo.green.three.alpha'): [Module('foo.green.three.alpha'),
                                                      Module('foo.green.one.alpha')]
                },
            },
            modules=[
                Module('foo.green'),
                Module('foo.green.one'),
                Module('foo.green.one.alpha'),
                Module('foo.green.one.beta'),
                Module('foo.green.two'),
                Module('foo.green.three'),
                Module('foo.blue'),
                Module('foo.blue.one'),
                Module('foo.blue.two'),
                Module('foo.blue.three'),
            ]
        )

        contract.check_dependencies(graph)

        assert contract.is_kept is True