diff --git a/brian_polling_manager/sensu.py b/brian_polling_manager/sensu.py index b1d429568e6a218afdd698cb3f98f495ad7190e6..e31545ba678c64a4542fcdc6c5df5a556609c074 100644 --- a/brian_polling_manager/sensu.py +++ b/brian_polling_manager/sensu.py @@ -1,7 +1,7 @@ """ Sensu api utilities """ -import functools +import copy import logging import random import requests @@ -97,7 +97,7 @@ def checks_match(a, b) -> bool: class AbstractCheck(object): """ - not explicitly using abc.ABC, to avoid stacks of decorators + not explicitly using abc.ABC ... more readable than stacks of decorators """ INTERVAL_S = 300 @@ -106,12 +106,54 @@ class AbstractCheck(object): METRIC_HANDLERS = ['influx-db-handler'] NAMESPACE = 'default' + CHECK_DICT_SCHEMA = { + # for unit tests + '$schema': 'http://json-schema.org/draft-07/schema#', + + 'definitions': { + 'metadata': { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'namespace': {'type': 'string'} + }, + 'required': ['name', 'namespace'] + } + }, + + 'type': 'object', + 'properties': { + 'command': {'type': 'string'}, + 'interval': {'type': 'integer'}, + 'subscriptions': { + 'type': 'array', + 'items': {'type': 'string'}, + 'minItems': 1 + }, + 'proxy_entity_name': {'type': 'string'}, + 'round_robin': {'type': 'boolean'}, + 'output_metric_format': {'type': 'string'}, + 'output_metric_handlers': { + 'type': 'array', + 'items': {'type': 'string'}, + 'minItems': 1 + }, + 'metadata': {'$ref': '#/definitions/metadata'}, + 'publish': {'type': 'boolean'} + }, + 'required': [ + 'command', 'interval', 'subscriptions', + 'proxy_entity_name', 'round_robin', + 'output_metric_format', 'output_metric_handlers', + 'metadata', 'publish'] + } + def __init__(self): self.publish = True self.round_robin = True self.interval = AbstractCheck.INTERVAL_S - self.subscriptions = AbstractCheck.SUBSCRIPTIONS - self.output_metric_handlers = AbstractCheck.METRIC_HANDLERS + self.subscriptions = copy.copy(AbstractCheck.SUBSCRIPTIONS) + self.output_metric_handlers = copy.copy(AbstractCheck.METRIC_HANDLERS) self.output_metric_format = AbstractCheck.METRIC_FORMAT self.namespace = AbstractCheck.NAMESPACE diff --git a/test/test_sensu_checks.py b/test/test_sensu_checks.py index 7e48b600c8142a4a090ac017397cb1598bba4328..a57762165b8d46a7e2ba9dd26d591dd4aebdbf41 100644 --- a/test/test_sensu_checks.py +++ b/test/test_sensu_checks.py @@ -1,6 +1,7 @@ import copy import random +import jsonschema import responses from brian_polling_manager import sensu, inventory, interfaces @@ -38,3 +39,85 @@ def test_check_lifecycle(config, mocked_sensu, mocked_inventory): # delete the check and confirm the correct call was made sensu.delete_check(config['sensu'], check_name) assert check_name not in mocked_sensu + + +class TestingCheck(sensu.AbstractCheck): + + def __init__(self, name, command, proxy_entity_name): + super().__init__() + self._name = name + self._command = command + self._proxy_entity_name = proxy_entity_name + + @sensu.AbstractCheck.name.getter + def name(self): + return self._name + + @sensu.AbstractCheck.command.getter + def command(self): + return self._command + + @sensu.AbstractCheck.proxy_entity_name.getter + def proxy_entity_name(self): + return self._proxy_entity_name + + +def test_check_dict_schema(): + c = TestingCheck(name='x', command='y', proxy_entity_name='z') + jsonschema.validate(c.to_dict(), sensu.AbstractCheck.CHECK_DICT_SCHEMA) + + +def test_check_compare(): + a = TestingCheck(name='x', command='y', proxy_entity_name='z') + b = TestingCheck(name='x', command='y', proxy_entity_name='z') + assert sensu.checks_match(a.to_dict(), b.to_dict()) + + +def test_checks_differ(): + a = TestingCheck(name='x', command='x', proxy_entity_name='1') + b = TestingCheck(name='x', command='x', proxy_entity_name='2') + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='1', proxy_entity_name='x') + b = TestingCheck(name='x', command='2', proxy_entity_name='x') + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='1', command='x', proxy_entity_name='x') + b = TestingCheck(name='2', command='x', proxy_entity_name='x') + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.publish = not a.publish + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.interval += 1 + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.round_robin = not a.round_robin + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.output_metric_format = a.output_metric_format + 'x' + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.subscriptions.append('x') + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.output_metric_handlers.append('x') + assert not sensu.checks_match(a.to_dict(), b.to_dict()) + + a = TestingCheck(name='x', command='x', proxy_entity_name='x') + b = TestingCheck(name='x', command='x', proxy_entity_name='x') + a.namespace = a.namespace + 'x' + assert not sensu.checks_match(a.to_dict(), b.to_dict()) +