Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 31 additions & 29 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ It's worth pointing out that `jdiff` is focused on the comparison of the two obj

## exact_match

Check type `exact_match` is concerned with the value of the elements within the data structure. The key-value pairs should match between the reference and comparison data. A diff is generated between the two data sets and tested to see if all the keys and values match.
Check type `exact_match` is concerned with the value of the elements within the data structure. The key-value pairs should match between the reference and comparison data. A diff is generated between the two data sets and tested to see whether all the keys and values match.

As some outputs might be too verbose or include fields that constantly change (e.g. interface counter), it is possible to exclude a portion of data traversed by JMESPath by defining a keys exclusion list.
As some outputs might be too verbose or include fields that constantly change (e.g., interface counter), it is possible to exclude a portion of data traversed by JMESPath by defining a key's exclusion list.


Examples:
Expand Down Expand Up @@ -102,9 +102,9 @@ Use the evaluate method to return the result.
False)
```

As we can see, we return a tuple containing a diff between the pre and post data as well as a boolean for the overall test result. In this case a difference has been found so the status of the test is `False`.
As we can see, we return a tuple containing a diff between the pre and post data as well as a boolean for the overall test result. In this case a difference has been found, so the status of the test is `False`.

Let's see a better way to run `exact_match` for this specific case. Because there is a lot of extra key value pairs, some of which change all the time, we are only interested in `interfaceStatus`, so we can use a utility of jdiff: `extract_data_from_json`, which can extract the value from the keys we are interested in and discard the rest.
Let's see a better way to run `exact_match` for this specific case. Because there are a lot of extra key value pairs, some of which change all the time, we are interested only in `interfaceStatus`. So we can use a utility of jdiff: `extract_data_from_json`, which can extract the value from the keys we are interested in and discard the rest.

```python
>>> my_jmspath = "result[*].interfaces.*.[$name$,interfaceStatus]"
Expand All @@ -121,13 +121,13 @@ Let's see a better way to run `exact_match` for this specific case. Because ther
False)
```

In this case, we only want to compare the value of a single key, the `interfaceStatus` key, so we define the jmespath logic to take the name and the interfaceStatus values from the all the interface objects in the data object.
In this case, we only want to compare the value of a single key, the `interfaceStatus` key. So we define the JMESPath logic to take the name and the interfaceStatus values from all the interface objects in the data object.

This type of logic to extract keys and value from the object is called anchor logic and more [here](#extra_value_from_json).
This type of logic to extract keys and value from the object is called anchor logic. Find more about anchor logic [here](#extra_value_from_json).

### Tolerance

The `tolerance` test checks for the deviation between the value or count between the reference and comparison values. A `tolerance` is defined and passed to the check along with the comparison and reference values.
The `tolerance` test checks for the deviation between the value or count of the reference and comparison values. A `tolerance` is defined and passed to the check along with the comparison and reference values.

The `tolerance` argument must be a `float > 0`. The calculation is percentage based, and the test of the values may be +/- the `tolerance` percentage.

Expand Down Expand Up @@ -190,7 +190,7 @@ Let's have a look at a couple of examples:
... }
>>> my_check = CheckType.create("tolerance")
```
We will define a jmespath search for the values we want to test and extract from the reference and comparison objects.
We will define a JMESPath search for the values we want to test and extract from the reference and comparison objects.
```python
>>> my_jmspath = "global.$peers$.*.*.ipv4.[accepted_prefixes,received_prefixes,sent_prefixes]"
>>> reference_value = extract_data_from_json(reference_data, my_jmspath)
Expand Down Expand Up @@ -231,13 +231,13 @@ Let's increase the tolerance:
({}, True)
```

This check can test if the difference between two values is within a specified tolerance percentage. It could be useful in cases where values like route metrics or optical power levels fluctuate by a small amount. It might be desirable to treat these values as equal if the deviation is within a given range. You can pass in the result of len() to count the number of objects returned within your data.
This check can test whether the difference between two values is within a specified tolerance percentage. It could be useful in cases where values like route metrics or optical power levels fluctuate by a small amount. It might be desirable to treat these values as equal if the deviation is within a given range. You can pass in the result of len() to count the number of objects returned within your data.

### Parameter match
### Parameter Match

The `parameter_match` check provides a way to test key/value pairs against baseline values.

The check defines baseline key/value pairs in a Python dictionary. Additionally, mode is set to one of `match` or `no-match`, which specifies if the data should match the baseline, or not.
The check defines baseline key/value pairs in a Python dictionary. Additionally, mode is set to one of `match` or `no-match`, which specifies whether the data should match the baseline, or not.

The test fails if:

