Skip to content

Commit

Permalink
Error if the containers don't exist
Browse files Browse the repository at this point in the history
  • Loading branch information
seddonym committed Oct 15, 2018
1 parent d1177c4 commit 109fc4e
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 46 deletions.
8 changes: 7 additions & 1 deletion src/layer_linter/contract.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List, Dict, Iterable, Optional
import yaml
import os
import importlib
import logging
from copy import copy

Expand Down Expand Up @@ -218,3 +218,9 @@ def _validate_container_name(container_name, package_name):
f"Invalid container '{container_name}': containers must be either a "
f"subpackage of '{package_name}', or '{package_name}' itself."
)

# Check that the container actually exists.
if importlib.util.find_spec(container_name) is None:
raise ValueError(
f"Invalid container '{container_name}': no such package."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Contract A:
containers:
- singlecontractfile.foo
- singlecontractfile.missing
- singlecontractfile.bar
layers:
- one
- two
File renamed without changes.
Empty file.
Empty file.
10 changes: 10 additions & 0 deletions tests/assets/successpackage/layers_with_missing_container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Modular:
containers:
- successpackage.one
- successpackage.two
- successpackage.missing
- successpackage.three
layers:
- gamma
- beta
- alpha
106 changes: 63 additions & 43 deletions tests/functional/test_get_contracts.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
import os
import sys

import pytest

from layer_linter.contract import get_contracts, Layer
from layer_linter.dependencies import ImportPath
from layer_linter.module import Module


def test_get_contracts():
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, '..', 'assets', 'singlecontractfile', 'layers.yml')

contracts = get_contracts(filename, package_name='singlecontractfile')

assert len(contracts) == 2
expected_contracts = [
{
'name': 'Contract A',
'packages': ['singlecontractfile.foo', 'singlecontractfile.bar'],
'layers': ['one', 'two'],
},
{
'name': 'Contract B',
'packages': ['singlecontractfile'],
'layers': ['one', 'two', 'three'],
'whitelisted_paths': [
('baz.utils', 'baz.three.green'),
('baz.three.blue', 'baz.two'),
],
},
]
sorted_contracts = sorted(contracts, key=lambda i: i.name)
for contract_index, contract in enumerate(sorted_contracts):
expected_data = expected_contracts[contract_index]
assert contract.name == expected_data['name']

for package_index, package in enumerate(contract.containers):
expected_package_name = expected_data['packages'][package_index]
assert package == Module(expected_package_name)

for layer_index, layer in enumerate(contract.layers):
expected_layer_data = expected_data['layers'][layer_index]
assert isinstance(layer, Layer)
assert layer.name == expected_layer_data

for whitelisted_index, whitelisted_path in enumerate(contract.whitelisted_paths):
expected_importer, expected_imported = expected_data['whitelisted_paths'][
whitelisted_index]
assert isinstance(whitelisted_path, ImportPath)
assert whitelisted_path.importer == Module(expected_importer)
assert whitelisted_path.imported == Module(expected_imported)
class TestGetContracts:
def test_happy_path(self):
self._initialize_test()

contracts = get_contracts(self.filename_and_path, package_name='singlecontractfile')

assert len(contracts) == 2
expected_contracts = [
{
'name': 'Contract A',
'packages': ['singlecontractfile.foo', 'singlecontractfile.bar'],
'layers': ['one', 'two'],
},
{
'name': 'Contract B',
'packages': ['singlecontractfile'],
'layers': ['one', 'two', 'three'],
'whitelisted_paths': [
('baz.utils', 'baz.three.green'),
('baz.three.blue', 'baz.two'),
],
},
]
sorted_contracts = sorted(contracts, key=lambda i: i.name)
for contract_index, contract in enumerate(sorted_contracts):
expected_data = expected_contracts[contract_index]
assert contract.name == expected_data['name']

for package_index, package in enumerate(contract.containers):
expected_package_name = expected_data['packages'][package_index]
assert package == Module(expected_package_name)

for layer_index, layer in enumerate(contract.layers):
expected_layer_data = expected_data['layers'][layer_index]
assert isinstance(layer, Layer)
assert layer.name == expected_layer_data

for whitelisted_index, whitelisted_path in enumerate(contract.whitelisted_paths):
expected_importer, expected_imported = expected_data['whitelisted_paths'][
whitelisted_index]
assert isinstance(whitelisted_path, ImportPath)
assert whitelisted_path.importer == Module(expected_importer)
assert whitelisted_path.imported == Module(expected_imported)

def test_container_does_not_exist(self):
self._initialize_test('layers_with_missing_container.yml')

with pytest.raises(ValueError) as e:
get_contracts(self.filename_and_path, package_name='singlecontractfile')

assert str(e.value) == "Invalid container 'singlecontractfile.missing': no such package."

def _initialize_test(self, config_filename='layers.yml'):
# Append the package directory to the path.
dirname = os.path.dirname(__file__)
package_dirname = os.path.join(dirname, '..', 'assets', 'singlecontractfile')
sys.path.append(package_dirname)

# Set the full config filename and path as an instance attribute.
self.filename_and_path = os.path.join(package_dirname, config_filename)
10 changes: 10 additions & 0 deletions tests/functional/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ def test_specify_config_file(self, verbosity_count, is_quiet, should_always_fail
else:
assert result == EXIT_STATUS_SUCCESS

def test_missing_container(self, verbosity_count, is_quiet, should_always_fail):
package_name = 'successpackage'
self._chdir_and_add_to_system_path(package_name)

result = _main(package_name,
config_filename='layers_with_missing_container.yml',
verbosity_count=verbosity_count, is_quiet=is_quiet)

assert result == EXIT_STATUS_ERROR

def _chdir_and_add_to_system_path(self, package_name):
path = os.path.join(assets_path, package_name)
sys.path.append(path)
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/test_contract.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from unittest import mock
import importlib
import pytest
from layer_linter import contract
from layer_linter.module import Module
Expand Down Expand Up @@ -286,8 +287,10 @@ def test_only_shortest_violation_is_reported(self, longer_first):
]


@mock.patch.object(importlib.util, 'find_spec')
class TestContractFromYAML:
def test_incorrect_whitelisted_path_format(self):

def test_incorrect_whitelisted_path_format(self, mock_find_spec):
data = {
'containers': ['mypackage.foo', 'mypackage.bar'],
'layers': ['one', 'two'],
Expand All @@ -303,7 +306,7 @@ def test_incorrect_whitelisted_path_format(self):
'"importer.module <- imported.module".'
)

def test_container_not_in_package(self):
def test_container_not_in_package(self, mock_find_spec):
data = {
'containers': ['mypackage.foo', 'anotherpackage.foo'],
'layers': ['one', 'two'],
Expand Down

0 comments on commit 109fc4e

Please sign in to comment.