From 70a75ec4693d193feda7f81afe4a210a8ca885e3 Mon Sep 17 00:00:00 2001 From: "Daniel W. Anner" Date: Wed, 27 Mar 2024 16:53:45 -0400 Subject: [PATCH] updating test code for new jsonschema version. removing old refresolver that is deprecated. updating schemas. (#2038) --- requirements.txt | 2 +- schema/components.json | 24 +++++++++++++----------- schema/devicetype.json | 30 ++++++++++++++++-------------- schema/generated_schema.json | 2 ++ schema/moduletype.json | 20 +++++++++++--------- schema/reusable.json | 4 +++- tests/definitions_test.py | 29 ++++++++++++++++++++--------- tests/test_configuration.py | 3 ++- 8 files changed, 68 insertions(+), 46 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5f246edac..ddf67526d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -jsonschema==4.19.0 +jsonschema==4.21.1 jsondiff==2.0.0 pre-commit==3.6.0 pytest==7.4.4 diff --git a/schema/components.json b/schema/components.json index 6df42f086..082a13b63 100644 --- a/schema/components.json +++ b/schema/components.json @@ -1,5 +1,7 @@ { "type": "object", + "$id": "urn:devicetype-library:components", + "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "definitions": { "console-port": { @@ -12,7 +14,7 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/console-port/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/console-port/properties/type" }, "poe": { "type": "boolean" @@ -33,7 +35,7 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/console-server-port/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/console-server-port/properties/type" } }, "required": [ @@ -51,7 +53,7 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/power-port/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/power-port/properties/type" }, "maximum_draw": { "type": "integer" @@ -75,13 +77,13 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/power-outlet/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/power-outlet/properties/type" }, "power_port": { "type": "string" }, "feed_leg": { - "$ref": "generated_schema.json#/definitions/power-outlet/properties/feed-leg" + "$ref": "urn:devicetype-library:generated-schema#/definitions/power-outlet/properties/feed-leg" } }, "required": [ @@ -99,13 +101,13 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/interface/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/interface/properties/type" }, "poe_mode": { - "$ref": "generated_schema.json#/definitions/interface/properties/poe_mode" + "$ref": "urn:devicetype-library:generated-schema#/definitions/interface/properties/poe_mode" }, "poe_type": { - "$ref": "generated_schema.json#/definitions/interface/properties/poe_type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/interface/properties/poe_type" }, "mgmt_only": { "type": "boolean" @@ -126,7 +128,7 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/front-port/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/front-port/properties/type" }, "color": { "type": "string", @@ -155,7 +157,7 @@ "type": "string" }, "type": { - "$ref": "generated_schema.json#/definitions/rear-port/properties/type" + "$ref": "urn:devicetype-library:generated-schema#/definitions/rear-port/properties/type" }, "color": { "type": "string", @@ -225,4 +227,4 @@ ] } } -} \ No newline at end of file +} diff --git a/schema/devicetype.json b/schema/devicetype.json index 62843158a..24820c87a 100644 --- a/schema/devicetype.json +++ b/schema/devicetype.json @@ -1,5 +1,7 @@ { "type": "object", + "$id": "urn:devicetype-library:device-type", + "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "manufacturer": { "type": "string" @@ -23,13 +25,13 @@ "type": "boolean" }, "airflow": { - "$ref": "generated_schema.json#/definitions/airflow" + "$ref": "urn:devicetype-library:generated-schema#/definitions/airflow" }, "weight": { - "$ref": "reusable.json#/definitions/weight" + "$ref": "urn:devicetype-library:reusable#/definitions/weight" }, "weight_unit": { - "$ref": "generated_schema.json#/definitions/weight-unit" + "$ref": "urn:devicetype-library:generated-schema#/definitions/weight-unit" }, "front_image": { "type": "boolean" @@ -38,7 +40,7 @@ "type": "boolean" }, "subdevice_role": { - "$ref": "generated_schema.json#/definitions/subdevice-role" + "$ref": "urn:devicetype-library:generated-schema#/definitions/subdevice-role" }, "is_powered": { "type": "boolean" @@ -46,61 +48,61 @@ "console-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/console-port" + "$ref": "urn:devicetype-library:components#/definitions/console-port" } }, "console-server-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/console-server-port" + "$ref": "urn:devicetype-library:components#/definitions/console-server-port" } }, "power-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/power-port" + "$ref": "urn:devicetype-library:components#/definitions/power-port" } }, "power-outlets": { "type": "array", "items": { - "$ref": "components.json#/definitions/power-outlet" + "$ref": "urn:devicetype-library:components#/definitions/power-outlet" } }, "interfaces": { "type": "array", "items": { - "$ref": "components.json#/definitions/interface" + "$ref": "urn:devicetype-library:components#/definitions/interface" } }, "front-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/front-port" + "$ref": "urn:devicetype-library:components#/definitions/front-port" } }, "rear-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/rear-port" + "$ref": "urn:devicetype-library:components#/definitions/rear-port" } }, "module-bays": { "type": "array", "items": { - "$ref": "components.json#/definitions/module-bay" + "$ref": "urn:devicetype-library:components#/definitions/module-bay" } }, "device-bays": { "type": "array", "items": { - "$ref": "components.json#/definitions/device-bay" + "$ref": "urn:devicetype-library:components#/definitions/device-bay" } }, "inventory-items": { "type": "array", "items": { - "$ref": "components.json#/definitions/inventory-item" + "$ref": "urn:devicetype-library:components#/definitions/inventory-item" } }, "description": { diff --git a/schema/generated_schema.json b/schema/generated_schema.json index 1164f2e48..b6632dd4c 100644 --- a/schema/generated_schema.json +++ b/schema/generated_schema.json @@ -1,5 +1,7 @@ { "type": "object", + "$id": "urn:devicetype-library:generated-schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "definitions": { "airflow": { diff --git a/schema/moduletype.json b/schema/moduletype.json index 2c0781c85..25d434d5f 100644 --- a/schema/moduletype.json +++ b/schema/moduletype.json @@ -1,5 +1,7 @@ { "type": "object", + "$id": "urn:devicetype-library:module-type", + "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": { "manufacturer": { "type": "string" @@ -11,51 +13,51 @@ "type": "string" }, "weight": { - "$ref": "reusable.json#/definitions/weight" + "$ref": "urn:devicetype-library:reusable#/definitions/weight" }, "weight_unit": { - "$ref": "generated_schema.json#/definitions/weight-unit" + "$ref": "urn:devicetype-library:generated-schema#/definitions/weight-unit" }, "console-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/console-port" + "$ref": "urn:devicetype-library:components#/definitions/console-port" } }, "console-server-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/console-server-port" + "$ref": "urn:devicetype-library:components#/definitions/console-server-port" } }, "power-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/power-port" + "$ref": "urn:devicetype-library:components#/definitions/power-port" } }, "power-outlets": { "type": "array", "items": { - "$ref": "components.json#/definitions/power-outlet" + "$ref": "urn:devicetype-library:components#/definitions/power-outlet" } }, "interfaces": { "type": "array", "items": { - "$ref": "components.json#/definitions/interface" + "$ref": "urn:devicetype-library:components#/definitions/interface" } }, "front-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/front-port" + "$ref": "urn:devicetype-library:components#/definitions/front-port" } }, "rear-ports": { "type": "array", "items": { - "$ref": "components.json#/definitions/rear-port" + "$ref": "urn:devicetype-library:components#/definitions/rear-port" } }, "description": { diff --git a/schema/reusable.json b/schema/reusable.json index 965ff1df5..d446a7b50 100644 --- a/schema/reusable.json +++ b/schema/reusable.json @@ -1,5 +1,7 @@ { "type": "object", + "$id": "urn:devicetype-library:reusable", + "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "definitions": { "weight": { @@ -8,4 +10,4 @@ "multipleOf": 0.01 } } -} \ No newline at end of file +} diff --git a/tests/definitions_test.py b/tests/definitions_test.py index 00144e21f..dc3275671 100644 --- a/tests/definitions_test.py +++ b/tests/definitions_test.py @@ -1,4 +1,4 @@ -from test_configuration import COMPONENT_TYPES, IMAGE_FILETYPES, SCHEMAS, KNOWN_SLUGS, ROOT_DIR, USE_LOCAL_KNOWN_SLUGS, NETBOX_DT_LIBRARY_URL, KNOWN_MODULES, USE_UPSTREAM_DIFF, PRECOMMIT_ALL_SWITCHES +from test_configuration import COMPONENT_TYPES, IMAGE_FILETYPES, SCHEMAS, SCHEMAS_BASEPATH, KNOWN_SLUGS, ROOT_DIR, USE_LOCAL_KNOWN_SLUGS, NETBOX_DT_LIBRARY_URL, KNOWN_MODULES, USE_UPSTREAM_DIFF, PRECOMMIT_ALL_SWITCHES import pickle_operations from yaml_loader import DecimalSafeLoader from device_types import DeviceType, ModuleType, verify_filename, validate_components @@ -9,10 +9,10 @@ import os import tempfile import psutil from urllib.request import urlopen - import pytest import yaml -from jsonschema import Draft4Validator, RefResolver +from referencing import Registry, Resource +from jsonschema import Draft202012Validator from jsonschema.exceptions import ValidationError from git import Repo @@ -36,6 +36,20 @@ def _get_definition_files(): return file_list +def _generate_schema_registry(): + """ + Return a list of all definition files within the specified path. + """ + registry = Registry() + + for schema_f in os.listdir(SCHEMAS_BASEPATH): + # Initialize the schema + with open(f"schema/{schema_f}") as schema_file: + resource = Resource.from_contents(json.loads(schema_file.read(), parse_float=decimal.Decimal)) + registry = resource @ registry + + return registry + def _get_diff_from_upstream(): file_list = [] @@ -126,6 +140,7 @@ else: KNOWN_SLUGS = pickle_operations.read_pickle_data(f'{temp_dir.name}/tests/known-slugs.pickle') KNOWN_MODULES = pickle_operations.read_pickle_data(f'{temp_dir.name}/tests/known-modules.pickle') +SCHEMA_REGISTRY = _generate_schema_registry() @pytest.mark.parametrize(('file_path', 'schema', 'change_type'), definition_files) def test_definitions(file_path, schema, change_type): @@ -147,13 +162,9 @@ def test_definitions(file_path, schema, change_type): # Validate YAML definition against the supplied schema try: - resolver = RefResolver( - f"file://{os.getcwd()}/schema/devicetype.json", - schema, - handlers={"file": _decimal_file_handler}, - ) # Validate definition against schema - Draft4Validator(schema, resolver=resolver).validate(definition) + validator = Draft202012Validator(schema, registry=SCHEMA_REGISTRY) + validator.validate(definition) except ValidationError as e: # Schema validation failure. Ensure you are following the proper format. pytest.fail(f"{file_path} failed validation: {e}", False) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 2082033b7..6102cc0e7 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -4,6 +4,7 @@ SCHEMAS = ( ('device-types', 'devicetype.json'), ('module-types', 'moduletype.json'), ) +SCHEMAS_BASEPATH = f"{os.getcwd()}/schema/" IMAGE_FILETYPES = ( 'bmp', 'gif', 'pjp', 'jpg', 'pjpeg', 'jpeg', 'jfif', 'png', 'tif', 'tiff', 'webp' @@ -35,4 +36,4 @@ KNOWN_MODULES = set() USE_LOCAL_KNOWN_SLUGS = False USE_UPSTREAM_DIFF = True -NETBOX_DT_LIBRARY_URL = "https://github.com/netbox-community/devicetype-library.git" \ No newline at end of file +NETBOX_DT_LIBRARY_URL = "https://github.com/netbox-community/devicetype-library.git"