diff --git a/brian_polling_manager/interface_stats/vendors/nokia.py b/brian_polling_manager/interface_stats/vendors/nokia.py index a8879fbc96cd69ead2458f919b934d3ddfd4a4e5..d458ed43301d9e023a8dfc7eb10d9441cd20af44 100644 --- a/brian_polling_manager/interface_stats/vendors/nokia.py +++ b/brian_polling_manager/interface_stats/vendors/nokia.py @@ -19,7 +19,7 @@ NCCLIENT_PARAMS = { } INTERFACE_COUNTERS = { - # Counters must be floats to be compatible with influx writing to the same + # Counters must be floats to be compatible with sensu writing to the same # measurement. cf https://github.com/sensu/sensu-go/issues/2213 "__defaults__": {"transform": float, "required": False}, "name": { @@ -51,7 +51,7 @@ INTERFACE_COUNTERS = { } INTERFACE_COUNTERS_ALT = { - # Counters must be floats to be compatible with influx writing to the same + # Counters must be floats to be compatible with sensu writing to the same # measurement. cf https://github.com/sensu/sensu-go/issues/2213 "__defaults__": {"transform": float, "required": False}, "name": { diff --git a/test/interface_stats/conftest.py b/test/interface_stats/conftest.py index 99585822674f340181357fe762a3afd38cb245ac..6edb22a042509a922ba1f1c607a212b87a75d5b9 100644 --- a/test/interface_stats/conftest.py +++ b/test/interface_stats/conftest.py @@ -97,3 +97,43 @@ def nokia_router_fqdn(request): # do a pytest.mark.parametrize instead but we'd have to redefine NOKIA_ROUTERS in # the test module or import from this conftest directly return request.param + + +@pytest.fixture +def schemavalidate(): + """Minimal jsonschema validation. Just enough to validate the various interface + point dictionaries. Does not resolve $ref. Custom implementation because jsonschema + is slooooooow""" + + def _validate(obj, schema): + type_ = schema.get("type") + + if type_ == "object": + assert isinstance(obj, dict) + assert set(schema.get("required", [])).issubset(obj.keys()) + + additionalProperties = schema.get("additionalProperties", True) + + properties = schema.get("properties", {}) + if not additionalProperties: + assert set(obj).issubset(properties) + + for key, val in obj.items(): + if key not in properties: + if isinstance(additionalProperties, dict): + _validate(val, additionalProperties) + continue + subschema = properties[key] + if "type" not in subschema: + continue + _validate(val, subschema) + elif type_ == "number": + assert isinstance(obj, (float, int)) + elif type_ == "integer": + assert isinstance(obj, int) + elif type_ == "string": + assert isinstance(obj, str) + else: + raise ValueError(f"unsuppported type '{type_}'") + + return _validate diff --git a/test/interface_stats/test_interface_stats.py b/test/interface_stats/test_interface_stats.py index c5ada9c2a876f4395c77bc95f9746599f0d94f4d..169a09ac09e960ab9eb57ad80e802bf6901fe475 100644 --- a/test/interface_stats/test_interface_stats.py +++ b/test/interface_stats/test_interface_stats.py @@ -2,7 +2,6 @@ from datetime import datetime from unittest.mock import Mock, call, patch from brian_polling_manager import influx -import jsonschema import pytest from brian_polling_manager.interface_stats import cli from brian_polling_manager.interface_stats.cli import PointGroup, Vendor @@ -169,8 +168,9 @@ def test_no_error_point_counters(): @patch.object(cli.OutputMethod, "write_points") +@pytest.mark.usefixtures("mocked_get_netconf") def test_main_for_all_juniper_routers( - write_points, mocked_get_netconf, juniper_router_fqdn, juniper_inventory + write_points, juniper_router_fqdn, juniper_inventory, schemavalidate ): config = { "juniper": {"some": "params"}, @@ -187,7 +187,7 @@ def test_main_for_all_juniper_routers( assert points for point in points: total_points += 1 - jsonschema.validate(point, influx.INFLUX_POINT) + schemavalidate(point, influx.INFLUX_POINT) assert point["fields"] # must contain at least one field write_points.side_effect = validate diff --git a/test/interface_stats/test_juniper.py b/test/interface_stats/test_juniper.py index f6ecca551b53c6d7c18eeead34e1ad8774f158dc..1b4745fd406c988ce1dbabf6cc491b540033c1e3 100644 --- a/test/interface_stats/test_juniper.py +++ b/test/interface_stats/test_juniper.py @@ -1,7 +1,6 @@ from datetime import datetime from unittest.mock import call, patch -import jsonschema import pytest from brian_polling_manager import influx from brian_polling_manager.interface_stats.vendors import common, juniper @@ -176,9 +175,10 @@ def test_juniper_router_docs_do_not_generate_errors( def test_validate_interface_counters_and_influx_points_for_all_juniper_routers( - juniper_router_fqdn, get_netconf, juniper_inventory + juniper_router_fqdn, get_netconf, juniper_inventory, schemavalidate ): doc = get_netconf(juniper_router_fqdn) + interfaces = list( juniper.interface_counters( doc, interfaces=juniper_inventory[juniper_router_fqdn] @@ -186,7 +186,8 @@ def test_validate_interface_counters_and_influx_points_for_all_juniper_routers( ) assert interfaces for ifc in interfaces: - jsonschema.validate(ifc, common.INTERFACE_COUNTER_SCHEMA) + schemavalidate(ifc, common.INTERFACE_COUNTER_SCHEMA) + schemavalidate(ifc["brian"], common.BRIAN_POINT_FIELDS_SCHEMA) bpoints = list( common.brian_points( @@ -198,10 +199,11 @@ def test_validate_interface_counters_and_influx_points_for_all_juniper_routers( ) assert bpoints for point in bpoints: - jsonschema.validate(point, influx.INFLUX_POINT) - jsonschema.validate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA) + schemavalidate(point, influx.INFLUX_POINT) + schemavalidate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA) for value in point['fields'].values(): assert isinstance(value, float) + epoints = list( common.error_points( juniper_router_fqdn, @@ -212,10 +214,8 @@ def test_validate_interface_counters_and_influx_points_for_all_juniper_routers( ) assert epoints for point in epoints: - jsonschema.validate(point, influx.INFLUX_POINT) - jsonschema.validate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA) - for value in point['fields'].values(): - assert isinstance(value, int) + schemavalidate(point, influx.INFLUX_POINT) + schemavalidate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA) class TestGetJuniperNetConf: diff --git a/test/interface_stats/test_nokia.py b/test/interface_stats/test_nokia.py index 6bffba144f461d88bc9cd60940129c170c5ef562..1b368d17a3940704dad757ebc720d01c25e915cb 100644 --- a/test/interface_stats/test_nokia.py +++ b/test/interface_stats/test_nokia.py @@ -2,7 +2,6 @@ from datetime import datetime from unittest.mock import call, patch from brian_polling_manager import influx from brian_polling_manager.interface_stats.vendors import common, nokia -import jsonschema import pytest from lxml import etree @@ -183,13 +182,13 @@ def test_nokia_router_docs_do_not_generate_errors( def test_validate_interface_counters_and_influx_points_for_all_nokia_routers( - nokia_router_fqdn, get_netconf + nokia_router_fqdn, get_netconf, schemavalidate ): doc = get_netconf(nokia_router_fqdn) interfaces = list(nokia.interface_counters(doc)) assert interfaces for ifc in interfaces: - jsonschema.validate(ifc, common.INTERFACE_COUNTER_SCHEMA) + schemavalidate(ifc, common.INTERFACE_COUNTER_SCHEMA) bpoints = list( common.brian_points( @@ -201,8 +200,8 @@ def test_validate_interface_counters_and_influx_points_for_all_nokia_routers( ) assert bpoints for point in bpoints: - jsonschema.validate(point, influx.INFLUX_POINT) - jsonschema.validate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA) + schemavalidate(point, influx.INFLUX_POINT) + schemavalidate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA) epoints = list( common.error_points( @@ -214,8 +213,8 @@ def test_validate_interface_counters_and_influx_points_for_all_nokia_routers( ) assert epoints for point in epoints: - jsonschema.validate(point, influx.INFLUX_POINT) - jsonschema.validate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA) + schemavalidate(point, influx.INFLUX_POINT) + schemavalidate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA) def test_processes_specific_interfaces(get_netconf, caplog):