Expand Down Expand Up @@ -282,7 +282,7 @@ For example, in network data:
>>> comparison_value = extract_data_from_json(comparison_data, path=my_jmspath)
```

This test requires a mode argument, match in this case matches the keys and values in the "params" to the keys and values in the data.
This test requires a mode argument; match in this case matches the keys and values in the "params" to the keys and values in the data.
```python
>>> actual_results = my_check.evaluate(
post_value,
Expand All @@ -296,7 +296,7 @@ This test requires a mode argument, match in this case matches the keys and valu
({'Management1': {'interfaceStatus': 'down'}}, False)
```

mode: no-match - return the keys and values from the test object that do not match the keys and values provides in "params"
mode: no-match - return the keys and values from the test object that do not match the keys and values provided in "params"
```python
>>> my_parameter_match =
>>> actual_results = my_check.evaluate(
Expand All @@ -315,7 +315,7 @@ mode: no-match - return the keys and values from the test object that do not mat

The `regex` check type evaluates data against a regular expression passed as an argument to the `evaluate` method. Similarly to `parameter_match` check, the `match` and `no-match` modes are supported.

Let's run an example where we want to check the `burnedInAddress` key has a string representing a MAC Address as value
Let's run an example where we want to check the `burnedInAddress` key has a string representing a MAC address as value.

```python
>>> data = {
Expand Down Expand Up @@ -344,21 +344,21 @@ Let's run an example where we want to check the `burnedInAddress` key has a stri
... }
... ]
... }
>>> # Python regex for matching MAC Address string
>>> # Python regex for matching MAC address string
>>> regex_args = {"regex": "(?:[0-9a-fA-F]:?){12}", "mode": "match"}
>>> path = "result[*].interfaces.*.[$name$,burnedInAddress]"
>>> check = CheckType.create(check_type="regex")
>>> value = check.extract_data_from_json(output=data, path=path)
>>> value
[{'Management1': {'burnedInAddress': '08:00:27:e6:b2:f8'}}]
>>> result = check.evaluate(value, **regex_args)
>>> # The test is passed as the burnedInAddress value match our regex
>>> # The test is passed as the burnedInAddress value matches our regex
>>> result
({}, True)
>>> # What if we want "no-match"?
>>> regex_args = {"regex": "(?:[0-9a-fA-F]:?){12}", "mode": "no-match"}
>>> result = check.evaluate(value, **regex_args)
>>> # jdiff return the failing data as the regex match the value
>>> # jdiff returns the failing data, as the regex matches the value
>>> result
({'Management1': {'burnedInAddress': '08:00:27:e6:b2:f8'}}, False)
```
Expand All @@ -371,7 +371,7 @@ The `operator` check is a collection of more specific checks divided into catego

| Przemek: The below is not very readable? Indented sections are rendered as code blocks. I would suggest naming these groups "categories" or "groups" and explaing that each of the names is the name of the check that needs to be passed as the argument.

#### `in` operators
#### `in` Operators


1. is-in: Check if the specified element string value is included in a given list of strings.
Expand All @@ -386,35 +386,37 @@ The `operator` check is a collection of more specific checks divided into catego
- in-range: [20, 70]
check if value is in range between 20 and 70

|Dwight: delete the space between 5 and comma in #4, below?

4. not-range: Check if the value of a specified element is outside of a given numeric range.
- not-range: [5 , 40]
checks if value is not in range between 5 and 40

#### `bool` operators
#### `bool` Operators

1. all-same: Check if all content values for the specified element are the same. It can also be used to compare all content values against another specified element.
- all-same: flap-count
checks if all values of node <flap-count> in given path is same or not.
checks if all values of node <flap-count> in given path are same or not.

#### `str` operators
#### `str` Operators

1. contains: determines if an element string value contains the provided test-string value.
1. contains: Determines if an element string value contains the provided test-string value.
- contains: "underlay"
checks if "underlay" is present in given data or not.

2. not-contains: determines if an element string value does not contain the provided test-string value.
2. not-contains: Determines if an element string value does not contain the provided test-string value.
- not-contains: "overlay"
checks if "overlay" is present in given node or not.

#### `int`, `float` operators
#### `int`, `float` Operators

1. is-gt: Check if the value of a specified element is greater than a given numeric value.
- is-gt: 2
checks if value should be greater than 2
checks if value is greater than 2

2. is-lt: Check if the value of a specified element is lesser than a given numeric value.
- is-lt: 55
checks if value is lower than 55 or not.
checks if value is less than 55


Examples:
Expand Down Expand Up @@ -473,15 +475,15 @@ Examples:
... ]
... }
>>> path = "result[0].vrfs.default.peerList[*].[$peerAddress$,peerGroup,vrf,state]"
>>> # "operator" checks requires "mode" argument - which specify the operator logic to apply -
>>> # "operator" checks require "mode" argument - which specifies the operator logic to apply -
>>> # and "operator_data" required for the mode defined.
>>> check_args = {"params": {"mode": "all-same", "operator_data": True}}
>>> check = CheckType.create("operator")
>>> value = check.extract_data_from_json(data, path)
>>> value
[{'7.7.7.7': {'peerGroup': 'EVPN-OVERLAY-SPINE', 'vrf': 'default', 'state': 'Connected'}}, {'10.1.0.0': {'peerGroup': 'IPv4-UNDERLAY-SPINE', 'vrf': 'default', 'state': 'Idle'}}]
>>> result = check.evaluate(value, check_args)
>>> # We are looking for peers that have the same peerGroup,vrf and state. If not, return those are not.
>>> # We are looking for peers that have the same peerGroup, vrf, and state. If not, return those that do not.
>>> result
((False, [{'7.7.7.7': {'peerGroup': 'EVPN-OVERLAY-SPINE', 'vrf': 'default', 'state': 'Connected'}}, {'10.1.0.0': {'peerGroup': 'IPv4-UNDERLAY-SPINE', 'vrf': 'default', 'state': 'Idle'}}]), False)
```
Expand Down Expand Up @@ -513,7 +515,7 @@ What about `str` operator?
((True, [{'7.7.7.7': {'peerGroup': 'EVPN-OVERLAY-SPINE'}}]), False)
```

Can you guess what would ne the outcome for an `int`, `float` operator?
Can you guess what would be the outcome for an `int`, `float` operator?

```python
>>> path = "result[0].vrfs.default.peerList[*].[$peerAddress$,prefixesReceived]"
Expand Down