mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
This commit is contained in:
parent
83dc92ed2d
commit
5788b6cb28
@ -135,23 +135,23 @@ class ConditionSet:
|
|||||||
def __init__(self, ruleset):
|
def __init__(self, ruleset):
|
||||||
if type(ruleset) is not dict:
|
if type(ruleset) is not dict:
|
||||||
raise ValueError(_("Ruleset must be a dictionary, not {ruleset}.").format(ruleset=type(ruleset)))
|
raise ValueError(_("Ruleset must be a dictionary, not {ruleset}.").format(ruleset=type(ruleset)))
|
||||||
if len(ruleset) != 1:
|
|
||||||
raise ValueError(_("Ruleset must have exactly one logical operator (found {ruleset})").format(
|
|
||||||
ruleset=len(ruleset)))
|
|
||||||
|
|
||||||
# Determine the logic type
|
if len(ruleset) == 1:
|
||||||
logic = list(ruleset.keys())[0]
|
self.logic = (list(ruleset.keys())[0]).lower()
|
||||||
if type(logic) is not str or logic.lower() not in (AND, OR):
|
if self.logic not in (AND, OR):
|
||||||
raise ValueError(_("Invalid logic type: {logic} (must be '{op_and}' or '{op_or}')").format(
|
raise ValueError(_("Invalid logic type: must be 'AND' or 'OR'. Please check documentation."))
|
||||||
logic=logic, op_and=AND, op_or=OR
|
|
||||||
))
|
|
||||||
self.logic = logic.lower()
|
|
||||||
|
|
||||||
# Compile the set of Conditions
|
# Compile the set of Conditions
|
||||||
self.conditions = [
|
self.conditions = [
|
||||||
ConditionSet(rule) if is_ruleset(rule) else Condition(**rule)
|
ConditionSet(rule) if is_ruleset(rule) else Condition(**rule)
|
||||||
for rule in ruleset[self.logic]
|
for rule in ruleset[self.logic]
|
||||||
]
|
]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.logic = None
|
||||||
|
self.conditions = [Condition(**ruleset)]
|
||||||
|
except TypeError:
|
||||||
|
raise ValueError(_("Incorrect key(s) informed. Please check documentation."))
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
"""
|
"""
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from dcim.choices import SiteStatusChoices
|
||||||
|
from dcim.models import Site
|
||||||
from extras.conditions import Condition, ConditionSet
|
from extras.conditions import Condition, ConditionSet
|
||||||
|
from extras.events import serialize_for_event
|
||||||
|
from extras.forms import EventRuleForm
|
||||||
|
from extras.models import EventRule, Webhook
|
||||||
|
|
||||||
|
|
||||||
class ConditionTestCase(TestCase):
|
class ConditionTestCase(TestCase):
|
||||||
@ -217,3 +223,93 @@ class ConditionSetTest(TestCase):
|
|||||||
self.assertTrue(cs.eval({'a': 1, 'b': 2, 'c': 9}))
|
self.assertTrue(cs.eval({'a': 1, 'b': 2, 'c': 9}))
|
||||||
self.assertFalse(cs.eval({'a': 9, 'b': 2, 'c': 9}))
|
self.assertFalse(cs.eval({'a': 9, 'b': 2, 'c': 9}))
|
||||||
self.assertFalse(cs.eval({'a': 9, 'b': 9, 'c': 3}))
|
self.assertFalse(cs.eval({'a': 9, 'b': 9, 'c': 3}))
|
||||||
|
|
||||||
|
def test_event_rule_conditions_without_logic_operator(self):
|
||||||
|
"""
|
||||||
|
Test evaluation of EventRule conditions without logic operator.
|
||||||
|
"""
|
||||||
|
event_rule = EventRule(
|
||||||
|
name='Event Rule 1',
|
||||||
|
type_create=True,
|
||||||
|
type_update=True,
|
||||||
|
conditions={
|
||||||
|
'attr': 'status.value',
|
||||||
|
'value': 'active',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a Site to evaluate - Status = active
|
||||||
|
site = Site.objects.create(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_ACTIVE)
|
||||||
|
data = serialize_for_event(site)
|
||||||
|
|
||||||
|
# Evaluate the conditions (status='active')
|
||||||
|
self.assertTrue(event_rule.eval_conditions(data))
|
||||||
|
|
||||||
|
def test_event_rule_conditions_with_logical_operation(self):
|
||||||
|
"""
|
||||||
|
Test evaluation of EventRule conditions without logic operator, but with logical operation (in).
|
||||||
|
"""
|
||||||
|
event_rule = EventRule(
|
||||||
|
name='Event Rule 1',
|
||||||
|
type_create=True,
|
||||||
|
type_update=True,
|
||||||
|
conditions={
|
||||||
|
"attr": "status.value",
|
||||||
|
"value": ["planned", "staging"],
|
||||||
|
"op": "in",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a Site to evaluate - Status = active
|
||||||
|
site = Site.objects.create(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_ACTIVE)
|
||||||
|
data = serialize_for_event(site)
|
||||||
|
|
||||||
|
# Evaluate the conditions (status in ['planned, 'staging'])
|
||||||
|
self.assertFalse(event_rule.eval_conditions(data))
|
||||||
|
|
||||||
|
def test_event_rule_conditions_with_logical_operation_and_negate(self):
|
||||||
|
"""
|
||||||
|
Test evaluation of EventRule with logical operation (in) and negate.
|
||||||
|
"""
|
||||||
|
event_rule = EventRule(
|
||||||
|
name='Event Rule 1',
|
||||||
|
type_create=True,
|
||||||
|
type_update=True,
|
||||||
|
conditions={
|
||||||
|
"attr": "status.value",
|
||||||
|
"value": ["planned", "staging"],
|
||||||
|
"op": "in",
|
||||||
|
"negate": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a Site to evaluate - Status = active
|
||||||
|
site = Site.objects.create(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_ACTIVE)
|
||||||
|
data = serialize_for_event(site)
|
||||||
|
|
||||||
|
# Evaluate the conditions (status NOT in ['planned, 'staging'])
|
||||||
|
self.assertTrue(event_rule.eval_conditions(data))
|
||||||
|
|
||||||
|
def test_event_rule_conditions_with_incorrect_key_must_return_false(self):
|
||||||
|
"""
|
||||||
|
Test Event Rule with incorrect condition (key "foo" is wrong). Must return false.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ct = ContentType.objects.get(app_label='extras', model='webhook')
|
||||||
|
site_ct = ContentType.objects.get_for_model(Site)
|
||||||
|
webhook = Webhook.objects.create(name='Webhook 100', payload_url='http://example.com/?1', http_method='POST')
|
||||||
|
form = EventRuleForm({
|
||||||
|
"name": "Event Rule 1",
|
||||||
|
"type_create": True,
|
||||||
|
"type_update": True,
|
||||||
|
"action_object_type": ct.pk,
|
||||||
|
"action_type": "webhook",
|
||||||
|
"action_choice": webhook.pk,
|
||||||
|
"content_types": [site_ct.pk],
|
||||||
|
"conditions": {
|
||||||
|
"foo": "status.value",
|
||||||
|
"value": "active"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertFalse(form.is_valid())
|
||||||
|
Loading…
Reference in New Issue
Block a user