1# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17 18# Make coding more python3-ish 19from __future__ import (absolute_import, division, print_function) 20__metaclass__ = type 21 22 23from units.compat import unittest 24from units.compat.builtins import BUILTINS 25from units.compat.mock import mock_open, patch 26from ansible.errors import AnsibleError 27from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject 28 29 30class TestErrors(unittest.TestCase): 31 32 def setUp(self): 33 self.message = 'This is the error message' 34 self.unicode_message = 'This is an error with \xf0\x9f\x98\xa8 in it' 35 36 self.obj = AnsibleBaseYAMLObject() 37 38 def test_basic_error(self): 39 e = AnsibleError(self.message) 40 self.assertEqual(e.message, self.message) 41 self.assertEqual(e.__repr__(), self.message) 42 43 def test_basic_unicode_error(self): 44 e = AnsibleError(self.unicode_message) 45 self.assertEqual(e.message, self.unicode_message) 46 self.assertEqual(e.__repr__(), self.unicode_message) 47 48 @patch.object(AnsibleError, '_get_error_lines_from_file') 49 def test_error_with_kv(self, mock_method): 50 ''' This tests a task with both YAML and k=v syntax 51 52 - lineinfile: line=foo path=bar 53 line: foo 54 55 An accurate error message and position indicator are expected. 56 57 _get_error_lines_from_file() returns (target_line, prev_line) 58 ''' 59 60 self.obj.ansible_pos = ('foo.yml', 2, 1) 61 62 mock_method.return_value = [' line: foo\n', '- lineinfile: line=foo path=bar\n'] 63 64 e = AnsibleError(self.message, self.obj) 65 self.assertEqual( 66 e.message, 67 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 1, column 19, but may\nbe elsewhere in the " 68 "file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n- lineinfile: line=foo path=bar\n" 69 " ^ here\n\n" 70 "There appears to be both 'k=v' shorthand syntax and YAML in this task. Only one syntax may be used.\n") 71 ) 72 73 @patch.object(AnsibleError, '_get_error_lines_from_file') 74 def test_error_with_object(self, mock_method): 75 self.obj.ansible_pos = ('foo.yml', 1, 1) 76 77 mock_method.return_value = ('this is line 1\n', '') 78 e = AnsibleError(self.message, self.obj) 79 80 self.assertEqual( 81 e.message, 82 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 1, column 1, but may\nbe elsewhere in the file depending on the " 83 "exact syntax problem.\n\nThe offending line appears to be:\n\n\nthis is line 1\n^ here\n") 84 ) 85 86 def test_get_error_lines_from_file(self): 87 m = mock_open() 88 m.return_value.readlines.return_value = ['this is line 1\n'] 89 90 with patch('{0}.open'.format(BUILTINS), m): 91 # this line will be found in the file 92 self.obj.ansible_pos = ('foo.yml', 1, 1) 93 e = AnsibleError(self.message, self.obj) 94 self.assertEqual( 95 e.message, 96 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 1, column 1, but may\nbe elsewhere in the file depending on " 97 "the exact syntax problem.\n\nThe offending line appears to be:\n\n\nthis is line 1\n^ here\n") 98 ) 99 100 with patch('ansible.errors.to_text', side_effect=IndexError('Raised intentionally')): 101 # raise an IndexError 102 self.obj.ansible_pos = ('foo.yml', 2, 1) 103 e = AnsibleError(self.message, self.obj) 104 self.assertEqual( 105 e.message, 106 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 2, column 1, but may\nbe elsewhere in the file depending on " 107 "the exact syntax problem.\n\n(specified line no longer in file, maybe it changed?)") 108 ) 109 110 m = mock_open() 111 m.return_value.readlines.return_value = ['this line has unicode \xf0\x9f\x98\xa8 in it!\n'] 112 113 with patch('{0}.open'.format(BUILTINS), m): 114 # this line will be found in the file 115 self.obj.ansible_pos = ('foo.yml', 1, 1) 116 e = AnsibleError(self.unicode_message, self.obj) 117 self.assertEqual( 118 e.message, 119 ("This is an error with \xf0\x9f\x98\xa8 in it\n\nThe error appears to be in 'foo.yml': line 1, column 1, but may\nbe elsewhere in the " 120 "file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\nthis line has unicode \xf0\x9f\x98\xa8 in it!\n^ " 121 "here\n") 122 ) 123 124 def test_get_error_lines_error_in_last_line(self): 125 m = mock_open() 126 m.return_value.readlines.return_value = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n'] 127 128 with patch('{0}.open'.format(BUILTINS), m): 129 # If the error occurs in the last line of the file, use the correct index to get the line 130 # and avoid the IndexError 131 self.obj.ansible_pos = ('foo.yml', 4, 1) 132 e = AnsibleError(self.message, self.obj) 133 self.assertEqual( 134 e.message, 135 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 4, column 1, but may\nbe elsewhere in the file depending on " 136 "the exact syntax problem.\n\nThe offending line appears to be:\n\nthis is line 2\nthis is line 3\n^ here\n") 137 ) 138 139 def test_get_error_lines_error_empty_lines_around_error(self): 140 """Test that trailing whitespace after the error is removed""" 141 m = mock_open() 142 m.return_value.readlines.return_value = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n', ' \n', ' \n', ' '] 143 144 with patch('{0}.open'.format(BUILTINS), m): 145 self.obj.ansible_pos = ('foo.yml', 5, 1) 146 e = AnsibleError(self.message, self.obj) 147 self.assertEqual( 148 e.message, 149 ("This is the error message\n\nThe error appears to be in 'foo.yml': line 5, column 1, but may\nbe elsewhere in the file depending on " 150 "the exact syntax problem.\n\nThe offending line appears to be:\n\nthis is line 2\nthis is line 3\n^ here\n") 151 ) 152