Browse Source

Unit testing for undercloud_conf

- modifies custom module undercloud_conf.py in such a way that its individual
  stages can be easily tested
- tests for this module (test_undercloud_conf.py) are created

Change-Id: I65951cd9bc864a731d485a94bf468eab46e7e2a0
Partial-Bug: #1594785
Katerina Pilatova 2 years ago
parent
commit
a85fdc643b
2 changed files with 201 additions and 14 deletions
  1. 144
    0
      tripleo_validations/tests/test_undercloud_conf.py
  2. 57
    14
      validations/library/undercloud_conf.py

+ 144
- 0
tripleo_validations/tests/test_undercloud_conf.py View File

@@ -0,0 +1,144 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+"""
16
+test_undercloud_conf
17
+----------------------------------
18
+
19
+Tests for `undercloud_conf` module.
20
+"""
21
+
22
+import os
23
+import tempfile
24
+
25
+from tripleo_validations.tests import base
26
+import validations.library.undercloud_conf as validation
27
+
28
+
29
+missing_section_content = 'hello world'
30
+
31
+valid_content = '''
32
+[DEFAULT]
33
+debug=True
34
+
35
+[dhcp]
36
+dhcp_start=192.168.0.1
37
+dhcp_end=192.168.0.254
38
+
39
+[secrets]
40
+password=1234
41
+'''
42
+
43
+parsing_error_content = '''
44
+[DEFAULT]
45
+    debug =
46
+
47
+    [ip
48
+'''
49
+
50
+valid_result = {'DEFAULT': {'debug': 'True'},
51
+                'dhcp': {'debug': 'True',
52
+                         'dhcp_end': '192.168.0.254',
53
+                         'dhcp_start': '192.168.0.1'},
54
+                'secrets': {'debug': 'True',
55
+                            'password': '1234'}}
56
+
57
+
58
+class TestUndercloudConf(base.TestCase):
59
+
60
+    def test_check_arguments_invalid_path(self):
61
+        '''Test undercloud_conf when path is invalid'''
62
+
63
+        exists, errors = validation.check_arguments('non/existing/path', False)
64
+        self.assertEqual(False, exists)
65
+        self.assertEqual(1, len(errors))
66
+        self.assertEqual(errors[0], 'Could not open the undercloud.conf file' +
67
+                         ' at non/existing/path')
68
+
69
+    def test_check_arguments_valid_path(self):
70
+        '''Test undercloud_conf when path is valid'''
71
+
72
+        tmpfile = self.create_tmp_undercloud_conf()
73
+        tmp_name = os.path.relpath(tmpfile.name)
74
+        exists, errors = validation.check_arguments(tmp_name, False)
75
+        tmpfile.close()
76
+
77
+        self.assertEqual(True, exists)
78
+        self.assertEqual([], errors)
79
+
80
+    def test_check_arguments_ignore_missing_invalid_path(self):
81
+        '''Test undercloud_conf when ignore_missing is set, path is invalid'''
82
+
83
+        exists, errors = validation.check_arguments('non/existing/path', True)
84
+        self.assertEqual(False, exists)
85
+        self.assertEqual([], errors)
86
+
87
+    def test_check_arguments_ignore_missing_valid_path(self):
88
+        '''Test undercloud_conf when ignore_missing is set, path is valid'''
89
+
90
+        tmpfile = self.create_tmp_undercloud_conf()
91
+        tmp_name = os.path.relpath(tmpfile.name)
92
+        exists, errors = validation.check_arguments(tmp_name, True)
93
+        tmpfile.close()
94
+
95
+        self.assertEqual(True, exists)
96
+        self.assertEqual([], errors)
97
+
98
+    def test_get_result_missing_section_headers(self):
99
+        '''Test undercloud_conf when content format is invalid'''
100
+
101
+        tmpfile = self.create_tmp_undercloud_conf()
102
+        tmp_name = os.path.relpath(tmpfile.name)
103
+        tmpfile.write(missing_section_content.encode('utf-8'))
104
+        tmpfile.seek(0)
105
+        errors, result = validation.get_result(tmp_name)
106
+        tmpfile.close()
107
+
108
+        self.assertEqual({}, result)
109
+        self.assertEqual(1, len(errors))
110
+        self.assertEqual('File contains no section headers.', errors[0])
111
+
112
+    def test_get_result_parsing_error(self):
113
+        '''Test undercloud_conf when content format is invalid'''
114
+
115
+        tmpfile = self.create_tmp_undercloud_conf()
116
+        tmp_name = os.path.relpath(tmpfile.name)
117
+        tmpfile.write(parsing_error_content.encode('utf-8'))
118
+        tmpfile.seek(0)
119
+        errors, result = validation.get_result(tmp_name)
120
+        tmpfile.close()
121
+
122
+        self.assertEqual({}, result)
123
+        self.assertEqual(1, len(errors))
124
+        self.assertEqual('File contains parsing errors.', errors[0])
125
+
126
+    def test_get_result_valid_file(self):
127
+        '''Test undercloud_conf when content format is valid'''
128
+
129
+        tmpfile = self.create_tmp_undercloud_conf()
130
+        tmp_name = os.path.relpath(tmpfile.name)
131
+        tmpfile.write(valid_content.encode('utf-8'))
132
+        tmpfile.seek(0)
133
+        errors, result = validation.get_result(tmp_name)
134
+        tmpfile.close()
135
+
136
+        self.assertEqual(valid_result, result)
137
+        self.assertEqual([], errors)
138
+
139
+    def create_tmp_undercloud_conf(self):
140
+        '''Create temporary undercloud.conf file, return its full name'''
141
+        path = 'tripleo_validations/tests'
142
+        tmpfile = tempfile.NamedTemporaryFile(suffix='.conf',
143
+                                              prefix='undercloud', dir=path)
144
+        return tmpfile

