From 5062f4962f8e7939c4656a059fc86e0fb4a3bf55 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Fri, 7 Mar 2014 21:51:12 -0600 Subject: [PATCH] Unit tests for ansible.utils --- test/units/TestModuleUtilsBasic.py | 7 +- test/units/TestUtils.py | 658 +++++++++++++++++-- test/units/TestUtilsStringFunctions.py | 33 + test/units/inventory_test_data/broken.yml | 2 + test/units/inventory_test_data/encrypted.yml | 6 + 5 files changed, 640 insertions(+), 66 deletions(-) create mode 100644 test/units/TestUtilsStringFunctions.py create mode 100644 test/units/inventory_test_data/broken.yml create mode 100644 test/units/inventory_test_data/encrypted.yml diff --git a/test/units/TestModuleUtilsBasic.py b/test/units/TestModuleUtilsBasic.py index 547de0f792a..3d85b613525 100644 --- a/test/units/TestModuleUtilsBasic.py +++ b/test/units/TestModuleUtilsBasic.py @@ -50,8 +50,13 @@ class TestModuleUtilsBasic(unittest.TestCase): exec(module_data, d, d) self.module = d['get_module']() + # module_utils/basic.py screws with CWD, let's save it and reset + self.cwd = os.getcwd() + def tearDown(self): self.cleanup_temp_file(self.tmp_fd, self.tmp_path) + # Reset CWD back to what it was before basic.py changed it + os.chdir(self.cwd) ################################################################################# # run_command() tests @@ -147,7 +152,7 @@ class TestModuleUtilsBasic(unittest.TestCase): (rc, out, err) = self.module.run_command('pwd', cwd=tmp_path) self.assertEqual(rc, 0) self.assertTrue(os.path.exists(tmp_path)) - self.assertEqual(out.strip(), tmp_path) + self.assertEqual(out.strip(), os.path.realpath(tmp_path)) except: raise finally: diff --git a/test/units/TestUtils.py b/test/units/TestUtils.py index 28e0dfc0cd2..a56a79e4ef2 100644 --- a/test/units/TestUtils.py +++ b/test/units/TestUtils.py @@ -4,12 +4,21 @@ import unittest import os import os.path import tempfile +import yaml +import passlib.hash +import string +import StringIO +import copy from nose.plugins.skip import SkipTest import ansible.utils +import ansible.errors +import ansible.constants as C import ansible.utils.template as template2 +from ansible import __version__ + import sys reload(sys) sys.setdefaultencoding("utf8") @@ -22,22 +31,22 @@ class TestUtils(unittest.TestCase): input = "before # comment" expected = "before " actual = ansible.utils.before_comment(input) - assert expected == actual + self.assertEqual(expected, actual) input = "before \# not a comment" expected = "before # not a comment" actual = ansible.utils.before_comment(input) - assert expected == actual + self.assertEqual(expected, actual) input = "" expected = "" actual = ansible.utils.before_comment(input) - assert expected == actual + self.assertEqual(expected, actual) input = "#" expected = "" actual = ansible.utils.before_comment(input) - assert expected == actual + self.assertEqual(expected, actual) ##################################### ### check_conditional tests @@ -45,97 +54,616 @@ class TestUtils(unittest.TestCase): def test_check_conditional_jinja2_literals(self): # see http://jinja.pocoo.org/docs/templates/#literals + # none + self.assertEqual(ansible.utils.check_conditional( + None, '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + '', '/', {}), True) + + # list + self.assertEqual(ansible.utils.check_conditional( + ['true'], '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + ['false'], '/', {}), False) + + # non basestring or list + self.assertEqual(ansible.utils.check_conditional( + {}, '/', {}), {}) + # boolean - assert(ansible.utils.check_conditional( - 'true', '/', {}) == True) - assert(ansible.utils.check_conditional( - 'false', '/', {}) == False) - assert(ansible.utils.check_conditional( - 'True', '/', {}) == True) - assert(ansible.utils.check_conditional( - 'False', '/', {}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'true', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + 'false', '/', {}), False) + self.assertEqual(ansible.utils.check_conditional( + 'True', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + 'False', '/', {}), False) # integer - assert(ansible.utils.check_conditional( - '1', '/', {}) == True) - assert(ansible.utils.check_conditional( - '0', '/', {}) == False) + self.assertEqual(ansible.utils.check_conditional( + '1', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + '0', '/', {}), False) # string, beware, a string is truthy unless empty - assert(ansible.utils.check_conditional( - '"yes"', '/', {}) == True) - assert(ansible.utils.check_conditional( - '"no"', '/', {}) == True) - assert(ansible.utils.check_conditional( - '""', '/', {}) == False) + self.assertEqual(ansible.utils.check_conditional( + '"yes"', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + '"no"', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + '""', '/', {}), False) def test_check_conditional_jinja2_variable_literals(self): # see http://jinja.pocoo.org/docs/templates/#literals # boolean - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'True'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'true'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'False'}) == False) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'false'}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'True'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'true'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'False'}), False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'false'}), False) # integer - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '1'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 1}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '0'}) == False) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 0}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '1'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 1}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '0'}), False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 0}), False) # string, beware, a string is truthy unless empty - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '"yes"'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '"no"'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '""'}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '"yes"'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '"no"'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '""'}), False) # Python boolean in Jinja2 expression - assert(ansible.utils.check_conditional( - 'var', '/', {'var': True}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': False}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': True}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': False}), False) def test_check_conditional_jinja2_expression(self): - assert(ansible.utils.check_conditional( - '1 == 1', '/', {}) == True) - assert(ansible.utils.check_conditional( - 'bar == 42', '/', {'bar': 42}) == True) - assert(ansible.utils.check_conditional( - 'bar != 42', '/', {'bar': 42}) == False) + self.assertEqual(ansible.utils.check_conditional( + '1 == 1', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + 'bar == 42', '/', {'bar': 42}), True) + self.assertEqual(ansible.utils.check_conditional( + 'bar != 42', '/', {'bar': 42}), False) def test_check_conditional_jinja2_expression_in_variable(self): - assert(ansible.utils.check_conditional( - 'var', '/', {'var': '1 == 1'}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'bar == 42', 'bar': 42}) == True) - assert(ansible.utils.check_conditional( - 'var', '/', {'var': 'bar != 42', 'bar': 42}) == False) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': '1 == 1'}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'bar == 42', 'bar': 42}), True) + self.assertEqual(ansible.utils.check_conditional( + 'var', '/', {'var': 'bar != 42', 'bar': 42}), False) def test_check_conditional_jinja2_unicode(self): - assert(ansible.utils.check_conditional( - u'"\u00df"', '/', {}) == True) - assert(ansible.utils.check_conditional( - u'var == "\u00df"', '/', {'var': u'\u00df'}) == True) + self.assertEqual(ansible.utils.check_conditional( + u'"\u00df"', '/', {}), True) + self.assertEqual(ansible.utils.check_conditional( + u'var == "\u00df"', '/', {'var': u'\u00df'}), True) ##################################### ### key-value parsing def test_parse_kv_basic(self): - assert (ansible.utils.parse_kv('a=simple b="with space" c="this=that"') == + self.assertEqual(ansible.utils.parse_kv('a=simple b="with space" c="this=that"'), {'a': 'simple', 'b': 'with space', 'c': 'this=that'}) + + def test_jsonify(self): + self.assertEqual(ansible.utils.jsonify(None), '{}') + self.assertEqual(ansible.utils.jsonify(dict(foo='bar', baz=['qux'])), + '{"baz": ["qux"], "foo": "bar"}') + expected = '''{ + "baz": [ + "qux" + ], + "foo": "bar" +}''' + self.assertEqual(ansible.utils.jsonify(dict(foo='bar', baz=['qux']), format=True), expected) + + def test_is_failed(self): + self.assertEqual(ansible.utils.is_failed(dict(rc=0)), False) + self.assertEqual(ansible.utils.is_failed(dict(rc=1)), True) + self.assertEqual(ansible.utils.is_failed(dict()), False) + self.assertEqual(ansible.utils.is_failed(dict(failed=False)), False) + self.assertEqual(ansible.utils.is_failed(dict(failed=True)), True) + self.assertEqual(ansible.utils.is_failed(dict(failed='True')), True) + self.assertEqual(ansible.utils.is_failed(dict(failed='true')), True) + + def test_is_changed(self): + self.assertEqual(ansible.utils.is_changed(dict()), False) + self.assertEqual(ansible.utils.is_changed(dict(changed=False)), False) + self.assertEqual(ansible.utils.is_changed(dict(changed=True)), True) + self.assertEqual(ansible.utils.is_changed(dict(changed='True')), True) + self.assertEqual(ansible.utils.is_changed(dict(changed='true')), True) + + def test_path_dwim(self): + self.assertEqual(ansible.utils.path_dwim(None, __file__), + __file__) + self.assertEqual(ansible.utils.path_dwim(None, '~'), + os.path.expanduser('~')) + self.assertEqual(ansible.utils.path_dwim(None, 'TestUtils.py'), + __file__.rstrip('c')) + + def test_path_dwim_relative(self): + self.assertEqual(ansible.utils.path_dwim_relative(__file__, 'units', 'TestUtils.py', + os.path.dirname(os.path.dirname(__file__))), + __file__.rstrip('c')) + + def test_json_loads(self): + self.assertEqual(ansible.utils.json_loads('{"foo": "bar"}'), dict(foo='bar')) + + def test_parse_json(self): + # leading junk + self.assertEqual(ansible.utils.parse_json('ansible\n{"foo": "bar"}'), dict(foo="bar")) + + # "baby" json + self.assertEqual(ansible.utils.parse_json('foo=bar baz=qux'), dict(foo='bar', baz='qux')) + + # No closing quotation + try: + ansible.utils.parse_json('foo=bar "') + except ValueError: + pass + else: + raise AssertionError('Incorrect exception, expected ValueError') + + # Failed to parse + try: + ansible.utils.parse_json('{') + except ansible.errors.AnsibleError: + pass + else: + raise AssertionError('Incorrect exception, expected ansible.errors.AnsibleError') + + # boolean changed/failed + self.assertEqual(ansible.utils.parse_json('changed=true'), dict(changed=True)) + self.assertEqual(ansible.utils.parse_json('changed=false'), dict(changed=False)) + self.assertEqual(ansible.utils.parse_json('failed=true'), dict(failed=True)) + self.assertEqual(ansible.utils.parse_json('failed=false'), dict(failed=False)) + + # rc + self.assertEqual(ansible.utils.parse_json('rc=0'), dict(rc=0)) + + # Just a string + self.assertEqual(ansible.utils.parse_json('foo'), dict(failed=True, parsed=False, msg='foo')) + + def test_smush_braces(self): + self.assertEqual(ansible.utils.smush_braces('{{ foo}}'), '{{foo}}') + self.assertEqual(ansible.utils.smush_braces('{{foo }}'), '{{foo}}') + self.assertEqual(ansible.utils.smush_braces('{{ foo }}'), '{{foo}}') + + def test_smush_ds(self): + # list + self.assertEqual(ansible.utils.smush_ds(['foo={{ foo }}']), ['foo={{foo}}']) + + # dict + self.assertEqual(ansible.utils.smush_ds(dict(foo='{{ foo }}')), dict(foo='{{foo}}')) + + # string + self.assertEqual(ansible.utils.smush_ds('foo={{ foo }}'), 'foo={{foo}}') + + # int + self.assertEqual(ansible.utils.smush_ds(0), 0) + + def test_parse_yaml(self): + #json + self.assertEqual(ansible.utils.parse_yaml('{"foo": "bar"}'), dict(foo='bar')) + + # broken json + try: + ansible.utils.parse_yaml('{') + except ansible.errors.AnsibleError: + pass + else: + raise AssertionError + + # broken json with path_hint + try: + ansible.utils.parse_yaml('{', path_hint='foo') + except ansible.errors.AnsibleError: + pass + else: + raise AssertionError + + # yaml with front-matter + self.assertEqual(ansible.utils.parse_yaml("---\nfoo: bar"), dict(foo='bar')) + # yaml no front-matter + self.assertEqual(ansible.utils.parse_yaml('foo: bar'), dict(foo='bar')) + # yaml indented first line (See #6348) + self.assertEqual(ansible.utils.parse_yaml(' - foo: bar\n baz: qux'), [dict(foo='bar', baz='qux')]) + + def test_process_common_errors(self): + # no quote + self.assertTrue('YAML thought it' in ansible.utils.process_common_errors('', 'foo: {{bar}}', 6)) + + # extra colon + self.assertTrue('an extra unquoted colon' in ansible.utils.process_common_errors('', 'foo: bar:', 8)) + + # match + self.assertTrue('same kind of quote' in ansible.utils.process_common_errors('', 'foo: "{{bar}}"baz', 6)) + self.assertTrue('same kind of quote' in ansible.utils.process_common_errors('', "foo: '{{bar}}'baz", 6)) + + # unbalanced + # The first test fails and is commented out for now, logic is wrong and the test fails + #self.assertTrue('We could be wrong' in ansible.utils.process_common_errors('', 'foo: "bad" "wolf"', 6)) + self.assertTrue('We could be wrong' in ansible.utils.process_common_errors('', "foo: 'bad' 'wolf'", 6)) + + + def test_process_yaml_error(self): + data = 'foo: bar\n baz: qux' + try: + ansible.utils.parse_yaml(data) + except yaml.YAMLError, exc: + try: + ansible.utils.process_yaml_error(exc, data, __file__) + except ansible.errors.AnsibleYAMLValidationFailed, e: + self.assertTrue('Syntax Error while loading' in e.msg) + else: + raise AssertionError('Incorrect exception, expected AnsibleYAMLValidationFailed') + + data = 'foo: bar\n baz: {{qux}}' + try: + ansible.utils.parse_yaml(data) + except yaml.YAMLError, exc: + try: + ansible.utils.process_yaml_error(exc, data, __file__) + except ansible.errors.AnsibleYAMLValidationFailed, e: + self.assertTrue('Syntax Error while loading' in e.msg) + else: + raise AssertionError('Incorrect exception, expected AnsibleYAMLValidationFailed') + + data = '\xFF' + try: + ansible.utils.parse_yaml(data) + except yaml.YAMLError, exc: + try: + ansible.utils.process_yaml_error(exc, data, __file__) + except ansible.errors.AnsibleYAMLValidationFailed, e: + self.assertTrue('Check over' in e.msg) + else: + raise AssertionError('Incorrect exception, expected AnsibleYAMLValidationFailed') + + data = '\xFF' + try: + ansible.utils.parse_yaml(data) + except yaml.YAMLError, exc: + try: + ansible.utils.process_yaml_error(exc, data, None) + except ansible.errors.AnsibleYAMLValidationFailed, e: + self.assertTrue('Could not parse YAML.' in e.msg) + else: + raise AssertionError('Incorrect exception, expected AnsibleYAMLValidationFailed') + + def test_parse_yaml_from_file(self): + test = os.path.join(os.path.dirname(__file__), 'inventory_test_data', + 'common_vars.yml') + encrypted = os.path.join(os.path.dirname(__file__), 'inventory_test_data', + 'encrypted.yml') + broken = os.path.join(os.path.dirname(__file__), 'inventory_test_data', + 'broken.yml') + + try: + ansible.utils.parse_yaml_from_file(os.path.dirname(__file__)) + except ansible.errors.AnsibleError: + pass + else: + raise AssertionError('Incorrect exception, expected AnsibleError') + + self.assertEqual(ansible.utils.parse_yaml_from_file(test), yaml.safe_load(open(test))) + + self.assertEqual(ansible.utils.parse_yaml_from_file(encrypted, 'ansible'), dict(foo='bar')) + + try: + ansible.utils.parse_yaml_from_file(broken) + except ansible.errors.AnsibleYAMLValidationFailed, e: + self.assertTrue('Syntax Error while loading' in e.msg) + else: + raise AssertionError('Incorrect exception, expected AnsibleYAMLValidationFailed') + + def test_merge_hash(self): + self.assertEqual(ansible.utils.merge_hash(dict(foo='bar', baz='qux'), dict(foo='baz')), + dict(foo='baz', baz='qux')) + self.assertEqual(ansible.utils.merge_hash(dict(foo=dict(bar='baz')), dict(foo=dict(bar='qux'))), + dict(foo=dict(bar='qux'))) + + def test_md5s(self): + self.assertEqual(ansible.utils.md5s('ansible'), '640c8a5376aa12fa15cf02130ce239a6') + # Need a test that causes UnicodeEncodeError See 4221 + + def test_md5(self): + self.assertEqual(ansible.utils.md5(os.path.join(os.path.dirname(__file__), 'ansible.cfg')), + 'fb7b5b90ea63f04bde33e804b6fad42c') + self.assertEqual(ansible.utils.md5(os.path.join(os.path.dirname(__file__), 'ansible.cf')), + None) + + def test_default(self): + self.assertEqual(ansible.utils.default(None, lambda: {}), {}) + self.assertEqual(ansible.utils.default(dict(foo='bar'), lambda: {}), dict(foo='bar')) + + def test__gitinfo(self): + # this fails if not run from git clone + # self.assertEqual('last updated' in ansible.utils._gitinfo()) + # missing test for git submodule + # missing test outside of git clone + pass + + def test_version(self): + version = ansible.utils.version('ansible') + self.assertTrue(version.startswith('ansible %s' % __version__)) + # this fails if not run from git clone + # self.assertEqual('last updated' in version) + + def test_getch(self): + # figure out how to test this + pass + + def test_sanitize_output(self): + self.assertEqual(ansible.utils.sanitize_output('password=foo'), 'password=VALUE_HIDDEN') + self.assertEqual(ansible.utils.sanitize_output('foo=user:pass@foo/whatever'), + 'foo=user:********@foo/whatever') + self.assertEqual(ansible.utils.sanitize_output('foo=http://username:pass@wherever/foo'), + 'foo=http://username:********@wherever/foo') + self.assertEqual(ansible.utils.sanitize_output('foo=http://wherever/foo'), + 'foo=http://wherever/foo') + + def test_increment_debug(self): + ansible.utils.VERBOSITY = 0 + ansible.utils.increment_debug(None, None, None, None) + self.assertEqual(ansible.utils.VERBOSITY, 1) + + def test_base_parser(self): + output = ansible.utils.base_parser(output_opts=True) + self.assertTrue(output.has_option('--one-line') and output.has_option('--tree')) + + runas = ansible.utils.base_parser(runas_opts=True) + for opt in ['--sudo', '--sudo-user', '--user', '--su', '--su-user']: + self.assertTrue(runas.has_option(opt)) + + async = ansible.utils.base_parser(async_opts=True) + self.assertTrue(async.has_option('--poll') and async.has_option('--background')) + + connect = ansible.utils.base_parser(connect_opts=True) + self.assertTrue(connect.has_option('--connection')) + + subset = ansible.utils.base_parser(subset_opts=True) + self.assertTrue(subset.has_option('--limit')) + + check = ansible.utils.base_parser(check_opts=True) + self.assertTrue(check.has_option('--check')) + + diff = ansible.utils.base_parser(diff_opts=True) + self.assertTrue(diff.has_option('--diff')) + + def test_do_encrypt(self): + salt_chars = string.ascii_letters + string.digits + './' + salt = ansible.utils.random_password(length=8, chars=salt_chars) + hash = ansible.utils.do_encrypt('ansible', 'sha256_crypt', salt=salt) + self.assertTrue(passlib.hash.sha256_crypt.verify('ansible', hash)) + + hash = ansible.utils.do_encrypt('ansible', 'sha256_crypt') + self.assertTrue(passlib.hash.sha256_crypt.verify('ansible', hash)) + + hash = ansible.utils.do_encrypt('ansible', 'md5_crypt', salt_size=4) + self.assertTrue(passlib.hash.md5_crypt.verify('ansible', hash)) + + + try: + ansible.utils.do_encrypt('ansible', 'ansible') + except ansible.errors.AnsibleError: + pass + else: + raise AssertionError('Incorrect exception, expected AnsibleError') + + def test_last_non_blank_line(self): + self.assertEqual(ansible.utils.last_non_blank_line('a\n\nb\n\nc'), 'c') + self.assertEqual(ansible.utils.last_non_blank_line(''), '') + + def test_filter_leading_non_json_lines(self): + self.assertEqual(ansible.utils.filter_leading_non_json_lines('a\nb\nansible!\n{"foo": "bar"}'), + '{"foo": "bar"}\n') + self.assertEqual(ansible.utils.filter_leading_non_json_lines('a\nb\nansible!\n["foo", "bar"]'), + '["foo", "bar"]\n') + self.assertEqual(ansible.utils.filter_leading_non_json_lines('a\nb\nansible!\nfoo=bar'), + 'foo=bar\n') + + def test_boolean(self): + self.assertEqual(ansible.utils.boolean("true"), True) + self.assertEqual(ansible.utils.boolean("True"), True) + self.assertEqual(ansible.utils.boolean("TRUE"), True) + self.assertEqual(ansible.utils.boolean("t"), True) + self.assertEqual(ansible.utils.boolean("T"), True) + self.assertEqual(ansible.utils.boolean("Y"), True) + self.assertEqual(ansible.utils.boolean("y"), True) + self.assertEqual(ansible.utils.boolean("1"), True) + self.assertEqual(ansible.utils.boolean(1), True) + self.assertEqual(ansible.utils.boolean("false"), False) + self.assertEqual(ansible.utils.boolean("False"), False) + self.assertEqual(ansible.utils.boolean("0"), False) + self.assertEqual(ansible.utils.boolean(0), False) + self.assertEqual(ansible.utils.boolean("foo"), False) + + def test_make_sudo_cmd(self): + cmd = ansible.utils.make_sudo_cmd('root', '/bin/sh', '/bin/ls') + self.assertTrue(isinstance(cmd, tuple)) + self.assertEqual(len(cmd), 3) + self.assertTrue('-u root' in cmd[0]) + self.assertTrue('-p "[sudo via ansible, key=' in cmd[0] and cmd[1].startswith('[sudo via ansible, key')) + self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) + self.assertTrue('sudo -k' in cmd[0]) + + def test_make_su_cmd(self): + cmd = ansible.utils.make_su_cmd('root', '/bin/sh', '/bin/ls') + self.assertTrue(isinstance(cmd, tuple)) + self.assertEqual(len(cmd), 3) + self.assertTrue(' root /bin/sh' in cmd[0]) + self.assertTrue(cmd[1] == 'assword: ') + self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) + + def test_to_unicode(self): + uni = ansible.utils.to_unicode(u'ansible') + self.assertTrue(isinstance(uni, unicode)) + self.assertEqual(uni, u'ansible') + + none = ansible.utils.to_unicode(None) + self.assertTrue(isinstance(none, type(None))) + self.assertTrue(none is None) + + utf8 = ansible.utils.to_unicode('ansible') + self.assertTrue(isinstance(utf8, unicode)) + self.assertEqual(utf8, u'ansible') + + def test_is_list_of_strings(self): + self.assertEqual(ansible.utils.is_list_of_strings(['foo', 'bar', u'baz']), True) + self.assertEqual(ansible.utils.is_list_of_strings(['foo', 'bar', True]), False) + self.assertEqual(ansible.utils.is_list_of_strings(['one', 2, 'three']), False) + + def test_safe_eval(self): + # Not basestring + self.assertEqual(ansible.utils.safe_eval(len), len) + self.assertEqual(ansible.utils.safe_eval(1), 1) + self.assertEqual(ansible.utils.safe_eval(len, include_exceptions=True), (len, None)) + self.assertEqual(ansible.utils.safe_eval(1, include_exceptions=True), (1, None)) + + # module + self.assertEqual(ansible.utils.safe_eval('foo.bar('), 'foo.bar(') + self.assertEqual(ansible.utils.safe_eval('foo.bar(', include_exceptions=True), ('foo.bar(', None)) + + # import + self.assertEqual(ansible.utils.safe_eval('import foo'), 'import foo') + self.assertEqual(ansible.utils.safe_eval('import foo', include_exceptions=True), ('import foo', None)) + + # valid simple eval + self.assertEqual(ansible.utils.safe_eval('True'), True) + self.assertEqual(ansible.utils.safe_eval('True', include_exceptions=True), (True, None)) + + # valid eval with lookup + self.assertEqual(ansible.utils.safe_eval('foo + bar', dict(foo=1, bar=2)), 3) + self.assertEqual(ansible.utils.safe_eval('foo + bar', dict(foo=1, bar=2), include_exceptions=True), (3, None)) + + # invalid eval + self.assertEqual(ansible.utils.safe_eval('foo'), 'foo') + nameerror = ansible.utils.safe_eval('foo', include_exceptions=True) + self.assertTrue(isinstance(nameerror, tuple)) + self.assertEqual(nameerror[0], 'foo') + self.assertTrue(isinstance(nameerror[1], NameError)) + + def test_listify_lookup_plugin_terms(self): + basedir = os.path.dirname(__file__) + self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict()), + ['things']) + self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=['one', 'two'])), + ['one', 'two']) + + def test_deprecated(self): + sys_stderr = sys.stderr + sys.stderr = StringIO.StringIO() + ansible.utils.deprecated('Ack!', '0.0') + out = sys.stderr.getvalue() + self.assertTrue('0.0' in out) + self.assertTrue('[DEPRECATION WARNING]' in out) + + sys.stderr = StringIO.StringIO() + ansible.utils.deprecated('Ack!', None) + out = sys.stderr.getvalue() + self.assertTrue('0.0' not in out) + self.assertTrue('[DEPRECATION WARNING]' in out) + + sys.stderr = StringIO.StringIO() + warnings = C.DEPRECATION_WARNINGS + C.DEPRECATION_WARNINGS = False + ansible.utils.deprecated('Ack!', None) + out = sys.stderr.getvalue() + self.assertTrue(not out) + C.DEPRECATION_WARNINGS = warnings + + sys.stderr = sys_stderr + + try: + ansible.utils.deprecated('Ack!', '0.0', True) + except ansible.errors.AnsibleError, e: + self.assertTrue('0.0' not in e.msg) + self.assertTrue('[DEPRECATED]' in e.msg) + else: + raise AssertionError("Incorrect exception, expected AnsibleError") + + def test_warning(self): + sys_stderr = sys.stderr + sys.stderr = StringIO.StringIO() + ansible.utils.warning('ANSIBLE') + out = sys.stderr.getvalue() + sys.stderr = sys_stderr + self.assertTrue('[WARNING]: ANSIBLE' in out) + + def test_combine_vars(self): + one = {'foo': {'bar': True}, 'baz': {'one': 'qux'}} + two = {'baz': {'two': 'qux'}} + replace = {'baz': {'two': 'qux'}, 'foo': {'bar': True}} + merge = {'baz': {'two': 'qux', 'one': 'qux'}, 'foo': {'bar': True}} + + C.DEFAULT_HASH_BEHAVIOUR = 'replace' + self.assertEqual(ansible.utils.combine_vars(one, two), replace) + + C.DEFAULT_HASH_BEHAVIOUR = 'merge' + self.assertEqual(ansible.utils.combine_vars(one, two), merge) + + def test_err(self): + sys_stderr = sys.stderr + sys.stderr = StringIO.StringIO() + ansible.utils.err('ANSIBLE') + out = sys.stderr.getvalue() + sys.stderr = sys_stderr + self.assertEqual(out, 'ANSIBLE\n') + + def test_exit(self): + sys_stderr = sys.stderr + sys.stderr = StringIO.StringIO() + try: + ansible.utils.exit('ansible') + except SystemExit, e: + self.assertEqual(e.code, 1) + self.assertEqual(sys.stderr.getvalue(), 'ansible\n') + else: + raise AssertionError('Incorrect exception, expected SystemExit') + finally: + sys.stderr = sys_stderr + + def test_unfrackpath(self): + os.environ['TEST_ROOT'] = os.path.dirname(os.path.dirname(__file__)) + self.assertEqual(ansible.utils.unfrackpath('$TEST_ROOT/units/../units/TestUtils.py'), __file__.rstrip('c')) + + def test_is_executable(self): + self.assertEqual(ansible.utils.is_executable(__file__), 0) + + bin_ansible = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), + 'bin', 'ansible') + self.assertNotEqual(ansible.utils.is_executable(bin_ansible), 0) + + def test_get_diff(self): + standard = dict( + before_header='foo', + after_header='bar', + before='fooo', + after='foo' + ) + standard_expected = """--- before: foo ++++ after: bar +@@ -1 +1 @@ +-fooo+foo""" + self.assertEqual(ansible.utils.get_diff(standard), standard_expected) diff --git a/test/units/TestUtilsStringFunctions.py b/test/units/TestUtilsStringFunctions.py new file mode 100644 index 00000000000..cccedf280d3 --- /dev/null +++ b/test/units/TestUtilsStringFunctions.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +import unittest +import os +import os.path +import tempfile +import yaml +import passlib.hash +import string +import StringIO +import copy + +from nose.plugins.skip import SkipTest + +from ansible.utils import string_functions +import ansible.errors +import ansible.constants as C +import ansible.utils.template as template2 + +from ansible import __version__ + +import sys +reload(sys) +sys.setdefaultencoding("utf8") + +class TestUtilsStringFunctions(unittest.TestCase): + def test_isprintable(self): + self.assertFalse(string_functions.isprintable(chr(7))) + self.assertTrue(string_functions.isprintable('hello')) + + def test_count_newlines_from_end(self): + self.assertEqual(string_functions.count_newlines_from_end('foo\n\n\n\n'), 4) + self.assertEqual(string_functions.count_newlines_from_end('\nfoo'), 0) diff --git a/test/units/inventory_test_data/broken.yml b/test/units/inventory_test_data/broken.yml new file mode 100644 index 00000000000..0eccc1ba78c --- /dev/null +++ b/test/units/inventory_test_data/broken.yml @@ -0,0 +1,2 @@ +foo: bar + baz: qux diff --git a/test/units/inventory_test_data/encrypted.yml b/test/units/inventory_test_data/encrypted.yml new file mode 100644 index 00000000000..ca33ab25cbb --- /dev/null +++ b/test/units/inventory_test_data/encrypted.yml @@ -0,0 +1,6 @@ +$ANSIBLE_VAULT;1.1;AES256 +33343734386261666161626433386662623039356366656637303939306563376130623138626165 +6436333766346533353463636566313332623130383662340a393835656134633665333861393331 +37666233346464636263636530626332623035633135363732623332313534306438393366323966 +3135306561356164310a343937653834643433343734653137383339323330626437313562306630 +3035