2013-07-02 10:16:47 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2012-11-18 18:57:10 +00:00
|
|
|
# Import python libs
|
2014-11-21 19:05:13 +00:00
|
|
|
from __future__ import absolute_import
|
2012-05-10 04:29:05 +00:00
|
|
|
import os
|
2016-12-01 14:05:00 +00:00
|
|
|
import ast
|
2014-11-21 19:05:13 +00:00
|
|
|
import copy
|
2012-05-10 04:29:05 +00:00
|
|
|
import tempfile
|
2013-07-08 14:19:19 +00:00
|
|
|
import json
|
2013-07-11 11:39:14 +00:00
|
|
|
import datetime
|
2013-10-16 15:14:20 +00:00
|
|
|
import pprint
|
2016-11-04 10:40:31 +00:00
|
|
|
import re
|
2012-11-18 18:57:10 +00:00
|
|
|
|
2013-06-27 13:10:26 +00:00
|
|
|
# Import Salt Testing libs
|
2017-02-27 13:58:07 +00:00
|
|
|
from tests.support.unit import skipIf, TestCase
|
|
|
|
from tests.support.case import ModuleCase
|
2017-03-29 18:41:51 +00:00
|
|
|
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock
|
2017-02-27 15:59:04 +00:00
|
|
|
from tests.support.paths import TMP_CONF_DIR
|
2013-06-27 13:10:26 +00:00
|
|
|
|
2012-11-18 18:57:10 +00:00
|
|
|
# Import salt libs
|
2016-08-03 18:45:29 +00:00
|
|
|
import salt.config
|
Use explicit unicode strings + break up salt.utils
This PR is part of what will be an ongoing effort to use explicit
unicode strings in Salt. Because Python 3 does not suport Python 2's raw
unicode string syntax (i.e. `ur'\d+'`), we must use
`salt.utils.locales.sdecode()` to ensure that the raw string is unicode.
However, because of how `salt/utils/__init__.py` has evolved into the
hulking monstrosity it is today, this means importing a large module in
places where it is not needed, which could negatively impact
performance. For this reason, this PR also breaks out some of the
functions from `salt/utils/__init__.py` into new/existing modules under
`salt/utils/`. The long term goal will be that the modules within this
directory do not depend on importing `salt.utils`.
A summary of the changes in this PR is as follows:
* Moves the following functions from `salt.utils` to new locations
(including a deprecation warning if invoked from `salt.utils`):
`to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`,
`dequote`, `is_hex`, `is_bin_str`, `rand_string`,
`contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`,
`which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`,
`is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`,
`is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`,
`is_openbsd`, `is_aix`
* Moves the functions already deprecated by @rallytime to the bottom of
`salt/utils/__init__.py` for better organization, so we can keep the
deprecated ones separate from the ones yet to be deprecated as we
continue to break up `salt.utils`
* Updates `salt/*.py` and all files under `salt/client/` to use explicit
unicode string literals.
* Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils
import foo` becomes `import salt.utils.foo as foo`).
* Renames the `test.rand_str` function to `test.random_hash` to more
accurately reflect what it does
* Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`)
such that it returns a string matching the passed size. Previously
this function would get `size` bytes from `os.urandom()`,
base64-encode it, and return the result, which would in most cases not
be equal to the passed size.
2017-07-25 01:47:15 +00:00
|
|
|
from salt.ext import six
|
2014-07-07 02:04:17 +00:00
|
|
|
import salt.loader
|
2017-07-18 16:31:01 +00:00
|
|
|
import salt.utils.files
|
Use explicit unicode strings + break up salt.utils
This PR is part of what will be an ongoing effort to use explicit
unicode strings in Salt. Because Python 3 does not suport Python 2's raw
unicode string syntax (i.e. `ur'\d+'`), we must use
`salt.utils.locales.sdecode()` to ensure that the raw string is unicode.
However, because of how `salt/utils/__init__.py` has evolved into the
hulking monstrosity it is today, this means importing a large module in
places where it is not needed, which could negatively impact
performance. For this reason, this PR also breaks out some of the
functions from `salt/utils/__init__.py` into new/existing modules under
`salt/utils/`. The long term goal will be that the modules within this
directory do not depend on importing `salt.utils`.
A summary of the changes in this PR is as follows:
* Moves the following functions from `salt.utils` to new locations
(including a deprecation warning if invoked from `salt.utils`):
`to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`,
`dequote`, `is_hex`, `is_bin_str`, `rand_string`,
`contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`,
`which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`,
`is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`,
`is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`,
`is_openbsd`, `is_aix`
* Moves the functions already deprecated by @rallytime to the bottom of
`salt/utils/__init__.py` for better organization, so we can keep the
deprecated ones separate from the ones yet to be deprecated as we
continue to break up `salt.utils`
* Updates `salt/*.py` and all files under `salt/client/` to use explicit
unicode string literals.
* Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils
import foo` becomes `import salt.utils.foo as foo`).
* Renames the `test.rand_str` function to `test.random_hash` to more
accurately reflect what it does
* Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`)
such that it returns a string matching the passed size. Previously
this function would get `size` bytes from `os.urandom()`,
base64-encode it, and return the result, which would in most cases not
be equal to the passed size.
2017-07-25 01:47:15 +00:00
|
|
|
from salt.utils import get_context
|
2013-11-14 01:21:57 +00:00
|
|
|
from salt.exceptions import SaltRenderError
|
2015-06-09 20:18:04 +00:00
|
|
|
from salt.ext.six.moves import builtins
|
Use explicit unicode strings + break up salt.utils
This PR is part of what will be an ongoing effort to use explicit
unicode strings in Salt. Because Python 3 does not suport Python 2's raw
unicode string syntax (i.e. `ur'\d+'`), we must use
`salt.utils.locales.sdecode()` to ensure that the raw string is unicode.
However, because of how `salt/utils/__init__.py` has evolved into the
hulking monstrosity it is today, this means importing a large module in
places where it is not needed, which could negatively impact
performance. For this reason, this PR also breaks out some of the
functions from `salt/utils/__init__.py` into new/existing modules under
`salt/utils/`. The long term goal will be that the modules within this
directory do not depend on importing `salt.utils`.
A summary of the changes in this PR is as follows:
* Moves the following functions from `salt.utils` to new locations
(including a deprecation warning if invoked from `salt.utils`):
`to_bytes`, `to_str`, `to_unicode`, `str_to_num`, `is_quoted`,
`dequote`, `is_hex`, `is_bin_str`, `rand_string`,
`contains_whitespace`, `clean_kwargs`, `invalid_kwargs`, `which`,
`which_bin`, `path_join`, `shlex_split`, `rand_str`, `is_windows`,
`is_proxy`, `is_linux`, `is_darwin`, `is_sunos`, `is_smartos`,
`is_smartos_globalzone`, `is_smartos_zone`, `is_freebsd`, `is_netbsd`,
`is_openbsd`, `is_aix`
* Moves the functions already deprecated by @rallytime to the bottom of
`salt/utils/__init__.py` for better organization, so we can keep the
deprecated ones separate from the ones yet to be deprecated as we
continue to break up `salt.utils`
* Updates `salt/*.py` and all files under `salt/client/` to use explicit
unicode string literals.
* Gets rid of implicit imports of `salt.utils` (e.g. `from salt.utils
import foo` becomes `import salt.utils.foo as foo`).
* Renames the `test.rand_str` function to `test.random_hash` to more
accurately reflect what it does
* Modifies `salt.utils.stringutils.random()` (née `salt.utils.rand_string()`)
such that it returns a string matching the passed size. Previously
this function would get `size` bytes from `os.urandom()`,
base64-encode it, and return the result, which would in most cases not
be equal to the passed size.
2017-07-25 01:47:15 +00:00
|
|
|
from salt.utils.decorators.jinja import JinjaFilter
|
2014-02-15 17:26:35 +00:00
|
|
|
from salt.utils.jinja import (
|
|
|
|
SaltCacheLoader,
|
|
|
|
SerializerExtension,
|
|
|
|
ensure_sequence_filter
|
2013-10-05 11:32:30 +00:00
|
|
|
)
|
2014-02-15 17:26:35 +00:00
|
|
|
from salt.utils.templates import JINJA, render_jinja_tmpl
|
2013-10-24 09:10:13 +00:00
|
|
|
from salt.utils.odict import OrderedDict
|
2013-06-24 22:53:59 +00:00
|
|
|
|
|
|
|
# Import 3rd party libs
|
2013-07-08 14:19:19 +00:00
|
|
|
import yaml
|
2013-07-19 13:10:06 +00:00
|
|
|
from jinja2 import Environment, DictLoader, exceptions
|
2013-07-17 10:23:42 +00:00
|
|
|
try:
|
2014-02-08 08:01:12 +00:00
|
|
|
import timelib # pylint: disable=W0611
|
2013-07-17 10:23:42 +00:00
|
|
|
HAS_TIMELIB = True
|
|
|
|
except ImportError:
|
|
|
|
HAS_TIMELIB = False
|
2012-01-29 15:01:43 +00:00
|
|
|
|
2012-05-10 04:29:05 +00:00
|
|
|
TEMPLATES_DIR = os.path.dirname(os.path.abspath(__file__))
|
2011-12-29 23:58:00 +00:00
|
|
|
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
class MockFileClient(object):
|
|
|
|
'''
|
|
|
|
Does not download files but records any file request for testing
|
|
|
|
'''
|
|
|
|
def __init__(self, loader=None):
|
2012-05-29 16:40:20 +00:00
|
|
|
if loader:
|
|
|
|
loader._file_client = self
|
2011-12-29 23:58:00 +00:00
|
|
|
self.requests = []
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2013-11-10 19:13:33 +00:00
|
|
|
def get_file(self, template, dest='', makedirs=False, saltenv='base'):
|
2011-12-29 23:58:00 +00:00
|
|
|
self.requests.append({
|
2012-05-10 04:29:05 +00:00
|
|
|
'path': template,
|
2011-12-29 23:58:00 +00:00
|
|
|
'dest': dest,
|
|
|
|
'makedirs': makedirs,
|
2013-11-10 19:13:33 +00:00
|
|
|
'saltenv': saltenv
|
2011-12-29 23:58:00 +00:00
|
|
|
})
|
|
|
|
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2012-01-29 15:01:43 +00:00
|
|
|
class TestSaltCacheLoader(TestCase):
|
2015-01-26 22:04:21 +00:00
|
|
|
def __init__(self, *args, **kws):
|
|
|
|
TestCase.__init__(self, *args, **kws)
|
|
|
|
self.opts = {
|
|
|
|
'cachedir': TEMPLATES_DIR,
|
|
|
|
'file_roots': {
|
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
|
|
|
},
|
|
|
|
'pillar_roots': {
|
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_searchpath(self):
|
|
|
|
'''
|
2013-11-10 19:13:33 +00:00
|
|
|
The searchpath is based on the cachedir option and the saltenv parameter
|
2011-12-29 23:58:00 +00:00
|
|
|
'''
|
2012-05-10 04:29:05 +00:00
|
|
|
tmp = tempfile.gettempdir()
|
2015-01-26 22:04:21 +00:00
|
|
|
opts = copy.deepcopy(self.opts)
|
|
|
|
opts.update({'cachedir': tmp})
|
|
|
|
loader = SaltCacheLoader(opts, saltenv='test')
|
2013-01-14 07:58:27 +00:00
|
|
|
assert loader.searchpath == [os.path.join(tmp, 'files', 'test')]
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_mockclient(self):
|
|
|
|
'''
|
2012-06-30 20:10:34 +00:00
|
|
|
A MockFileClient is used that records all file requests normally sent
|
|
|
|
to the master.
|
2011-12-29 23:58:00 +00:00
|
|
|
'''
|
2015-01-26 22:04:21 +00:00
|
|
|
loader = SaltCacheLoader(self.opts, 'test')
|
2011-12-29 23:58:00 +00:00
|
|
|
fc = MockFileClient(loader)
|
|
|
|
res = loader.get_source(None, 'hello_simple')
|
|
|
|
assert len(res) == 3
|
2012-06-25 00:10:54 +00:00
|
|
|
# res[0] on Windows is unicode and use os.linesep so it works cross OS
|
|
|
|
self.assertEqual(str(res[0]), 'world' + os.linesep)
|
2012-05-10 04:29:05 +00:00
|
|
|
tmpl_dir = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_simple')
|
|
|
|
self.assertEqual(res[1], tmpl_dir)
|
2013-06-24 22:53:59 +00:00
|
|
|
assert res[2](), 'Template up to date?'
|
2011-12-29 23:58:00 +00:00
|
|
|
assert len(fc.requests)
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://hello_simple')
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2013-11-10 19:13:33 +00:00
|
|
|
def get_test_saltenv(self):
|
2011-12-29 23:58:00 +00:00
|
|
|
'''
|
|
|
|
Setup a simple jinja test environment
|
|
|
|
'''
|
2015-01-26 22:04:21 +00:00
|
|
|
loader = SaltCacheLoader(self.opts, 'test')
|
2011-12-29 23:58:00 +00:00
|
|
|
fc = MockFileClient(loader)
|
|
|
|
jinja = Environment(loader=loader)
|
|
|
|
return fc, jinja
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_import(self):
|
|
|
|
'''
|
|
|
|
You can import and use macros from other files
|
|
|
|
'''
|
2013-11-10 19:13:33 +00:00
|
|
|
fc, jinja = self.get_test_saltenv()
|
2011-12-29 23:58:00 +00:00
|
|
|
result = jinja.get_template('hello_import').render()
|
|
|
|
self.assertEqual(result, 'Hey world !a b !')
|
|
|
|
assert len(fc.requests) == 2
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://hello_import')
|
|
|
|
self.assertEqual(fc.requests[1]['path'], 'salt://macro')
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_include(self):
|
|
|
|
'''
|
|
|
|
You can also include a template that imports and uses macros
|
|
|
|
'''
|
2013-11-10 19:13:33 +00:00
|
|
|
fc, jinja = self.get_test_saltenv()
|
2011-12-29 23:58:00 +00:00
|
|
|
result = jinja.get_template('hello_include').render()
|
|
|
|
self.assertEqual(result, 'Hey world !a b !')
|
|
|
|
assert len(fc.requests) == 3
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://hello_include')
|
|
|
|
self.assertEqual(fc.requests[1]['path'], 'salt://hello_import')
|
|
|
|
self.assertEqual(fc.requests[2]['path'], 'salt://macro')
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_include_context(self):
|
|
|
|
'''
|
|
|
|
Context variables are passes to the included template by default.
|
|
|
|
'''
|
2013-11-10 19:13:33 +00:00
|
|
|
_, jinja = self.get_test_saltenv()
|
2011-12-29 23:58:00 +00:00
|
|
|
result = jinja.get_template('hello_include').render(a='Hi', b='Salt')
|
|
|
|
self.assertEqual(result, 'Hey world !Hi Salt !')
|
|
|
|
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2012-01-29 15:01:43 +00:00
|
|
|
class TestGetTemplate(TestCase):
|
2012-11-12 22:08:14 +00:00
|
|
|
def __init__(self, *args, **kws):
|
|
|
|
TestCase.__init__(self, *args, **kws)
|
|
|
|
self.local_opts = {
|
|
|
|
'cachedir': TEMPLATES_DIR,
|
|
|
|
'file_client': 'local',
|
2014-12-11 00:41:32 +00:00
|
|
|
'file_ignore_regex': None,
|
|
|
|
'file_ignore_glob': None,
|
2012-11-12 22:08:14 +00:00
|
|
|
'file_roots': {
|
2014-12-11 00:41:32 +00:00
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
2014-09-22 16:29:25 +00:00
|
|
|
},
|
2015-01-26 19:10:05 +00:00
|
|
|
'pillar_roots': {
|
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
|
|
|
},
|
2014-09-22 16:29:25 +00:00
|
|
|
'fileserver_backend': ['roots'],
|
2014-12-11 00:41:32 +00:00
|
|
|
'hash_type': 'md5',
|
2014-09-23 20:02:34 +00:00
|
|
|
'extension_modules': os.path.join(
|
|
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
|
|
'extmods'),
|
2012-11-12 22:08:14 +00:00
|
|
|
}
|
2017-04-12 21:04:00 +00:00
|
|
|
self.local_salt = {}
|
2012-11-12 22:08:14 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_fallback(self):
|
|
|
|
'''
|
2012-09-27 21:39:49 +00:00
|
|
|
A Template with a filesystem loader is returned as fallback
|
2011-12-29 23:58:00 +00:00
|
|
|
if the file is not contained in the searchpath
|
|
|
|
'''
|
2012-11-14 03:32:55 +00:00
|
|
|
fn_ = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_simple')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(fn_) as fp_:
|
2012-11-14 03:32:55 +00:00
|
|
|
out = render_jinja_tmpl(
|
2016-08-11 16:45:24 +00:00
|
|
|
fp_.read(),
|
2017-04-12 21:04:00 +00:00
|
|
|
dict(
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2012-12-02 18:45:09 +00:00
|
|
|
self.assertEqual(out, 'world\n')
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2011-12-29 23:58:00 +00:00
|
|
|
def test_fallback_noloader(self):
|
|
|
|
'''
|
2012-09-27 21:39:49 +00:00
|
|
|
A Template with a filesystem loader is returned as fallback
|
|
|
|
if the file is not contained in the searchpath
|
2011-12-29 23:58:00 +00:00
|
|
|
'''
|
2012-05-10 04:29:05 +00:00
|
|
|
filename = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_import')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2016-08-11 16:45:24 +00:00
|
|
|
out = render_jinja_tmpl(
|
|
|
|
fp_.read(),
|
2017-04-12 21:04:00 +00:00
|
|
|
dict(
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2012-12-02 18:45:09 +00:00
|
|
|
self.assertEqual(out, 'Hey world !a b !\n')
|
2012-05-29 16:40:20 +00:00
|
|
|
|
2013-11-10 19:13:33 +00:00
|
|
|
def test_saltenv(self):
|
2011-12-29 23:58:00 +00:00
|
|
|
'''
|
|
|
|
If the template is within the searchpath it can
|
|
|
|
import, include and extend other templates.
|
|
|
|
The initial template is expected to be already cached
|
|
|
|
get_template does not request it from the master again.
|
|
|
|
'''
|
|
|
|
fc = MockFileClient()
|
2017-03-29 18:41:51 +00:00
|
|
|
with patch.object(SaltCacheLoader, 'file_client', MagicMock(return_value=fc)):
|
|
|
|
filename = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_import')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-29 18:41:51 +00:00
|
|
|
out = render_jinja_tmpl(
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts={'cachedir': TEMPLATES_DIR, 'file_client': 'remote',
|
|
|
|
'file_roots': self.local_opts['file_roots'],
|
|
|
|
'pillar_roots': self.local_opts['pillar_roots']},
|
|
|
|
a='Hi', b='Salt', saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(out, 'Hey world !Hi Salt !\n')
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
|
2013-06-24 22:53:59 +00:00
|
|
|
|
2013-12-22 17:15:19 +00:00
|
|
|
def test_macro_additional_log_for_generalexc(self):
|
|
|
|
'''
|
2014-07-13 18:43:33 +00:00
|
|
|
If we failed in a macro because of e.g. a TypeError, get
|
2013-12-22 17:15:19 +00:00
|
|
|
more output from trace.
|
|
|
|
'''
|
|
|
|
expected = r'''Jinja error:.*division.*
|
|
|
|
.*/macrogeneral\(2\):
|
|
|
|
---
|
|
|
|
\{% macro mymacro\(\) -%\}
|
|
|
|
\{\{ 1/0 \}\} <======================
|
|
|
|
\{%- endmacro %\}
|
|
|
|
---.*'''
|
|
|
|
filename = os.path.join(TEMPLATES_DIR,
|
|
|
|
'files', 'test', 'hello_import_generalerror')
|
|
|
|
fc = MockFileClient()
|
2017-03-29 18:41:51 +00:00
|
|
|
with patch.object(SaltCacheLoader, 'file_client', MagicMock(return_value=fc)):
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2017-03-29 18:41:51 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2013-12-22 17:15:19 +00:00
|
|
|
|
|
|
|
def test_macro_additional_log_for_undefined(self):
|
|
|
|
'''
|
|
|
|
If we failed in a macro because of undefined variables, get
|
|
|
|
more output from trace.
|
|
|
|
'''
|
|
|
|
expected = r'''Jinja variable 'b' is undefined
|
|
|
|
.*/macroundefined\(2\):
|
|
|
|
---
|
|
|
|
\{% macro mymacro\(\) -%\}
|
|
|
|
\{\{b.greetee\}\} <-- error is here <======================
|
|
|
|
\{%- endmacro %\}
|
|
|
|
---'''
|
|
|
|
filename = os.path.join(TEMPLATES_DIR,
|
|
|
|
'files', 'test', 'hello_import_undefined')
|
|
|
|
fc = MockFileClient()
|
2017-03-29 18:41:51 +00:00
|
|
|
with patch.object(SaltCacheLoader, 'file_client', MagicMock(return_value=fc)):
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2017-03-29 18:41:51 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2013-12-22 17:15:19 +00:00
|
|
|
|
|
|
|
def test_macro_additional_log_syntaxerror(self):
|
|
|
|
'''
|
|
|
|
If we failed in a macro, get more output from trace.
|
|
|
|
'''
|
|
|
|
expected = r'''Jinja syntax error: expected token .*end.*got '-'.*
|
|
|
|
.*/macroerror\(2\):
|
|
|
|
---
|
|
|
|
# macro
|
|
|
|
\{% macro mymacro\(greeting, greetee='world'\) -\} <-- error is here <======================
|
|
|
|
\{\{ greeting ~ ' ' ~ greetee \}\} !
|
|
|
|
\{%- endmacro %\}
|
|
|
|
---.*'''
|
|
|
|
filename = os.path.join(TEMPLATES_DIR,
|
|
|
|
'files', 'test', 'hello_import_error')
|
|
|
|
fc = MockFileClient()
|
2017-03-29 18:41:51 +00:00
|
|
|
with patch.object(SaltCacheLoader, 'file_client', MagicMock(return_value=fc)):
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2017-03-29 18:41:51 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2013-12-22 17:15:19 +00:00
|
|
|
|
2013-07-02 10:16:47 +00:00
|
|
|
def test_non_ascii_encoding(self):
|
|
|
|
fc = MockFileClient()
|
2017-03-29 18:41:51 +00:00
|
|
|
with patch.object(SaltCacheLoader, 'file_client', MagicMock(return_value=fc)):
|
|
|
|
filename = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_import')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-29 18:41:51 +00:00
|
|
|
out = render_jinja_tmpl(
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts={'cachedir': TEMPLATES_DIR, 'file_client': 'remote',
|
|
|
|
'file_roots': self.local_opts['file_roots'],
|
|
|
|
'pillar_roots': self.local_opts['pillar_roots']},
|
|
|
|
a='Hi', b='Sàlt', saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(out, u'Hey world !Hi Sàlt !\n')
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
|
2013-07-02 10:16:47 +00:00
|
|
|
|
2017-03-29 18:41:51 +00:00
|
|
|
filename = os.path.join(TEMPLATES_DIR, 'files', 'test', 'non_ascii')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(filename) as fp_:
|
2017-03-29 18:41:51 +00:00
|
|
|
out = render_jinja_tmpl(
|
|
|
|
fp_.read(),
|
|
|
|
dict(opts={'cachedir': TEMPLATES_DIR, 'file_client': 'remote',
|
|
|
|
'file_roots': self.local_opts['file_roots'],
|
|
|
|
'pillar_roots': self.local_opts['pillar_roots']},
|
|
|
|
a='Hi', b='Sàlt', saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(u'Assunção\n', out)
|
|
|
|
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
|
2013-10-07 23:11:44 +00:00
|
|
|
|
2013-07-17 10:23:42 +00:00
|
|
|
@skipIf(HAS_TIMELIB is False, 'The `timelib` library is not installed.')
|
2013-07-11 11:39:14 +00:00
|
|
|
def test_strftime(self):
|
2017-04-12 21:04:00 +00:00
|
|
|
response = render_jinja_tmpl(
|
|
|
|
'{{ "2002/12/25"|strftime }}',
|
|
|
|
dict(
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2013-07-11 11:39:14 +00:00
|
|
|
self.assertEqual(response, '2002-12-25')
|
|
|
|
|
|
|
|
objects = (
|
|
|
|
datetime.datetime(2002, 12, 25, 12, 00, 00, 00),
|
|
|
|
'2002/12/25',
|
|
|
|
1040814000,
|
|
|
|
'1040814000'
|
|
|
|
)
|
|
|
|
|
|
|
|
for object in objects:
|
2017-04-12 21:04:00 +00:00
|
|
|
response = render_jinja_tmpl(
|
|
|
|
'{{ object|strftime }}',
|
|
|
|
dict(
|
|
|
|
object=object,
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2013-07-12 09:48:12 +00:00
|
|
|
self.assertEqual(response, '2002-12-25')
|
|
|
|
|
2017-04-12 21:04:00 +00:00
|
|
|
response = render_jinja_tmpl(
|
|
|
|
'{{ object|strftime("%b %d, %Y") }}',
|
|
|
|
dict(
|
|
|
|
object=object,
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2013-07-11 11:39:14 +00:00
|
|
|
self.assertEqual(response, 'Dec 25, 2002')
|
|
|
|
|
2017-04-12 21:04:00 +00:00
|
|
|
response = render_jinja_tmpl(
|
|
|
|
'{{ object|strftime("%y") }}',
|
|
|
|
dict(
|
|
|
|
object=object,
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
))
|
2013-07-11 11:39:14 +00:00
|
|
|
self.assertEqual(response, '02')
|
|
|
|
|
2013-10-05 11:32:30 +00:00
|
|
|
def test_non_ascii(self):
|
|
|
|
fn = os.path.join(TEMPLATES_DIR, 'files', 'test', 'non_ascii')
|
2017-04-12 21:04:00 +00:00
|
|
|
out = JINJA(
|
|
|
|
fn,
|
|
|
|
opts=self.local_opts,
|
|
|
|
saltenv='test',
|
|
|
|
salt=self.local_salt
|
|
|
|
)
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(out['data']) as fp:
|
2016-08-03 18:45:29 +00:00
|
|
|
result = fp.read()
|
|
|
|
if six.PY2:
|
|
|
|
result = result.decode('utf-8')
|
2013-10-05 11:32:30 +00:00
|
|
|
self.assertEqual(u'Assunção\n', result)
|
|
|
|
|
2013-11-14 01:21:57 +00:00
|
|
|
def test_get_context_has_enough_context(self):
|
2013-09-19 08:00:22 +00:00
|
|
|
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'
|
2013-11-14 01:21:57 +00:00
|
|
|
context = get_context(template, 8)
|
2013-09-19 08:00:22 +00:00
|
|
|
expected = '---\n[...]\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\n[...]\n---'
|
|
|
|
self.assertEqual(expected, context)
|
|
|
|
|
2013-11-14 01:21:57 +00:00
|
|
|
def test_get_context_at_top_of_file(self):
|
2013-09-19 08:00:22 +00:00
|
|
|
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'
|
2013-11-14 01:21:57 +00:00
|
|
|
context = get_context(template, 1)
|
2013-09-19 08:00:22 +00:00
|
|
|
expected = '---\n1\n2\n3\n4\n5\n6\n[...]\n---'
|
|
|
|
self.assertEqual(expected, context)
|
|
|
|
|
2013-11-14 01:21:57 +00:00
|
|
|
def test_get_context_at_bottom_of_file(self):
|
2013-09-19 08:00:22 +00:00
|
|
|
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'
|
2013-11-14 01:21:57 +00:00
|
|
|
context = get_context(template, 15)
|
2013-09-19 08:00:22 +00:00
|
|
|
expected = '---\n[...]\na\nb\nc\nd\ne\nf\n---'
|
|
|
|
self.assertEqual(expected, context)
|
|
|
|
|
2013-11-14 01:21:57 +00:00
|
|
|
def test_get_context_2_context_lines(self):
|
2013-09-19 08:00:22 +00:00
|
|
|
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'
|
2013-11-14 01:21:57 +00:00
|
|
|
context = get_context(template, 8, num_lines=2)
|
2013-09-19 08:00:22 +00:00
|
|
|
expected = '---\n[...]\n6\n7\n8\n9\na\n[...]\n---'
|
|
|
|
self.assertEqual(expected, context)
|
|
|
|
|
2013-11-14 01:21:57 +00:00
|
|
|
def test_get_context_with_marker(self):
|
2013-09-19 08:00:22 +00:00
|
|
|
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'
|
2013-11-14 01:21:57 +00:00
|
|
|
context = get_context(template, 8, num_lines=2, marker=' <---')
|
2013-09-19 08:00:22 +00:00
|
|
|
expected = '---\n[...]\n6\n7\n8 <---\n9\na\n[...]\n---'
|
|
|
|
self.assertEqual(expected, context)
|
|
|
|
|
|
|
|
def test_render_with_syntax_error(self):
|
|
|
|
template = 'hello\n\n{{ bad\n\nfoo'
|
|
|
|
expected = r'.*---\nhello\n\n{{ bad\n\nfoo <======================\n---'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2013-11-14 01:21:57 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
2013-11-14 01:21:57 +00:00
|
|
|
)
|
2013-09-19 08:00:22 +00:00
|
|
|
|
2016-08-03 18:45:29 +00:00
|
|
|
@skipIf(six.PY3, 'Not applicable to Python 3: skipping.')
|
2017-02-19 15:35:30 +00:00
|
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
2013-12-05 17:46:43 +00:00
|
|
|
def test_render_with_unicode_syntax_error(self):
|
2017-02-19 15:35:30 +00:00
|
|
|
with patch.object(builtins, '__salt_system_encoding__', 'utf-8'):
|
|
|
|
template = u'hello\n\n{{ bad\n\nfoo\ud55c'
|
|
|
|
expected = r'.*---\nhello\n\n{{ bad\n\nfoo\xed\x95\x9c <======================\n---'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2017-02-19 15:35:30 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
|
|
|
)
|
2013-12-05 17:46:43 +00:00
|
|
|
|
2017-02-19 15:35:30 +00:00
|
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
2013-12-05 17:46:43 +00:00
|
|
|
def test_render_with_utf8_syntax_error(self):
|
2017-02-19 15:35:30 +00:00
|
|
|
with patch.object(builtins, '__salt_system_encoding__', 'utf-8'):
|
|
|
|
template = 'hello\n\n{{ bad\n\nfoo\xed\x95\x9c'
|
|
|
|
expected = r'.*---\nhello\n\n{{ bad\n\nfoo\xed\x95\x9c <======================\n---'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2017-02-19 15:35:30 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
|
|
|
)
|
2013-12-05 17:46:43 +00:00
|
|
|
|
2013-09-19 08:00:22 +00:00
|
|
|
def test_render_with_undefined_variable(self):
|
|
|
|
template = "hello\n\n{{ foo }}\n\nfoo"
|
2014-06-12 19:33:53 +00:00
|
|
|
expected = r'Jinja variable \'foo\' is undefined'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2013-11-14 01:21:57 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
2013-11-14 01:21:57 +00:00
|
|
|
)
|
2013-09-19 08:00:22 +00:00
|
|
|
|
2013-12-05 17:46:43 +00:00
|
|
|
def test_render_with_undefined_variable_utf8(self):
|
|
|
|
template = "hello\xed\x95\x9c\n\n{{ foo }}\n\nfoo"
|
2014-06-12 19:33:53 +00:00
|
|
|
expected = r'Jinja variable \'foo\' is undefined'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2013-12-05 17:46:43 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
2013-12-05 17:46:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_render_with_undefined_variable_unicode(self):
|
|
|
|
template = u"hello\ud55c\n\n{{ foo }}\n\nfoo"
|
2014-06-12 19:33:53 +00:00
|
|
|
expected = r'Jinja variable \'foo\' is undefined'
|
2017-03-31 11:22:33 +00:00
|
|
|
self.assertRaisesRegex(
|
2013-12-05 17:46:43 +00:00
|
|
|
SaltRenderError,
|
|
|
|
expected,
|
|
|
|
render_jinja_tmpl,
|
|
|
|
template,
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
|
2013-12-05 17:46:43 +00:00
|
|
|
)
|
2013-07-11 11:39:14 +00:00
|
|
|
|
2013-12-09 20:02:25 +00:00
|
|
|
|
2013-07-08 14:19:19 +00:00
|
|
|
class TestCustomExtensions(TestCase):
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def __init__(self, *args, **kws):
|
|
|
|
TestCase.__init__(self, *args, **kws)
|
|
|
|
self.local_opts = {
|
|
|
|
'cachedir': TEMPLATES_DIR,
|
|
|
|
'file_client': 'local',
|
|
|
|
'file_ignore_regex': None,
|
|
|
|
'file_ignore_glob': None,
|
|
|
|
'file_roots': {
|
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
|
|
|
},
|
|
|
|
'pillar_roots': {
|
|
|
|
'test': [os.path.join(TEMPLATES_DIR, 'files', 'test')]
|
|
|
|
},
|
|
|
|
'fileserver_backend': ['roots'],
|
|
|
|
'hash_type': 'md5',
|
|
|
|
'extension_modules': os.path.join(
|
|
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
|
|
'extmods'),
|
|
|
|
}
|
|
|
|
self.local_salt = {
|
|
|
|
# 'dns.A': dnsutil.A,
|
|
|
|
# 'dns.AAAA': dnsutil.AAAA,
|
|
|
|
# 'file.exists': filemod.file_exists,
|
|
|
|
# 'file.basename': filemod.basename,
|
|
|
|
# 'file.dirname': filemod.dirname
|
|
|
|
}
|
|
|
|
|
2016-11-04 10:40:31 +00:00
|
|
|
def test_regex_escape(self):
|
|
|
|
dataset = 'foo?:.*/\\bar'
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
2017-04-12 21:03:55 +00:00
|
|
|
env.filters.update(JinjaFilter.salt_jinja_filters)
|
2016-11-04 10:40:31 +00:00
|
|
|
rendered = env.from_string('{{ dataset|regex_escape }}').render(dataset=dataset)
|
|
|
|
self.assertEqual(rendered, re.escape(dataset))
|
|
|
|
|
2016-11-04 12:09:37 +00:00
|
|
|
def test_unique_string(self):
|
|
|
|
dataset = 'foo'
|
|
|
|
unique = set(dataset)
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
2017-04-12 21:03:55 +00:00
|
|
|
env.filters.update(JinjaFilter.salt_jinja_filters)
|
2017-06-16 19:11:51 +00:00
|
|
|
if six.PY3:
|
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '")
|
2017-07-07 15:43:52 +00:00
|
|
|
self.assertEqual(sorted(rendered), sorted(list(unique)))
|
2017-06-16 19:11:51 +00:00
|
|
|
else:
|
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset)
|
|
|
|
self.assertEqual(rendered, u"{0}".format(unique))
|
2016-11-04 12:09:37 +00:00
|
|
|
|
|
|
|
def test_unique_tuple(self):
|
|
|
|
dataset = ('foo', 'foo', 'bar')
|
|
|
|
unique = set(dataset)
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
2017-04-12 21:03:55 +00:00
|
|
|
env.filters.update(JinjaFilter.salt_jinja_filters)
|
2017-06-16 19:11:51 +00:00
|
|
|
if six.PY3:
|
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '")
|
2017-08-07 18:38:10 +00:00
|
|
|
self.assertEqual(sorted(rendered), sorted(list(unique)))
|
2017-06-16 19:11:51 +00:00
|
|
|
else:
|
2017-06-19 15:37:00 +00:00
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset)
|
|
|
|
self.assertEqual(rendered, u"{0}".format(unique))
|
2016-11-04 12:09:37 +00:00
|
|
|
|
|
|
|
def test_unique_list(self):
|
|
|
|
dataset = ['foo', 'foo', 'bar']
|
|
|
|
unique = ['foo', 'bar']
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
2017-04-12 21:03:55 +00:00
|
|
|
env.filters.update(JinjaFilter.salt_jinja_filters)
|
2017-06-16 19:11:51 +00:00
|
|
|
if six.PY3:
|
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'[]").split("', '")
|
|
|
|
self.assertEqual(rendered, unique)
|
2017-06-19 16:52:45 +00:00
|
|
|
else:
|
2017-06-16 19:11:51 +00:00
|
|
|
rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset)
|
|
|
|
self.assertEqual(rendered, u"{0}".format(unique))
|
2016-11-04 12:09:37 +00:00
|
|
|
|
2013-07-17 14:53:09 +00:00
|
|
|
def test_serialize_json(self):
|
|
|
|
dataset = {
|
|
|
|
"foo": True,
|
|
|
|
"bar": 42,
|
|
|
|
"baz": [1, 2, 3],
|
|
|
|
"qux": 2.0
|
|
|
|
}
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ dataset|json }}').render(dataset=dataset)
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(dataset, json.loads(rendered))
|
2013-07-17 14:53:09 +00:00
|
|
|
|
|
|
|
def test_serialize_yaml(self):
|
2013-07-08 14:19:19 +00:00
|
|
|
dataset = {
|
|
|
|
"foo": True,
|
|
|
|
"bar": 42,
|
|
|
|
"baz": [1, 2, 3],
|
2017-01-04 11:14:27 +00:00
|
|
|
"qux": 2.0,
|
|
|
|
"spam": OrderedDict([
|
|
|
|
('foo', OrderedDict([
|
|
|
|
('bar', 'baz'),
|
|
|
|
('qux', 42)
|
|
|
|
])
|
|
|
|
)
|
|
|
|
])
|
2013-07-08 14:19:19 +00:00
|
|
|
}
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ dataset|yaml }}').render(dataset=dataset)
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(dataset, yaml.load(rendered))
|
2013-07-08 14:19:19 +00:00
|
|
|
|
2016-09-27 16:52:49 +00:00
|
|
|
def test_serialize_yaml_str(self):
|
|
|
|
dataset = "str value"
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ dataset|yaml }}').render(dataset=dataset)
|
|
|
|
self.assertEqual(dataset, rendered)
|
|
|
|
|
2017-01-04 12:17:20 +00:00
|
|
|
def test_serialize_yaml_unicode(self):
|
|
|
|
dataset = u"str value"
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ dataset|yaml }}').render(dataset=dataset)
|
2017-02-15 18:32:19 +00:00
|
|
|
if six.PY3:
|
|
|
|
self.assertEqual("str value", rendered)
|
|
|
|
else:
|
2017-05-10 22:55:37 +00:00
|
|
|
# Due to a bug in the equality handler, this check needs to be split
|
|
|
|
# up into several different assertions. We need to check that the various
|
|
|
|
# string segments are present in the rendered value, as well as the
|
2017-05-11 15:03:10 +00:00
|
|
|
# type of the rendered variable (should be unicode, which is the same as
|
|
|
|
# six.text_type). This should cover all use cases but also allow the test
|
|
|
|
# to pass on CentOS 6 running Python 2.7.
|
2017-05-10 22:55:37 +00:00
|
|
|
self.assertIn('!!python/unicode', rendered)
|
|
|
|
self.assertIn('str value', rendered)
|
2017-05-11 15:03:10 +00:00
|
|
|
self.assertIsInstance(rendered, six.text_type)
|
2017-01-04 12:17:20 +00:00
|
|
|
|
2013-10-16 15:14:20 +00:00
|
|
|
def test_serialize_python(self):
|
|
|
|
dataset = {
|
|
|
|
"foo": True,
|
|
|
|
"bar": 42,
|
|
|
|
"baz": [1, 2, 3],
|
|
|
|
"qux": 2.0
|
|
|
|
}
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ dataset|python }}').render(dataset=dataset)
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, pprint.pformat(dataset))
|
2013-10-16 15:14:20 +00:00
|
|
|
|
2013-07-19 13:10:06 +00:00
|
|
|
def test_load_yaml(self):
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{% set document = "{foo: it works}"|load_yaml %}{{ document.foo }}').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
rendered = env.from_string('{% set document = document|load_yaml %}'
|
|
|
|
'{{ document.foo }}').render(document="{foo: it works}")
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateRuntimeError):
|
|
|
|
env.from_string('{% set document = document|load_yaml %}'
|
|
|
|
'{{ document.foo }}').render(document={"foo": "it works"})
|
|
|
|
|
2013-07-25 15:22:38 +00:00
|
|
|
def test_load_tag(self):
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
|
|
|
|
source = '{{ bar }}, ' + \
|
|
|
|
'{% load_yaml as docu %}{foo: it works, {{ bar }}: baz}{% endload %}' + \
|
|
|
|
'{{ docu.foo }}'
|
|
|
|
|
|
|
|
rendered = env.from_string(source).render(bar="barred")
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"barred, it works")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
source = '{{ bar }}, {% load_json as docu %}{"foo": "it works", "{{ bar }}": "baz"}{% endload %}' + \
|
|
|
|
'{{ docu.foo }}'
|
|
|
|
|
|
|
|
rendered = env.from_string(source).render(bar="barred")
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"barred, it works")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateSyntaxError):
|
|
|
|
env.from_string('{% load_yamle as document %}{foo, bar: it works}{% endload %}').render()
|
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateRuntimeError):
|
|
|
|
env.from_string('{% load_json as document %}{foo, bar: it works}{% endload %}').render()
|
|
|
|
|
2013-07-19 13:10:06 +00:00
|
|
|
def test_load_json(self):
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{% set document = \'{"foo": "it works"}\'|load_json %}'
|
|
|
|
'{{ document.foo }}').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
rendered = env.from_string('{% set document = document|load_json %}'
|
|
|
|
'{{ document.foo }}').render(document='{"foo": "it works"}')
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
# bad quotes
|
|
|
|
with self.assertRaises(exceptions.TemplateRuntimeError):
|
|
|
|
env.from_string("{{ document|load_json }}").render(document="{'foo': 'it works'}")
|
|
|
|
|
|
|
|
# not a string
|
|
|
|
with self.assertRaises(exceptions.TemplateRuntimeError):
|
|
|
|
env.from_string('{{ document|load_json }}').render(document={"foo": "it works"})
|
|
|
|
|
|
|
|
def test_load_yaml_template(self):
|
|
|
|
loader = DictLoader({'foo': '{bar: "my god is blue", foo: [1, 2, 3]}'})
|
|
|
|
env = Environment(extensions=[SerializerExtension], loader=loader)
|
2013-07-19 14:02:03 +00:00
|
|
|
rendered = env.from_string('{% import_yaml "foo" as doc %}{{ doc.bar }}').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"my god is blue")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateNotFound):
|
2013-07-19 14:02:03 +00:00
|
|
|
env.from_string('{% import_yaml "does not exists" as doc %}').render()
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
def test_load_json_template(self):
|
|
|
|
loader = DictLoader({'foo': '{"bar": "my god is blue", "foo": [1, 2, 3]}'})
|
|
|
|
env = Environment(extensions=[SerializerExtension], loader=loader)
|
2013-07-19 14:02:03 +00:00
|
|
|
rendered = env.from_string('{% import_json "foo" as doc %}{{ doc.bar }}').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"my god is blue")
|
2013-07-19 13:10:06 +00:00
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateNotFound):
|
2013-07-19 14:02:03 +00:00
|
|
|
env.from_string('{% import_json "does not exists" as doc %}').render()
|
2013-07-19 13:10:06 +00:00
|
|
|
|
2014-03-07 01:30:47 +00:00
|
|
|
def test_load_text_template(self):
|
|
|
|
loader = DictLoader({'foo': 'Foo!'})
|
|
|
|
env = Environment(extensions=[SerializerExtension], loader=loader)
|
|
|
|
|
|
|
|
rendered = env.from_string('{% import_text "foo" as doc %}{{ doc }}').render()
|
|
|
|
self.assertEqual(rendered, u"Foo!")
|
|
|
|
|
|
|
|
with self.assertRaises(exceptions.TemplateNotFound):
|
|
|
|
env.from_string('{% import_text "does not exists" as doc %}').render()
|
|
|
|
|
2013-07-25 15:22:38 +00:00
|
|
|
def test_catalog(self):
|
|
|
|
loader = DictLoader({
|
|
|
|
'doc1': '{bar: "my god is blue"}',
|
|
|
|
'doc2': '{% import_yaml "doc1" as local2 %} never exported',
|
|
|
|
'doc3': '{% load_yaml as local3 %}{"foo": "it works"}{% endload %} me neither',
|
|
|
|
'main1': '{% from "doc2" import local2 %}{{ local2.bar }}',
|
|
|
|
'main2': '{% from "doc3" import local3 %}{{ local3.foo }}',
|
|
|
|
'main3': '''
|
|
|
|
{% import "doc2" as imported2 %}
|
|
|
|
{% import "doc3" as imported3 %}
|
|
|
|
{{ imported2.local2.bar }}
|
|
|
|
''',
|
|
|
|
'main4': '''
|
|
|
|
{% import "doc2" as imported2 %}
|
|
|
|
{% import "doc3" as imported3 %}
|
|
|
|
{{ imported3.local3.foo }}
|
|
|
|
''',
|
|
|
|
'main5': '''
|
|
|
|
{% from "doc2" import local2 as imported2 %}
|
|
|
|
{% from "doc3" import local3 as imported3 %}
|
|
|
|
{{ imported2.bar }}
|
|
|
|
''',
|
|
|
|
'main6': '''
|
|
|
|
{% from "doc2" import local2 as imported2 %}
|
|
|
|
{% from "doc3" import local3 as imported3 %}
|
|
|
|
{{ imported3.foo }}
|
|
|
|
'''
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
env = Environment(extensions=[SerializerExtension], loader=loader)
|
|
|
|
rendered = env.get_template('main1').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"my god is blue")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
rendered = env.get_template('main2').render()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
rendered = env.get_template('main3').render().strip()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"my god is blue")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
rendered = env.get_template('main4').render().strip()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
rendered = env.get_template('main5').render().strip()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"my god is blue")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
|
|
|
rendered = env.get_template('main6').render().strip()
|
2013-10-24 09:39:04 +00:00
|
|
|
self.assertEqual(rendered, u"it works")
|
2013-07-25 15:22:38 +00:00
|
|
|
|
2013-10-24 09:10:13 +00:00
|
|
|
def test_nested_structures(self):
|
|
|
|
env = Environment(extensions=[SerializerExtension])
|
|
|
|
rendered = env.from_string('{{ data }}').render(data="foo")
|
2013-10-24 15:34:38 +00:00
|
|
|
self.assertEqual(rendered, u"foo")
|
2013-10-24 09:10:13 +00:00
|
|
|
|
2013-10-24 09:44:38 +00:00
|
|
|
data = OrderedDict([
|
|
|
|
('foo', OrderedDict([
|
|
|
|
('bar', 'baz'),
|
|
|
|
('qux', 42)
|
|
|
|
])
|
|
|
|
)
|
|
|
|
])
|
|
|
|
|
|
|
|
rendered = env.from_string('{{ data }}').render(data=data)
|
2013-10-24 15:34:38 +00:00
|
|
|
self.assertEqual(rendered, u"{'foo': {'bar': 'baz', 'qux': 42}}")
|
2013-10-24 09:10:13 +00:00
|
|
|
|
|
|
|
rendered = env.from_string('{{ data }}').render(data=[
|
|
|
|
OrderedDict(
|
|
|
|
foo='bar',
|
|
|
|
),
|
|
|
|
OrderedDict(
|
|
|
|
baz=42,
|
|
|
|
)
|
|
|
|
])
|
2013-10-24 15:34:38 +00:00
|
|
|
self.assertEqual(rendered, u"[{'foo': 'bar'}, {'baz': 42}]")
|
2013-10-24 09:10:13 +00:00
|
|
|
|
2014-02-12 10:19:09 +00:00
|
|
|
def test_sequence(self):
|
2014-02-15 17:26:35 +00:00
|
|
|
env = Environment()
|
|
|
|
env.filters['sequence'] = ensure_sequence_filter
|
2014-02-12 10:19:09 +00:00
|
|
|
|
|
|
|
rendered = env.from_string('{{ data | sequence | length }}') \
|
|
|
|
.render(data='foo')
|
|
|
|
self.assertEqual(rendered, '1')
|
|
|
|
|
|
|
|
rendered = env.from_string('{{ data | sequence | length }}') \
|
|
|
|
.render(data=['foo', 'bar'])
|
|
|
|
self.assertEqual(rendered, '2')
|
|
|
|
|
|
|
|
rendered = env.from_string('{{ data | sequence | length }}') \
|
|
|
|
.render(data=('foo', 'bar'))
|
|
|
|
self.assertEqual(rendered, '2')
|
|
|
|
|
|
|
|
rendered = env.from_string('{{ data | sequence | length }}') \
|
|
|
|
.render(data=set(['foo', 'bar']))
|
|
|
|
self.assertEqual(rendered, '2')
|
|
|
|
|
|
|
|
rendered = env.from_string('{{ data | sequence | length }}') \
|
|
|
|
.render(data={'foo': 'bar'})
|
|
|
|
self.assertEqual(rendered, '1')
|
|
|
|
|
2016-12-01 14:05:00 +00:00
|
|
|
def test_is_ip(self):
|
|
|
|
'''Test the `is_ip` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | is_ip }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'FE80::' | is_ip }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | is_ip }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
def test_is_ipv4(self):
|
|
|
|
'''Test the `is_ipv4` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | is_ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'FE80::' | is_ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | is_ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
def test_is_ipv6(self):
|
|
|
|
'''Test the `is_ipv6` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | is_ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'FE80::' | is_ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | is_ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
def test_ipaddr(self):
|
|
|
|
'''Test the `ipaddr` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | ipaddr }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'192.168.0.1')
|
|
|
|
|
|
|
|
# provides a list with valid IP addresses only
|
|
|
|
rendered = render_jinja_tmpl("{{ ['192.168.0.1', '172.17.17.1', 'foo', 'bar', '::'] | ipaddr | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'192.168.0.1, 172.17.17.1, ::')
|
|
|
|
|
|
|
|
# return only multicast addresses
|
|
|
|
rendered = render_jinja_tmpl("{{ ['224.0.0.1', 'FF01::1', '::'] | ipaddr(options='multicast') | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'224.0.0.1, ff01::1')
|
|
|
|
|
|
|
|
def test_ipv4(self):
|
|
|
|
'''Test the `ipv4` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'192.168.0.1')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ ['192.168.0.1', '172.17.17.1'] | ipv4 | join(', ')}}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'192.168.0.1, 172.17.17.1')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'fe80::' | ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | ipv4 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | ipv4(options='lo') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ '127.0.0.1' | ipv4(options='lo') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'127.0.0.1')
|
|
|
|
|
|
|
|
def test_ipv6(self):
|
|
|
|
'''Test the `ipv6` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
# returns the standard format value
|
|
|
|
rendered = render_jinja_tmpl("{{ 'FE80:0:0::0' | ipv6 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'fe80::')
|
|
|
|
|
|
|
|
# fe80:: is link local therefore will be returned
|
|
|
|
rendered = render_jinja_tmpl("{{ 'fe80::' | ipv6(options='ll') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'fe80::')
|
|
|
|
|
|
|
|
# fe80:: is not loopback
|
|
|
|
rendered = render_jinja_tmpl("{{ 'fe80::' | ipv6(options='lo') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'None')
|
|
|
|
|
|
|
|
# returns only IPv6 addresses in the list
|
|
|
|
rendered = render_jinja_tmpl("{{ ['fe80::', '192.168.0.1'] | ipv6 | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'fe80::')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ ['fe80::', '::'] | ipv6 | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'fe80::, ::')
|
|
|
|
|
|
|
|
def test_network_hosts(self):
|
|
|
|
'''Test the `network_hosts` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1/30' | network_hosts | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'192.168.0.1, 192.168.0.2')
|
|
|
|
|
|
|
|
def test_network_size(self):
|
|
|
|
'''Test the `network_size` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1' | network_size }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'1')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ '192.168.0.1/8' | network_size }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'16777216')
|
|
|
|
|
|
|
|
def test_http_query(self):
|
|
|
|
'''Test the `http_query` Jinja filter.'''
|
2017-02-19 15:35:30 +00:00
|
|
|
for backend in ('requests', 'tornado', 'urllib2'):
|
|
|
|
rendered = render_jinja_tmpl("{{ 'http://www.google.com' | http_query(backend='" + backend + "') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertIsInstance(rendered, six.text_type, 'Failed with backend: {}'.format(backend))
|
|
|
|
dict_reply = ast.literal_eval(rendered)
|
|
|
|
self.assertIsInstance(dict_reply, dict, 'Failed with backend: {}'.format(backend))
|
|
|
|
self.assertIsInstance(dict_reply['body'], six.string_types, 'Failed with backend: {}'.format(backend))
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def test_to_bool(self):
|
|
|
|
'''Test the `to_bool` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 1 | to_bool }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'True' | to_bool }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 0 | to_bool }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl("{{ 'Yes' | to_bool }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
def test_quote(self):
|
|
|
|
'''Test the `quote` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | quote }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'random')
|
|
|
|
|
|
|
|
def test_regex_search(self):
|
|
|
|
'''Test the `regex_search` Jinja filter.'''
|
2016-12-01 16:12:53 +00:00
|
|
|
rendered = render_jinja_tmpl("{{ 'abcdefabcdef' | regex_search('BC(.*)', ignorecase=True) }}",
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2016-12-01 16:12:53 +00:00
|
|
|
self.assertEqual(rendered, u"('defabcdef',)") # because search looks only at the beginning
|
|
|
|
|
|
|
|
def test_regex_match(self):
|
|
|
|
'''Test the `regex_match` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'abcdefabcdef' | regex_match('BC(.*)', ignorecase=True)}}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u"None")
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def test_regex_replace(self):
|
|
|
|
'''Test the `regex_replace` Jinja filter.'''
|
2017-01-25 16:32:09 +00:00
|
|
|
rendered = render_jinja_tmpl(r"{{ 'lets replace spaces' | regex_replace('\s+', '__') }}",
|
2016-12-01 14:05:00 +00:00
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'lets__replace__spaces')
|
|
|
|
|
|
|
|
def test_uuid(self):
|
|
|
|
'''Test the `uuid` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | uuid }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2016-12-01 16:12:53 +00:00
|
|
|
self.assertEqual(rendered, u'3652b285-26ad-588e-a5dc-c2ee65edc804')
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def test_min(self):
|
|
|
|
'''Test the `min` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | min }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2017-02-09 15:53:00 +00:00
|
|
|
self.assertEqual(rendered, u'1')
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def test_max(self):
|
|
|
|
'''Test the `max` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | max }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
2017-02-09 15:53:00 +00:00
|
|
|
self.assertEqual(rendered, u'3')
|
2016-12-01 14:05:00 +00:00
|
|
|
|
|
|
|
def test_avg(self):
|
|
|
|
'''Test the `avg` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | avg }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'2.0')
|
|
|
|
|
|
|
|
def test_union(self):
|
|
|
|
'''Test the `union` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | union([2, 3, 4]) | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'1, 2, 3, 4')
|
|
|
|
|
|
|
|
def test_intersect(self):
|
|
|
|
'''Test the `intersect` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | intersect([2, 3, 4]) | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'2, 3')
|
|
|
|
|
|
|
|
def test_difference(self):
|
|
|
|
'''Test the `difference` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | difference([2, 3, 4]) | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'1')
|
|
|
|
|
|
|
|
def test_symmetric_difference(self):
|
|
|
|
'''Test the `symmetric_difference` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ [1, 2, 3] | symmetric_difference([2, 3, 4]) | join(', ') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'1, 4')
|
|
|
|
|
|
|
|
def test_md5(self):
|
|
|
|
'''Test the `md5` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | md5 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'7ddf32e17a6ac5ce04a8ecbf782ca509')
|
|
|
|
|
|
|
|
def test_sha256(self):
|
|
|
|
'''Test the `sha256` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | sha256 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'a441b15fe9a3cf56661190a0b93b9dec7d04127288cc87250967cf3b52894d11')
|
|
|
|
|
|
|
|
def test_sha512(self):
|
|
|
|
'''Test the `sha512` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | sha512 }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, six.text_type(('811a90e1c8e86c7b4c0eef5b2c0bf0ec1b19c4b1b5a242e6455be93787cb473cb7bc'
|
|
|
|
'9b0fdeb960d00d5c6881c2094dd63c5c900ce9057255e2a4e271fc25fef1')))
|
|
|
|
|
|
|
|
def test_hmac(self):
|
|
|
|
'''Test the `hmac` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | hmac('secret', 'blah') }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'False')
|
|
|
|
|
|
|
|
rendered = render_jinja_tmpl(("{{ 'get salted' | "
|
|
|
|
"hmac('shared secret', 'eBWf9bstXg+NiP5AOwppB5HMvZiYMPzEM9W5YMm/AmQ=') }}"),
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'True')
|
|
|
|
|
|
|
|
def test_base64_encode(self):
|
|
|
|
'''Test the `base64_encode` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'random' | base64_encode }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'cmFuZG9t')
|
|
|
|
|
|
|
|
def test_base64_decode(self):
|
|
|
|
'''Test the `base64_decode` Jinja filter.'''
|
|
|
|
rendered = render_jinja_tmpl("{{ 'cmFuZG9t' | base64_decode }}",
|
|
|
|
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
|
|
|
|
self.assertEqual(rendered, u'random')
|
|
|
|
|
2013-07-25 15:22:38 +00:00
|
|
|
# def test_print(self):
|
|
|
|
# env = Environment(extensions=[SerializerExtension])
|
|
|
|
# source = '{% import_yaml "toto.foo" as docu %}'
|
|
|
|
# name, filename = None, '<filename>'
|
|
|
|
# parsed = env._parse(source, name, filename)
|
|
|
|
# print parsed
|
|
|
|
# print
|
|
|
|
# compiled = env._generate(parsed, name, filename)
|
|
|
|
# print compiled
|
|
|
|
# return
|
|
|
|
|
|
|
|
|
2014-07-07 02:04:17 +00:00
|
|
|
class TestDotNotationLookup(ModuleCase):
|
|
|
|
'''
|
|
|
|
Tests to call Salt functions via Jinja with various lookup syntaxes
|
|
|
|
'''
|
|
|
|
def setUp(self, *args, **kwargs):
|
|
|
|
functions = {
|
|
|
|
'mocktest.ping': lambda: True,
|
|
|
|
'mockgrains.get': lambda x: 'jerry',
|
|
|
|
}
|
2015-06-10 21:50:53 +00:00
|
|
|
minion_opts = salt.config.minion_config(os.path.join(TMP_CONF_DIR, 'minion'))
|
2015-06-10 21:37:01 +00:00
|
|
|
render = salt.loader.render(minion_opts, functions)
|
2014-07-07 02:04:17 +00:00
|
|
|
self.jinja = render.get('jinja')
|
|
|
|
|
2017-03-15 19:23:47 +00:00
|
|
|
def tearDown(self):
|
|
|
|
del self.jinja
|
|
|
|
|
2014-07-07 02:04:17 +00:00
|
|
|
def render(self, tmpl_str, context=None):
|
|
|
|
return self.jinja(tmpl_str, context=context or {}, from_str=True).read()
|
|
|
|
|
|
|
|
def test_normlookup(self):
|
|
|
|
'''
|
|
|
|
Sanity-check the normal dictionary-lookup syntax for our stub function
|
|
|
|
'''
|
|
|
|
tmpl_str = '''Hello, {{ salt['mocktest.ping']() }}.'''
|
|
|
|
|
|
|
|
ret = self.render(tmpl_str)
|
|
|
|
self.assertEqual(ret, 'Hello, True.')
|
|
|
|
|
|
|
|
def test_dotlookup(self):
|
|
|
|
'''
|
|
|
|
Check calling a stub function using awesome dot-notation
|
|
|
|
'''
|
|
|
|
tmpl_str = '''Hello, {{ salt.mocktest.ping() }}.'''
|
|
|
|
|
|
|
|
ret = self.render(tmpl_str)
|
|
|
|
self.assertEqual(ret, 'Hello, True.')
|
|
|
|
|
|
|
|
def test_shadowed_dict_method(self):
|
|
|
|
'''
|
|
|
|
Check calling a stub function with a name that shadows a ``dict``
|
|
|
|
method name
|
|
|
|
'''
|
|
|
|
tmpl_str = '''Hello, {{ salt.mockgrains.get('id') }}.'''
|
|
|
|
|
|
|
|
ret = self.render(tmpl_str)
|
|
|
|
self.assertEqual(ret, 'Hello, jerry.')
|