Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tests, add test feature and examples of this feature #27

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,19 @@ There are two special notations:
value: "The Last Samurai"
```

### Examples
For more examples of how to use this module see `exmaples` folder.

## Testing
Testing is simple if you have pytest installed:

### create virtual environment
``` bash
python3 -m venv .venv
.venv/bin/python3 -m pip install -U ansible pytest
```
Testing is simple once you have pytest installed:
```bash
pytest
.venv/bin/py.test -v
```
Note you may have to copy the `json_patch.py` file into your Ansible installation's `lib/ansible/modules/files/` dir.

Expand Down
21 changes: 21 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Example playbooks

## Setup virtual environment
``` bash
python3 -m venv .venv
.venv/bin/python3 -m pip install -U ansible pytest
```
## Setup to run ansible
``` bash
mkdir -p library
ln -s ../json_patch.py library/json_patch.py
```
## Examples

### append-if-not-exist
Shows an example of how to test and add values to a list if they are not already there.

``` bash
.venv/bin/ansible-playbook -vvv -i local, --connection=local examples/append-if-not-exist.yaml

```
48 changes: 48 additions & 0 deletions examples/append-if-not-exist.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
- name: Append value to list if it does not already exist
hosts: local
gather_facts: false
become: false
vars:
jsonfile: "/tmp/example-append-if-not-exist.json"
json_keys:
- key: "/foo/-"
value: "bar"
test: "/foo/*"
tasks:
- name: "Ensure json {{jsonfile}} file exists"
ansible.builtin.copy:
content: '{"foo": []}'
dest: "{{jsonfile}}"
force: true

- name: Check if key exists
json_patch:
src: "{{jsonfile}}"
operations:
- op: test
path: "{{ item.test }}"
value: "{{ item.value }}"
loop: "{{json_keys}}"
register: foo_result
when:
- item.test is defined

- name: debug msgs from the results of test
debug:
msg: "{{ foo_result.results | selectattr('item.key', 'equalto', item.key) | list | map(attribute='tested') | first }}"
loop: "{{json_keys}}"
when:
- item.test is defined

- name: "append key/values to {{jsonfile}}"
json_patch:
src: "{{jsonfile}}"
pretty: true
operations:
- op: add
path: "{{ item.key }}"
value: "{{ item.value }}"
loop: "{{json_keys}}"
when:
- item.test is not defined or (item.test is defined and not foo_result.results | selectattr('item.key', 'equalto', item.key) | list | map(attribute='tested') | first)
19 changes: 15 additions & 4 deletions json_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# Copyright: (c) 2019, Joey Espinosa <[email protected]>
# Copyright: (c) 2019, Ansible Project
# MIT License (https://opensource.org/licenses/MIT)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

Expand Down Expand Up @@ -246,7 +245,9 @@ def run(self):
changed, tested = self.patcher.patch()
result = {'changed': changed}
if tested is not None:
result['tested'] = tested
print(tested)
result['tested'] = tested[0]
result['object'] = tested[1]
if result['changed']: # let's write the changes
dump_kwargs = {}
if self.pretty_print:
Expand Down Expand Up @@ -339,12 +340,16 @@ def patch(self):
# attach object to patch operation (helpful for recursion)
patch['obj'] = self.obj
new_obj, changed, tested = getattr(self, op)(**patch)
if changed or op == "remove": # 'remove' will fail if we don't actually remove anything
if changed or op in ["remove", "add", "move"]: # 'remove', 'add' and 'move' will fail if we don't actually remove anything
modified = bool(changed)
if modified is True:
self.obj = new_obj
if tested is not None:
test_result = False if test_result is False else tested # one false test fails everything
print(f"hej {tested}")
if test_result is None:
test_result = (tested, new_obj) # one false test fails everything
else:
test_result += (tested, new_obj)
return modified, test_result

def _get(self, path, obj, **discard):
Expand Down Expand Up @@ -520,8 +525,14 @@ def test(self, path, value, obj, **discard):
next_obj = obj
for idx, elem in enumerate(elements):
if elem == "*": # wildcard
# print(f"elem==*: {next_obj} {type(next_obj)}")
if not isinstance(next_obj, list):
return obj, None, False
# last element and test is '*' then just check if value is in list
if '/'.join(elements[(idx + 1):]) == '' and value in next_obj:
return obj, None, True
elif '/'.join(elements[(idx + 1):]) == '' and value not in next_obj:
return obj, None, False
for sub_obj in next_obj:
dummy, _, found = self.test('/'.join(elements[(idx + 1):]), value, sub_obj)
if found:
Expand Down
73 changes: 62 additions & 11 deletions test_json_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import json
import pytest

from ansible.modules.files.json_patch import JSONPatcher, PathError
# Will work both if installed in ansible and in the local folder
try:
from ansible.modules.files.json_patch import JSONPatcher, PathError
except ImportError:
from json_patch import JSONPatcher, PathError

__metaclass__ = type

Expand All @@ -13,7 +17,9 @@
{"baz": [{"foo": "apples", "bar": "oranges"},
{"foo": "grapes", "bar": "oranges"},
{"foo": "bananas", "bar": "potatoes"}],
"enabled": False}])
"enabled": False},
{"bar": ["foo", "bar", "baz", "baza", "baza", "bazb"], "enabled": False}
])


# OPERATION: ADD
Expand Down Expand Up @@ -245,7 +251,7 @@ def test_op_test_string_equal():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is True
assert tested[0] is True


def test_op_test_string_unequal():
Expand All @@ -256,7 +262,7 @@ def test_op_test_string_unequal():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is False
assert tested[0] is False


def test_op_test_number_equal():
Expand All @@ -267,7 +273,7 @@ def test_op_test_number_equal():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is True
assert tested[0] is True


def test_op_test_number_unequal():
Expand All @@ -278,7 +284,7 @@ def test_op_test_number_unequal():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is False
assert tested[0] is False


def test_op_test_list_equal():
Expand All @@ -290,7 +296,7 @@ def test_op_test_list_equal():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is True
assert tested is True
assert tested[0] is True


def test_op_test_wildcard():
Expand All @@ -301,7 +307,7 @@ def test_op_test_wildcard():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is True
assert tested[0] is True


def test_op_test_wildcard_not_found():
Expand All @@ -312,7 +318,51 @@ def test_op_test_wildcard_not_found():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is False
assert tested[0] is False


def test_op_test_wildcard_list_first():
"""Should find an element in the 'bar' list with the matching value."""
patches = [
{"op": "test", "path": "/3/bar/*", "value": "foo"}
]
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested[0] is True


def test_op_test_wildcard_list_middle():
"""Should find an element in the 'bar' list with the matching value."""
patches = [
{"op": "test", "path": "/3/bar/*", "value": "baz"}
]
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested[0] is True


def test_op_test_wildcard_list_last():
"""Should find an element in the 'bar' list with the matching value."""
patches = [
{"op": "test", "path": "/3/bar/*", "value": "bazb"}
]
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested[0] is True


def test_op_test_wildcard_list_not_found():
"""Should not find an element in the 'bar' list with the matching value."""
patches = [
{"op": "test", "path": "/3/bar/*", "value": "no_foo"}
]
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested[0] is False


def test_op_test_multiple_tests():
Expand All @@ -324,7 +374,8 @@ def test_op_test_multiple_tests():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is False
assert all(test for test in tested) is False
#assert tested is False


def test_op_test_nonexistent_member():
Expand All @@ -335,4 +386,4 @@ def test_op_test_nonexistent_member():
jp = JSONPatcher(sample_json, *patches)
changed, tested = jp.patch()
assert changed is None
assert tested is False
assert tested[0] is False