Skip to content

Commit

Permalink
Add Jinja2 tests for testing types
Browse files Browse the repository at this point in the history
So Jinja2 only has tests for testing string types, or iterable types,
which is quite limiting. If you need to test a boolean value in Jinja2
the only option is to test it is not a string and convert it to a string
and compare it to 'True' or 'False'.

So these tests are essential constructs in playbooks and templates.

This PR includes integration tests to validate Jinja2 behaviour.
  • Loading branch information
dagwieers committed Jul 25, 2018
1 parent 1305fca commit 43e716b
Show file tree
Hide file tree
Showing 4 changed files with 526 additions and 2 deletions.
52 changes: 50 additions & 2 deletions lib/ansible/plugins/test/core.py
Expand Up @@ -21,7 +21,8 @@

import re
import operator as py_operator
from collections import MutableMapping, MutableSequence
from ansible.module_utils.six import integer_types, string_types
from collections import Mapping, MutableMapping, MutableSequence, Sequence
from distutils.version import LooseVersion, StrictVersion

from ansible import errors
Expand Down Expand Up @@ -78,14 +79,52 @@ def finished(result):
raise errors.AnsibleFilterError("The 'finished' test expects a dictionary")
if 'finished' in result:
# For async tasks return status
# NOTE: The value of finished it 0 or 1, not False or True :-/
# NOTE: The value of finished is 0 or 1, not False or True :-/
return result.get('finished', 0) == 1
else:
# For non-async tasks warn user, but return as finished
display.warning("The 'finished' test expects an async task, but a non-async task was tested")
return True


def test_boolean(value):
''' Return true if the object is a boolean value '''
return value is True or value is False


def test_false(value):
''' Return true if the object is False '''
return value is False


def test_true(value):
''' Return true if the object is True '''
return value is True


# NOTE: The existing Jinja2 'number' test also matches booleans and floats
def test_integer(value):
''' Return true if the object is an integer '''
return isinstance(value, integer_types) and value is not True and value is not False


# NOTE: The existing Jinja2 'number' test also matches booleans and integers
def test_float(value):
''' Return true if the object is a float '''
return isinstance(value, float)


# NOTE: The existing Jinja2 'sequence' test also matches strings and dictionaries
def test_list(value):
''' Return true if the object is a list or tuple '''
return isinstance(value, Sequence) and not isinstance(value, string_types)


def test_mapping(value):
''' Return true if the object is a mapping (dict etc.).'''
return isinstance(value, Mapping)


def regex(value='', pattern='', ignorecase=False, multiline=False, match_type='search'):
''' Expose `re` as a boolean filter using the `search` method by default.
This is likely only useful for `search` and `match` which already
Expand Down Expand Up @@ -162,6 +201,15 @@ def tests(self):
# async testing
'finished': finished,

# type testing
'boolean': test_boolean,
'false': test_false,
'true': test_true,
'integer': test_integer,
'float': test_float,
'list': test_list,
'mapping': test_mapping, # Required for Jinja2 < 2.6

# regex
'match': match,
'search': search,
Expand Down
1 change: 1 addition & 0 deletions test/integration/targets/jinja2_tests/aliases
@@ -0,0 +1 @@
shippable/posix/group1

0 comments on commit 43e716b

Please sign in to comment.