From c1f6cecb213e48ac102fa64c13e2a30a8206b8c4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 18 Feb 2022 14:47:13 -0500 Subject: [PATCH] Combine validation and duplication tests for efficiency --- .github/workflows/validation.yml | 2 +- tests/definitions_test.py | 38 ++++++++++++++++++-- tests/dupes_test.py | 61 -------------------------------- 3 files changed, 36 insertions(+), 65 deletions(-) delete mode 100644 tests/dupes_test.py diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index 8eb49d64..f8e2019f 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v1 with: - python-version: 3.6 + python-version: 3.8 - name: Install dependencies run: pip install -r requirements.txt - name: Lint YAML files diff --git a/tests/definitions_test.py b/tests/definitions_test.py index 5146bce1..d2c96283 100644 --- a/tests/definitions_test.py +++ b/tests/definitions_test.py @@ -3,7 +3,7 @@ import json import os import pytest import yaml -from jsonschema import validate, RefResolver, Draft4Validator +from jsonschema import RefResolver, Draft4Validator from jsonschema.exceptions import ValidationError @@ -12,6 +12,18 @@ SCHEMAS = ( ('module-types', 'moduletype.json'), ) +COMPONENT_TYPES = ( + 'console-ports', + 'console-server-ports', + 'power-ports', + 'power-outlets', + 'interfaces', + 'front-ports', + 'rear-ports', + 'device-bays', + 'module-bays', +) + def _get_definition_files(): """ @@ -29,13 +41,14 @@ def _get_definition_files(): assert schema, f"Schema definition for {path} is empty!" # Map each definition file to its schema - for f in glob.glob(f"{path}/*/*", recursive=True): + for f in sorted(glob.glob(f"{path}/*/*", recursive=True)): ret.append((f, schema)) return ret definition_files = _get_definition_files() +known_slugs = set() def test_environment(): @@ -49,7 +62,7 @@ def test_environment(): @pytest.mark.parametrize(('file_path', 'schema'), definition_files) def test_definitions(file_path, schema): """ - Validate each definition file using the provided JSON schema. + Validate each definition file using the provided JSON schema and check for duplicate entries. """ # Check file extension assert file_path.split('.')[-1] in ('yaml', 'yml'), f"Invalid file extension: {file_path}" @@ -64,8 +77,27 @@ def test_definitions(file_path, schema): # Load YAML data from file definition = yaml.load(content, Loader=yaml.SafeLoader) + # Validate YAML definition against the supplied schema try: resolver = RefResolver(f'file://{os.getcwd()}/schema/devicetype.json', schema) Draft4Validator(schema, resolver=resolver).validate(definition) except ValidationError as e: pytest.fail(f"{file_path} failed validation: {e}", False) + + # Check for duplicate slug + if file_path.startswith('device-types/'): + slug = definition.get('slug') + if slug and slug in known_slugs: + pytest.fail(f'{file_path} device type has duplicate slug "{slug}"', False) + elif slug: + known_slugs.add(slug) + + # Check for duplicate components + for component_type in COMPONENT_TYPES: + known_names = set() + defined_components = definition.get(component_type, []) + for idx, component in enumerate(defined_components): + name = component.get('name') + if name in known_names: + pytest.fail(f'Duplicate entry "{name}" in {component_type} list', False) + known_names.add(name) diff --git a/tests/dupes_test.py b/tests/dupes_test.py deleted file mode 100644 index 7d77811b..00000000 --- a/tests/dupes_test.py +++ /dev/null @@ -1,61 +0,0 @@ -import glob -import json -import pytest -import yaml - -KNOWN_MODELS = {} - -def _get_definition_files(): - """ - Return a list of all definition files. - """ - return [f for f in glob.glob("device-types/*/*", recursive=True)] - -def test_environment(): - """ - Run basic sanity checks on the environment to ensure tests are running correctly. - """ - # Validate that definition files exist - assert _get_definition_files(), "No definition files found!" - -@pytest.mark.parametrize("file_path", _get_definition_files()) -def test_dupes(file_path): - # Check file extension - assert file_path.split('.')[-1] in ('yaml', 'yml'), f"Invalid file extension: {file_path}" - - # Read file - with open(file_path) as definition_file: - content = definition_file.read() - - # Check for trailing newline - assert content[-1] == '\n', "Missing trailing newline" - - # Load YAML data - definition = yaml.load(content, Loader=yaml.SafeLoader) - - slug = definition.get('slug') - - if KNOWN_MODELS.get(slug, None) is not None: - pytest.fail(f"{file_path} is a duplicate device_type for {slug}", False) - - KNOWN_MODELS[slug] = definition.get('model') - - def test_components(type): - KNOWN = [] - components = definition.get(type, None) - - if components is not None: - for idx,component in enumerate(components): - name = component.get('name') - if name in KNOWN: - pytest.fail(f'Duplicate {type} "{name}" in {file_path}', False) - KNOWN.append(name) - - test_components('interfaces') - test_components('device-bays') - test_components('front-ports') - test_components('rear-ports') - test_components('power-ports') - test_components('power-outlets') - test_components('console-ports') - test_components('console-server-ports')