Skip to content

Commit eb4ae29

Browse files
author
Patryk Szulczewski
committed
Fix operator checks to follow other check_type logic.
1 parent 43467af commit eb4ae29

File tree

4 files changed

+90
-65
lines changed

4 files changed

+90
-65
lines changed

docs/usage.md

+5-7
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ Let's run an example where we want to check the `burnedInAddress` key has a stri
416416
```
417417
We define the regex for matching a MAC address string. Then we define the path query to extract the data and create the check.
418418
```python
419-
>>> mac_regex = "(?:[0-9a-fA-F]:?){12}"
419+
>>> mac_regex = "^([0-9a-fA-F]{2}:){5}([0-9a-fA-F]{2})$"
420420
>>> path = "result[*].interfaces.*.[$name$,burnedInAddress]"
421421
>>> check = CheckType.create(check_type="regex")
422422
>>> actual_value = extract_data_from_json(actual_data, path)
@@ -556,7 +556,7 @@ We are looking for peers that have the same peerGroup, vrf, and state. Return pe
556556
{'10.1.0.0': {'peerGroup': 'IPv4-UNDERLAY-SPINE',
557557
'vrf': 'default',
558558
'state': 'Idle'}}],
559-
True)
559+
False)
560560
```
561561

562562
Let's now look to an example for the `in` operator. Keeping the same `data` and class object as above:
@@ -573,7 +573,7 @@ We are looking for "prefixesReceived" value in the operator_data list.
573573
```python
574574
>>> result = check.evaluate(check_args, value)
575575
>>> result
576-
([{'10.1.0.0': {'prefixesReceived': 50}}], False)
576+
([{'7.7.7.7': {'prefixesReceived': 101}}], False)
577577
```
578578

579579
What about `str` operator?
@@ -587,7 +587,7 @@ What about `str` operator?
587587
{'10.1.0.0': {'peerGroup': 'IPv4-UNDERLAY-SPINE'}}]
588588
>>> result = check.evaluate(check_args, value)
589589
>>> result
590-
([{'7.7.7.7': {'peerGroup': 'EVPN-OVERLAY-SPINE'}}], False)
590+
([{'10.1.0.0': {'peerGroup': 'IPv4-UNDERLAY-SPINE'}}], False)
591591
```
592592