+ 57
- 14
validations/library/undercloud_conf.py View File

@@ -14,12 +14,54 @@
14 14
 # License for the specific language governing permissions and limitations
15 15
 # under the License.
16 16
 
17
-import ConfigParser
17
+try:
18
+    import configparser as ConfigParser
19
+except ImportError:
20
+    import ConfigParser
21
+
18 22
 from os import path
19 23
 
20 24
 from ansible.module_utils.basic import *  # noqa
21 25
 
22 26
 
27
+def check_arguments(undercloud_conf_path, ignore_missing):
28
+    '''Validate format of arguments
29
+
30
+    return: (True, errors) if file can be opened
31
+            (False, errors) if ignore_missing or check failed
32
+    '''
33
+
34
+    errors = []
35
+
36
+    if path.exists(undercloud_conf_path) and path.isfile(undercloud_conf_path):
37
+        return (True, errors)
38
+    else:
39
+        if not ignore_missing:
40
+            errors.append('Could not open the undercloud.conf file at {}'
41
+                          .format(undercloud_conf_path))
42
+        return (False, errors)
43
+
44
+
45
+def get_result(undercloud_conf_path):
46
+    '''Get result from undercloud file'''
47
+
48
+    result = {}
49
+    errors = []
50
+
51
+    try:
52
+        config = ConfigParser.SafeConfigParser()
53
+        config.read(undercloud_conf_path)
54
+    except ConfigParser.MissingSectionHeaderError:
55
+        return (['File contains no section headers.'], {})
56
+    except ConfigParser.ParsingError:
57
+        return (['File contains parsing errors.'], {})
58
+
59
+    sections = ['DEFAULT'] + config.sections()
60
+    result = dict(((section, dict(config.items(section)))
61
+                   for section in sections))
62
+    return (errors, result)
63
+
64
+
23 65
 def main():
24 66
     module = AnsibleModule(argument_spec=dict(
25 67
         undercloud_conf_path=dict(required=True, type='str'),
@@ -27,24 +69,25 @@ def main():
27 69
     ))
28 70
 
29 71
     undercloud_conf_path = module.params.get('undercloud_conf_path')
72
+    ignore_missing = module.params.get('ignore_missing')
30 73
 
31
-    if path.exists(undercloud_conf_path) and path.isfile(undercloud_conf_path):
32
-        config = ConfigParser.SafeConfigParser()
33
-        config.read(undercloud_conf_path)
74
+    # Check arguments
75
+    file_exists, errors = check_arguments(undercloud_conf_path, ignore_missing)
34 76
 
35
-        sections = ['DEFAULT'] + config.sections()
36
-        result = dict(((section, dict(config.items(section)))
37
-                       for section in sections))
77
+    if errors:
78
+        module.fail_json(msg='\n'.join(errors))
79
+    elif file_exists:
80
+        # Get result
81
+        errors, result = get_result(undercloud_conf_path)
38 82
 
39
-        module.exit_json(changed=False,
40
-                         ansible_facts={u'undercloud_conf': result})
41
-    elif module.params.get('ignore_missing'):
83
+        if errors:
84
+            module.fail_json(msg='\n'.join(errors))
85
+        else:
86
+            module.exit_json(changed=False,
87
+                             ansible_facts={u'undercloud_conf': result})
88
+    else:
42 89
         module.exit_json(changed=False,
43 90
                          ansible_facts={u'undercloud_conf': {'DEFAULT': {}}})
44
-    else:
45
-        module.fail_json(msg="Could not open the undercloud.conf file at '%s'"
46
-                         % undercloud_conf_path)
47
-
48 91
 
49 92
 if __name__ == '__main__':
50 93
     main()

Loading…
Cancel
Save