parent
f5ab1d1b6a
commit
3d762f7800
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
bugfixes:
|
||||
- linting and formatting for CI
|
|
@ -1,3 +1,3 @@
|
|||
---
|
||||
major_changes:
|
||||
- Added validate module/lookup/filter/test plugin to validate data based on given criteria
|
||||
minor_changes:
|
||||
- Added fact_diff plugin and sub plugin
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
major_changes:
|
||||
- test ci.
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
minor_changes:
|
||||
- Added validate module/lookup/filter/test plugin to validate data based on given criteria
|
|
@ -68,7 +68,9 @@ class ActionModule(ActionBase):
|
|||
return argspec_result
|
||||
|
||||
self._task_vars = task_vars
|
||||
self._playhost = task_vars.get("inventory_hostname") if task_vars else None
|
||||
self._playhost = (
|
||||
task_vars.get("inventory_hostname") if task_vars else None
|
||||
)
|
||||
|
||||
self._validator_engine, validator_result = load_validator(
|
||||
engine=updated_params["engine"],
|
||||
|
|
|
@ -40,11 +40,9 @@ def load_validator(
|
|||
return None, result
|
||||
|
||||
cref = dict(zip(["corg", "cname", "plugin"], engine.split(".")))
|
||||
validatorlib = (
|
||||
"ansible_collections.{corg}.{cname}.plugins.validate.{plugin}".format(
|
||||
validatorlib = "ansible_collections.{corg}.{cname}.plugins.validate.{plugin}".format(
|
||||
**cref
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
validatorcls = getattr(import_module(validatorlib), cls_name)
|
||||
|
|
|
@ -147,7 +147,7 @@ def validate(*args, **kwargs):
|
|||
|
||||
class TestModule(object):
|
||||
"""data validation test"""
|
||||
# For testing
|
||||
|
||||
test_map = {"validate": validate}
|
||||
|
||||
def tests(self):
|
||||
|
|
|
@ -46,12 +46,20 @@ from ansible.module_utils.basic import missing_required_lib
|
|||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
from ansible_collections.ansible.utils.plugins.validate._base import ValidateBase
|
||||
from ansible_collections.ansible.utils.plugins.validate._base import (
|
||||
ValidateBase,
|
||||
)
|
||||
|
||||
from ansible_collections.ansible.utils.plugins.module_utils.common.utils import (
|
||||
to_list,
|
||||
)
|
||||
|
||||
# PY2 compatiblilty for JSONDecodeError
|
||||
try:
|
||||
from json.decoder import JSONDecodeError
|
||||
except ImportError:
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
try:
|
||||
import jsonschema
|
||||
|
||||
|
@ -100,7 +108,7 @@ class Validate(ValidateBase):
|
|||
)
|
||||
raise AnsibleError(msg)
|
||||
|
||||
except (TypeError, json.decoder.JSONDecodeError) as exe:
|
||||
except (TypeError, JSONDecodeError) as exe:
|
||||
msg = (
|
||||
"'data' option value is invalid, value should of type dict or str format of dict."
|
||||
" Failed to read with error '{err}'".format(
|
||||
|
@ -123,7 +131,7 @@ class Validate(ValidateBase):
|
|||
raise AnsibleError(msg)
|
||||
|
||||
self._criteria = criteria
|
||||
except (TypeError, json.decoder.JSONDecodeError) as exe:
|
||||
except (TypeError, JSONDecodeError) as exe:
|
||||
msg = (
|
||||
"'criteria' option value is invalid, value should of type dict or str format of dict."
|
||||
" Failed to read with error '{err}'".format(
|
||||
|
@ -200,12 +208,10 @@ class Validate(ValidateBase):
|
|||
"found": validation_error.instance,
|
||||
}
|
||||
self._result["errors"].append(error)
|
||||
error_message = (
|
||||
"At '{schema_path}' {message}. ".format(
|
||||
error_message = "At '{schema_path}' {message}. ".format(
|
||||
schema_path=error["schema_path"],
|
||||
message=error["message"],
|
||||
)
|
||||
)
|
||||
error_messages.append(error_message)
|
||||
if error_messages:
|
||||
if "msg" not in self._result:
|
||||
|
|
|
@ -9,7 +9,6 @@ __metaclass__ = type
|
|||
|
||||
import re
|
||||
import unittest
|
||||
from mock import MagicMock
|
||||
from ansible.playbook.task import Task
|
||||
from ansible.template import Templar
|
||||
|
||||
|
@ -17,6 +16,11 @@ from ansible_collections.ansible.utils.plugins.action.fact_diff import (
|
|||
ActionModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from unittest.mock import MagicMock # pylint:disable=syntax-error
|
||||
except ImportError:
|
||||
from mock import MagicMock
|
||||
|
||||
|
||||
class TestUpdate_Fact(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -10,7 +10,6 @@ __metaclass__ = type
|
|||
import copy
|
||||
import unittest
|
||||
from jinja2 import Template, TemplateSyntaxError
|
||||
from mock import MagicMock
|
||||
from ansible.playbook.task import Task
|
||||
from ansible.template import Templar
|
||||
|
||||
|
@ -18,6 +17,12 @@ from ansible_collections.ansible.utils.plugins.action.update_fact import (
|
|||
ActionModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from unittest.mock import MagicMock # pylint:disable=syntax-error
|
||||
except ImportError:
|
||||
from mock import MagicMock
|
||||
|
||||
|
||||
VALID_DATA = {
|
||||
"a": {
|
||||
"b": {"4.4": [{"1": {5: {"foo": 123}}}], 5.5: "float5.5"},
|
||||
|
|
|
@ -7,10 +7,7 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
__metaclass__ = type
|
||||
|
||||
import copy
|
||||
import unittest
|
||||
from jinja2 import Template, TemplateSyntaxError
|
||||
from mock import MagicMock
|
||||
from ansible.playbook.task import Task
|
||||
from ansible.template import Templar
|
||||
from ansible.errors import AnsibleActionFail
|
||||
|
@ -19,16 +16,19 @@ from ansible_collections.ansible.utils.plugins.action.validate import (
|
|||
ActionModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from unittest.mock import MagicMock # pylint:disable=syntax-error
|
||||
except ImportError:
|
||||
from mock import MagicMock
|
||||
|
||||
|
||||
DATA = {
|
||||
"GigabitEthernet0/0/0/0": {
|
||||
"auto_negotiate": False,
|
||||
"counters": {
|
||||
"in_crc_errors": 0,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "configured using Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -36,17 +36,14 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "down",
|
||||
"type": "GigabitEthernet"
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
"GigabitEthernet0/0/0/1": {
|
||||
"auto_negotiate": False,
|
||||
"counters": {
|
||||
"in_crc_errors": 10,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "# interface is configures with Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -54,8 +51,8 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "up",
|
||||
"type": "GigabitEthernet"
|
||||
}
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_CRC_ERROR_CHECK = {
|
||||
|
@ -66,29 +63,19 @@ CRITERIA_CRC_ERROR_CHECK = {
|
|||
"properties": {
|
||||
"counters": {
|
||||
"properties": {
|
||||
"in_crc_errors": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_crc_errors": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_ENABLED_CHECK = {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"enum": [True]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"^.*": {"type": "object", "properties": {"enabled": {"enum": [True]}}}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_OPER_STATUS_UP_CHECK = {
|
||||
|
@ -96,14 +83,9 @@ CRITERIA_OPER_STATUS_UP_CHECK = {
|
|||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"oper_status": {
|
||||
"type": "string",
|
||||
"pattern": "up"
|
||||
}
|
||||
}
|
||||
}
|
||||
"properties": {"oper_status": {"type": "string", "pattern": "up"}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_IN_RATE_CHECK = {
|
||||
|
@ -116,17 +98,14 @@ CRITERIA_IN_RATE_CHECK = {
|
|||
"properties": {
|
||||
"rate": {
|
||||
"properties": {
|
||||
"in_rate": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_rate": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,41 +133,48 @@ class TestValidate(unittest.TestCase):
|
|||
# missing required arguments
|
||||
self._plugin._task.args = {"engine": "ansible.utils.jsonschema"}
|
||||
result = self._plugin.run(task_vars=None)
|
||||
self.assertIn("missing required arguments: criteria", result["errors"])
|
||||
msg = "missing required arguments criteria data"
|
||||
for word in msg.split():
|
||||
self.assertIn(word, result["errors"])
|
||||
|
||||
# invalid engine option value
|
||||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.sample",
|
||||
"data": DATA,
|
||||
"criteria": CRITERIA_OPER_STATUS_UP_CHECK
|
||||
"criteria": CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
}
|
||||
result = self._plugin.run(task_vars=None)
|
||||
self.assertIn("For engine 'ansible.utils.sample' error loading the corresponding validate plugin", result["msg"])
|
||||
self.assertIn(
|
||||
"For engine 'ansible.utils.sample' error loading the corresponding validate plugin",
|
||||
result["msg"],
|
||||
)
|
||||
|
||||
# invalid data option value
|
||||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"data": "invalid data",
|
||||
"criteria": CRITERIA_OPER_STATUS_UP_CHECK
|
||||
"criteria": CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
}
|
||||
|
||||
with self.assertRaises(AnsibleActionFail) as error:
|
||||
self._plugin.run(task_vars=None)
|
||||
self.assertIn(
|
||||
"'data' option value is invalid, value should of type dict or str format of dict", str(error.exception)
|
||||
"'data' option value is invalid, value should of type dict or str format of dict",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
# invalid criteria option value
|
||||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"data": DATA,
|
||||
"criteria": "invalid criteria"
|
||||
"criteria": "invalid criteria",
|
||||
}
|
||||
|
||||
with self.assertRaises(AnsibleActionFail) as error:
|
||||
self._plugin.run(task_vars=None)
|
||||
self.assertIn(
|
||||
"'criteria' option value is invalid, value should of type dict or str format of dict", str(error.exception)
|
||||
"'criteria' option value is invalid, value should of type dict or str format of dict",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
def test_invalid_validate_plugin_config_options(self):
|
||||
|
@ -197,11 +183,16 @@ class TestValidate(unittest.TestCase):
|
|||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"data": DATA,
|
||||
"criteria": CRITERIA_IN_RATE_CHECK
|
||||
"criteria": CRITERIA_IN_RATE_CHECK,
|
||||
}
|
||||
|
||||
result = self._plugin.run(task_vars={'ansible_validate_jsonschema_draft': 'draft0'})
|
||||
self.assertIn("value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0", result["msg"])
|
||||
result = self._plugin.run(
|
||||
task_vars={"ansible_validate_jsonschema_draft": "draft0"}
|
||||
)
|
||||
self.assertIn(
|
||||
"value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0",
|
||||
result["msg"],
|
||||
)
|
||||
|
||||
def test_invalid_data(self):
|
||||
"""Check passing invalid data as per criteria"""
|
||||
|
@ -209,13 +200,25 @@ class TestValidate(unittest.TestCase):
|
|||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"data": DATA,
|
||||
"criteria": [CRITERIA_CRC_ERROR_CHECK, CRITERIA_ENABLED_CHECK, CRITERIA_OPER_STATUS_UP_CHECK]
|
||||
"criteria": [
|
||||
CRITERIA_CRC_ERROR_CHECK,
|
||||
CRITERIA_ENABLED_CHECK,
|
||||
CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
],
|
||||
}
|
||||
|
||||
result = self._plugin.run(task_vars=None)
|
||||
self.assertIn("patternProperties.^.*.properties.counters.properties.in_crc_errors.maximum", result["msg"])
|
||||
self.assertIn("patternProperties.^.*.properties.enabled.enum", result["msg"])
|
||||
self.assertIn("'patternProperties.^.*.properties.oper_status.pattern", result["msg"])
|
||||
self.assertIn(
|
||||
"patternProperties.^.*.properties.counters.properties.in_crc_errors.maximum",
|
||||
result["msg"],
|
||||
)
|
||||
self.assertIn(
|
||||
"patternProperties.^.*.properties.enabled.enum", result["msg"]
|
||||
)
|
||||
self.assertIn(
|
||||
"'patternProperties.^.*.properties.oper_status.pattern",
|
||||
result["msg"],
|
||||
)
|
||||
|
||||
def test_valid_data(self):
|
||||
"""Check passing valid data as per criteria"""
|
||||
|
@ -223,7 +226,7 @@ class TestValidate(unittest.TestCase):
|
|||
self._plugin._task.args = {
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"data": DATA,
|
||||
"criteria": CRITERIA_IN_RATE_CHECK
|
||||
"criteria": CRITERIA_IN_RATE_CHECK,
|
||||
}
|
||||
|
||||
result = self._plugin.run(task_vars=None)
|
||||
|
|
|
@ -18,10 +18,7 @@ DATA = {
|
|||
"counters": {
|
||||
"in_crc_errors": 0,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "configured using Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -29,17 +26,14 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "down",
|
||||
"type": "GigabitEthernet"
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
"GigabitEthernet0/0/0/1": {
|
||||
"auto_negotiate": False,
|
||||
"counters": {
|
||||
"in_crc_errors": 10,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "# interface is configures with Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -47,8 +41,8 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "up",
|
||||
"type": "GigabitEthernet"
|
||||
}
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_CRC_ERROR_CHECK = {
|
||||
|
@ -59,29 +53,19 @@ CRITERIA_CRC_ERROR_CHECK = {
|
|||
"properties": {
|
||||
"counters": {
|
||||
"properties": {
|
||||
"in_crc_errors": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_crc_errors": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_ENABLED_CHECK = {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"enum": [True]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"^.*": {"type": "object", "properties": {"enabled": {"enum": [True]}}}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_OPER_STATUS_UP_CHECK = {
|
||||
|
@ -89,14 +73,9 @@ CRITERIA_OPER_STATUS_UP_CHECK = {
|
|||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"oper_status": {
|
||||
"type": "string",
|
||||
"pattern": "up"
|
||||
}
|
||||
}
|
||||
}
|
||||
"properties": {"oper_status": {"type": "string", "pattern": "up"}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_IN_RATE_CHECK = {
|
||||
|
@ -109,17 +88,14 @@ CRITERIA_IN_RATE_CHECK = {
|
|||
"properties": {
|
||||
"rate": {
|
||||
"properties": {
|
||||
"in_rate": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_rate": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,34 +112,35 @@ class TestValidate(unittest.TestCase):
|
|||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"Missing either 'data' or 'criteria' value in filter input, refer 'ansible.utils.validate' filter", str(error.exception)
|
||||
"Missing either 'data' or 'criteria' value in filter input, refer 'ansible.utils.validate' filter",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
# missing required arguments
|
||||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate([DATA], {})
|
||||
self.assertIn(
|
||||
"Expected value of 'data' option is either dict or str, received type", str(error.exception)
|
||||
"Expected value of 'data' option is either dict or str, received type",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
args = [DATA, [CRITERIA_IN_RATE_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.sample'}
|
||||
kwargs = {"engine": "ansible.utils.sample"}
|
||||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"For engine 'ansible.utils.sample' error loading", str(error.exception)
|
||||
"For engine 'ansible.utils.sample' error loading",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
args = ["invalid data", [CRITERIA_IN_RATE_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"'data' option value is invalid", str(error.exception)
|
||||
)
|
||||
self.assertIn("'data' option value is invalid", str(error.exception))
|
||||
|
||||
args = [DATA, "invalid criteria"]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
|
@ -173,18 +150,26 @@ class TestValidate(unittest.TestCase):
|
|||
def test_invalid_validate_plugin_config_options(self):
|
||||
"""Check passing invalid validate plugin options"""
|
||||
|
||||
args = [DATA, [CRITERIA_CRC_ERROR_CHECK, CRITERIA_ENABLED_CHECK, CRITERIA_OPER_STATUS_UP_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema', 'draft': 'draft0'}
|
||||
args = [
|
||||
DATA,
|
||||
[
|
||||
CRITERIA_CRC_ERROR_CHECK,
|
||||
CRITERIA_ENABLED_CHECK,
|
||||
CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
],
|
||||
]
|
||||
kwargs = {"engine": "ansible.utils.jsonschema", "draft": "draft0"}
|
||||
with self.assertRaises(AnsibleFilterError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0", str(error.exception)
|
||||
"value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
def test_valid_data(self):
|
||||
"""Check passing valid data as per criteria"""
|
||||
|
||||
args = [DATA, CRITERIA_IN_RATE_CHECK]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
result = validate(*args, **kwargs)
|
||||
self.assertEqual(result, [])
|
||||
|
|
|
@ -10,7 +10,9 @@ __metaclass__ = type
|
|||
import unittest
|
||||
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible_collections.ansible.utils.plugins.lookup.validate import LookupModule
|
||||
from ansible_collections.ansible.utils.plugins.lookup.validate import (
|
||||
LookupModule,
|
||||
)
|
||||
|
||||
DATA = {
|
||||
"GigabitEthernet0/0/0/0": {
|
||||
|
@ -18,10 +20,7 @@ DATA = {
|
|||
"counters": {
|
||||
"in_crc_errors": 0,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "configured using Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -29,17 +28,14 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "down",
|
||||
"type": "GigabitEthernet"
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
"GigabitEthernet0/0/0/1": {
|
||||
"auto_negotiate": False,
|
||||
"counters": {
|
||||
"in_crc_errors": 10,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "# interface is configures with Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -47,8 +43,8 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "up",
|
||||
"type": "GigabitEthernet"
|
||||
}
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_CRC_ERROR_CHECK = {
|
||||
|
@ -59,29 +55,19 @@ CRITERIA_CRC_ERROR_CHECK = {
|
|||
"properties": {
|
||||
"counters": {
|
||||
"properties": {
|
||||
"in_crc_errors": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_crc_errors": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_ENABLED_CHECK = {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"enum": [True]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"^.*": {"type": "object", "properties": {"enabled": {"enum": [True]}}}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_OPER_STATUS_UP_CHECK = {
|
||||
|
@ -89,14 +75,9 @@ CRITERIA_OPER_STATUS_UP_CHECK = {
|
|||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"oper_status": {
|
||||
"type": "string",
|
||||
"pattern": "up"
|
||||
}
|
||||
}
|
||||
}
|
||||
"properties": {"oper_status": {"type": "string", "pattern": "up"}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_IN_RATE_CHECK = {
|
||||
|
@ -109,17 +90,14 @@ CRITERIA_IN_RATE_CHECK = {
|
|||
"properties": {
|
||||
"rate": {
|
||||
"properties": {
|
||||
"in_rate": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_rate": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,25 +116,24 @@ class TestValidate(unittest.TestCase):
|
|||
)
|
||||
|
||||
terms = [DATA, [CRITERIA_IN_RATE_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.sample'}
|
||||
kwargs = {"engine": "ansible.utils.sample"}
|
||||
variables = {}
|
||||
with self.assertRaises(AnsibleLookupError) as error:
|
||||
self._lp.run(terms, variables, **kwargs)
|
||||
self.assertIn(
|
||||
"For engine 'ansible.utils.sample' error loading", str(error.exception)
|
||||
"For engine 'ansible.utils.sample' error loading",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
terms = ["invalid data", [CRITERIA_IN_RATE_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
variables = {}
|
||||
with self.assertRaises(AnsibleLookupError) as error:
|
||||
self._lp.run(terms, variables, **kwargs)
|
||||
self.assertIn(
|
||||
"'data' option value is invalid", str(error.exception)
|
||||
)
|
||||
self.assertIn("'data' option value is invalid", str(error.exception))
|
||||
|
||||
terms = [DATA, "invalid criteria"]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
variables = {}
|
||||
with self.assertRaises(AnsibleLookupError) as error:
|
||||
self._lp.run(terms, variables, **kwargs)
|
||||
|
@ -167,20 +144,31 @@ class TestValidate(unittest.TestCase):
|
|||
def test_invalid_validate_plugin_config_options(self):
|
||||
"""Check passing invalid validate plugin options"""
|
||||
|
||||
terms = [DATA, [CRITERIA_CRC_ERROR_CHECK, CRITERIA_ENABLED_CHECK, CRITERIA_OPER_STATUS_UP_CHECK]]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
terms = [
|
||||
DATA,
|
||||
[
|
||||
CRITERIA_CRC_ERROR_CHECK,
|
||||
CRITERIA_ENABLED_CHECK,
|
||||
CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
],
|
||||
]
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
variables = {}
|
||||
result = self._lp.run(terms, variables, **kwargs)
|
||||
self.assertIn("GigabitEthernet0/0/0/1.counters.in_crc_errors", result[0]['data_path'])
|
||||
self.assertIn("GigabitEthernet0/0/0/1.enabled", result[1]['data_path'])
|
||||
self.assertIn("GigabitEthernet0/0/0/0.oper_status", result[2]['data_path'])
|
||||
self.assertIn(
|
||||
"GigabitEthernet0/0/0/1.counters.in_crc_errors",
|
||||
result[0]["data_path"],
|
||||
)
|
||||
self.assertIn("GigabitEthernet0/0/0/1.enabled", result[1]["data_path"])
|
||||
self.assertIn(
|
||||
"GigabitEthernet0/0/0/0.oper_status", result[2]["data_path"]
|
||||
)
|
||||
|
||||
def test_valid_data(self):
|
||||
"""Check passing valid data as per criteria"""
|
||||
|
||||
terms = [DATA, CRITERIA_IN_RATE_CHECK]
|
||||
kwargs = {'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {"engine": "ansible.utils.jsonschema"}
|
||||
variables = {}
|
||||
result = self._lp.run(terms, variables, **kwargs)
|
||||
self.assertEqual(result, [])
|
||||
|
||||
|
|
|
@ -18,10 +18,7 @@ DATA = {
|
|||
"counters": {
|
||||
"in_crc_errors": 0,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "configured using Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -29,17 +26,14 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "down",
|
||||
"type": "GigabitEthernet"
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
"GigabitEthernet0/0/0/1": {
|
||||
"auto_negotiate": False,
|
||||
"counters": {
|
||||
"in_crc_errors": 10,
|
||||
"in_errors": 0,
|
||||
"rate": {
|
||||
"in_rate": 0,
|
||||
"out_rate": 0
|
||||
}
|
||||
"rate": {"in_rate": 0, "out_rate": 0},
|
||||
},
|
||||
"description": "# interface is configures with Ansible",
|
||||
"duplex_mode": "full",
|
||||
|
@ -47,8 +41,8 @@ DATA = {
|
|||
"line_protocol": "up",
|
||||
"mtu": 1514,
|
||||
"oper_status": "up",
|
||||
"type": "GigabitEthernet"
|
||||
}
|
||||
"type": "GigabitEthernet",
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_CRC_ERROR_CHECK = {
|
||||
|
@ -59,29 +53,19 @@ CRITERIA_CRC_ERROR_CHECK = {
|
|||
"properties": {
|
||||
"counters": {
|
||||
"properties": {
|
||||
"in_crc_errors": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_crc_errors": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_ENABLED_CHECK = {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"enum": [True]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"^.*": {"type": "object", "properties": {"enabled": {"enum": [True]}}}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_OPER_STATUS_UP_CHECK = {
|
||||
|
@ -89,14 +73,9 @@ CRITERIA_OPER_STATUS_UP_CHECK = {
|
|||
"patternProperties": {
|
||||
"^.*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"oper_status": {
|
||||
"type": "string",
|
||||
"pattern": "up"
|
||||
}
|
||||
}
|
||||
}
|
||||
"properties": {"oper_status": {"type": "string", "pattern": "up"}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CRITERIA_IN_RATE_CHECK = {
|
||||
|
@ -109,17 +88,14 @@ CRITERIA_IN_RATE_CHECK = {
|
|||
"properties": {
|
||||
"rate": {
|
||||
"properties": {
|
||||
"in_rate": {
|
||||
"type": "number",
|
||||
"maximum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"in_rate": {"type": "number", "maximum": 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -135,27 +111,36 @@ class TestValidate(unittest.TestCase):
|
|||
kwargs = {}
|
||||
with self.assertRaises(AnsibleError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"missing required arguments: criteria", str(error.exception)
|
||||
msg = "missing required arguments: criteria"
|
||||
self.assertTrue(
|
||||
set(str(error.exception).split()).issuperset(set(msg.split()))
|
||||
)
|
||||
|
||||
kwargs = {'criteria': CRITERIA_IN_RATE_CHECK, 'engine': 'ansible.utils.sample'}
|
||||
kwargs = {
|
||||
"criteria": CRITERIA_IN_RATE_CHECK,
|
||||
"engine": "ansible.utils.sample",
|
||||
}
|
||||
with self.assertRaises(AnsibleError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"For engine 'ansible.utils.sample' error loading", str(error.exception)
|
||||
"For engine 'ansible.utils.sample' error loading",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
args = ["invalid data"]
|
||||
kwargs = {'criteria': [CRITERIA_IN_RATE_CHECK], 'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {
|
||||
"criteria": [CRITERIA_IN_RATE_CHECK],
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
}
|
||||
with self.assertRaises(AnsibleError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"'data' option value is invalid", str(error.exception)
|
||||
)
|
||||
self.assertIn("'data' option value is invalid", str(error.exception))
|
||||
|
||||
args = [DATA]
|
||||
kwargs = {'criteria': 'invalid criteria', 'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {
|
||||
"criteria": "invalid criteria",
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
}
|
||||
with self.assertRaises(AnsibleError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
|
@ -165,24 +150,39 @@ class TestValidate(unittest.TestCase):
|
|||
def test_invalid_validate_plugin_config_options(self):
|
||||
"""Check passing invalid validate plugin options"""
|
||||
args = [DATA]
|
||||
kwargs = {'criteria': 'invalid criteria', 'engine': 'ansible.utils.jsonschema', 'draft': 'draft0'}
|
||||
kwargs = {
|
||||
"criteria": "invalid criteria",
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
"draft": "draft0",
|
||||
}
|
||||
|
||||
with self.assertRaises(AnsibleError) as error:
|
||||
validate(*args, **kwargs)
|
||||
self.assertIn(
|
||||
"value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0", str(error.exception)
|
||||
"value of draft must be one of: draft3, draft4, draft6, draft7, got: draft0",
|
||||
str(error.exception),
|
||||
)
|
||||
|
||||
def test_invalid_data(self):
|
||||
"""Check passing invalid data as per criteria"""
|
||||
args = [DATA]
|
||||
kwargs = {'criteria': [CRITERIA_ENABLED_CHECK, CRITERIA_OPER_STATUS_UP_CHECK, CRITERIA_CRC_ERROR_CHECK], 'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {
|
||||
"criteria": [
|
||||
CRITERIA_ENABLED_CHECK,
|
||||
CRITERIA_OPER_STATUS_UP_CHECK,
|
||||
CRITERIA_CRC_ERROR_CHECK,
|
||||
],
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
}
|
||||
result = validate(*args, **kwargs)
|
||||
self.assertEqual(result, False)
|
||||
|
||||
def test_valid_data(self):
|
||||
"""Check passing valid data as per criteria"""
|
||||
args = [DATA]
|
||||
kwargs = {'criteria': CRITERIA_IN_RATE_CHECK, 'engine': 'ansible.utils.jsonschema'}
|
||||
kwargs = {
|
||||
"criteria": CRITERIA_IN_RATE_CHECK,
|
||||
"engine": "ansible.utils.jsonschema",
|
||||
}
|
||||
result = validate(*args, **kwargs)
|
||||
self.assertEqual(result, True)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
unittest2 ; python_version < '2.7'
|
Loading…
Reference in New Issue