593593
Can you guess what would be the outcome for an `int`, `float` operator?
@@ -601,9 +601,7 @@ Can you guess what would be the outcome for an `int`, `float` operator?
601601
{'10.1.0.0': {'prefixesReceived': 50}}]
602602
>>> result = check.evaluate(check_args, value)
603603
>>> result
604-
([{'7.7.7.7': {'prefixesReceived': 101}},
605-
{'10.1.0.0': {'prefixesReceived': 50}}],
606-
False)
604+
([], True)
607605
```
608606

609607
See `tests` folder in the repo for more examples.

jdiff/check_types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def _validate(params) -> None: # type: ignore[override]
193193
params_key = params.get("params", {}).get("mode")
194194
params_value = params.get("params", {}).get("operator_data")
195195

196-
if not params_key or not params_value:
196+
if not params_key or params_value is None:
197197
raise ValueError(
198198
f"'mode' and 'operator_data' arguments must be provided. You have: {list(params['params'].keys())}."
199199
)
@@ -258,4 +258,4 @@ def result(self, evaluation_result):
258258
259259
This is required as Opertor return its own boolean within result.
260260
"""
261-
return evaluation_result[0], not evaluation_result[1]
261+
return evaluation_result[0], evaluation_result[1]

jdiff/operator.py

+11-13
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ def call_evaluation_logic():
3131
"""Operator valuation logic wrapper."""
3232
# reverse operands: https://docs.python.org/3.8/library/operator.html#operator.contains
3333
if call_ops == "is_in":
34-
if ops[call_ops](self.reference_data, evaluated_value):
34+
if not ops[call_ops](self.reference_data, evaluated_value):
3535
result.append(item)
3636
elif call_ops == "not_contains":
37-
if not ops[call_ops](evaluated_value, self.reference_data):
37+
if ops[call_ops](evaluated_value, self.reference_data):
3838
result.append(item)
3939
elif call_ops == "not_in":
40-
if not ops[call_ops](self.reference_data, evaluated_value):
40+
if ops[call_ops](self.reference_data, evaluated_value):
4141
result.append(item)
4242
elif call_ops == "in_range":
43-
if self.reference_data[0] < evaluated_value < self.reference_data[1]:
43+
if not self.reference_data[0] < evaluated_value < self.reference_data[1]:
4444
result.append(item)
4545
elif call_ops == "not_in_range":
46-
if not self.reference_data[0] < evaluated_value < self.reference_data[1]:
46+
if self.reference_data[0] < evaluated_value < self.reference_data[1]:
4747
result.append(item)
4848
# "<", ">", "contains"
49-
elif ops[call_ops](evaluated_value, self.reference_data):
49+
elif not ops[call_ops](evaluated_value, self.reference_data):
5050
result.append(item)
5151

5252
ops = {
@@ -64,14 +64,13 @@ def call_evaluation_logic():
6464
for evaluated_value in value.values():
6565
call_evaluation_logic()
6666
if result:
67-
return (result, True)
68-
return (result, False)
67+
return (result, False)
68+
return (result, True)
6969

70-
def all_same(self) -> Tuple[bool, Any]:
70+
def all_same(self) -> Tuple[Any, bool]:
7171
"""All same operator type implementation."""
7272
list_of_values = []
7373
result = []
74-
7574
for item in self.value_to_compare:
7675
# Create a list for compare values.
7776
list_of_values.extend(iter(item.values()))
@@ -80,13 +79,12 @@ def all_same(self) -> Tuple[bool, Any]:
8079
result.append(False)
8180
else:
8281
result.append(True)
83-
8482
if self.reference_data and not all(result):
8583
return (self.value_to_compare, False)
8684
if self.reference_data:
87-
return (self.value_to_compare, True)
85+
return ([], True)
8886
if not all(result):
89-
return (self.value_to_compare, True)
87+
return ([], True)
9088
return (self.value_to_compare, False)
9189

9290
def contains(self) -> Tuple[List, bool]:

tests/test_operators.py

+72-43
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,22 @@
3939
}
4040
},
4141
],
42-
True,
42+
False,
4343
),
4444
)
4545
operator_contains = (
4646
"pre.json",
4747
"operator",
4848
{"params": {"mode": "contains", "operator_data": "EVPN"}},
4949
"result[0].vrfs.default.peerList[*].[$peerAddress$,peerGroup]",
50-
([{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE"}}], False),
50+
(
51+
[
52+
{"10.1.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE"}},
53+
{"10.2.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE"}},
54+
{"10.64.207.255": {"peerGroup": "IPv4-UNDERLAY-MLAG-PEER"}},
55+
],
56+
False,
57+
),
5158
)
5259
operator_not_contains = (
5360
"pre.json",
@@ -56,9 +63,7 @@
5663
"result[0].vrfs.default.peerList[*].[$peerAddress$,peerGroup]",
5764
(
5865
[
59-
{"10.1.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE"}},
60-
{"10.2.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE"}},
61-
{"10.64.207.255": {"peerGroup": "IPv4-UNDERLAY-MLAG-PEER"}},
66+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE"}},
6267
],
6368
False,
6469
),
@@ -68,50 +73,26 @@
6873
"operator",
6974
{"params": {"mode": "is-gt", "operator_data": 20}},
7075
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
71-
(
72-
[
73-
{"7.7.7.7": {"prefixesSent": 50}},
74-
{"10.1.0.0": {"prefixesSent": 50}},
75-
{"10.2.0.0": {"prefixesSent": 50}},
76-
{"10.64.207.255": {"prefixesSent": 50}},
77-
],
78-
False,
79-
),
76+
([], True),
8077
)
8178
operator_is_lt = (
8279
"pre.json",
8380
"operator",
8481
{"params": {"mode": "is-lt", "operator_data": 60}},
8582
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
86-
(
87-
[
88-
{"7.7.7.7": {"prefixesSent": 50}},
89-
{"10.1.0.0": {"prefixesSent": 50}},
90-
{"10.2.0.0": {"prefixesSent": 50}},
91-
{"10.64.207.255": {"prefixesSent": 50}},
92-
],
93-
False,
94-
),
83+
([], True),
9584
)
9685
operator_is_in = (
9786
"pre.json",
9887
"operator",
9988
{"params": {"mode": "is-in", "operator_data": [20, 40, 50]}},
10089
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
101-
(
102-
[
103-
{"7.7.7.7": {"prefixesSent": 50}},
104-
{"10.1.0.0": {"prefixesSent": 50}},
105-
{"10.2.0.0": {"prefixesSent": 50}},
106-
{"10.64.207.255": {"prefixesSent": 50}},
107-
],
108-
False,
109-
),
90+
([], True),
11091
)
11192
operator_not_in = (
11293
"pre.json",
11394
"operator",
114-
{"params": {"mode": "not-in", "operator_data": [20, 40, 60]}},
95+
{"params": {"mode": "not-in", "operator_data": [20, 40, 50]}},
11596
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
11697
(
11798
[
@@ -128,20 +109,12 @@
128109
"operator",
129110
{"params": {"mode": "in-range", "operator_data": (20, 60)}},
130111
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
131-
(
132-
[
133-
{"7.7.7.7": {"prefixesSent": 50}},
134-
{"10.1.0.0": {"prefixesSent": 50}},
135-
{"10.2.0.0": {"prefixesSent": 50}},
136-
{"10.64.207.255": {"prefixesSent": 50}},
137-
],
138-
False,
139-
),
112+
([], True),
140113
)
141114
operator_not_in_range = (
142115
"pre.json",
143116
"operator",
144-
{"params": {"mode": "not-in-range", "operator_data": (20, 40)}},
117+
{"params": {"mode": "not-in-range", "operator_data": (20, 60)}},
145118
"result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesSent]",
146119
(
147120
[
@@ -174,7 +147,63 @@ def test_operator(filename, check_type_str, evaluate_args, path, expected_result
174147
# There is not concept of "pre" and "post" in operator.
175148
data = load_json_file("api", filename)
176149
value = extract_data_from_json(data, path)
150+
print(evaluate_args, value)
177151
actual_results = check.evaluate(evaluate_args, value)
178152
assert actual_results == expected_result, ASSERT_FAIL_MESSAGE.format(
179153
output=actual_results, expected_output=expected_result
180154
)
155+
156+
157+
@pytest.mark.parametrize(
158+
"value, operator_data, expected_result",
159+
[
160+
(
161+
[
162+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
163+
{"10.1.0.0": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
164+
],
165+
True,
166+
([], True),
167+
),
168+
(
169+
[
170+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
171+
{"10.1.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE", "vrf": "default", "state": "Connected"}},
172+
],
173+
True,
174+
(
175+
[
176+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
177+
{"10.1.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE", "vrf": "default", "state": "Connected"}},
178+
],
179+
False,
180+
),
181+
),
182+
(
183+
[
184+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
185+
{"10.1.0.0": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
186+
],
187+
False,
188+
(
189+
[
190+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
191+
{"10.1.0.0": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
192+
],
193+
False,
194+
),
195+
),
196+
(
197+
[
198+
{"7.7.7.7": {"peerGroup": "EVPN-OVERLAY-SPINE", "vrf": "default", "state": "Connected"}},
199+
{"10.1.0.0": {"peerGroup": "IPv4-UNDERLAY-SPINE", "vrf": "default", "state": "Connected"}},
200+
],
201+
False,
202+
([], True),
203+
),
204+
],
205+
)
206+
def test_all_same(value, operator_data, expected_result):
207+
check_args = {"params": {"mode": "all-same", "operator_data": operator_data}}
208+
check = CheckType.create("operator")
209+
assert check.evaluate(check_args, value) == expected_result

0 commit comments

Comments
 (0)