Browse Source

Merge "Add test for packages structure"

Jenkins 2 years ago
parent
commit
6dcb389223
3 changed files with 198 additions and 71 deletions
  1. 12
    0
      unittests/base.py
  2. 0
    71
      unittests/test_namespaces.py
  3. 186
    0
      unittests/test_packages.py

+ 12
- 0
unittests/base.py View File

@@ -0,0 +1,12 @@
1
+import os
2
+
3
+import testtools
4
+
5
+
6
+class UnittestBaseCiCd(testtools.TestCase):
7
+
8
+    def setUp(self):
9
+        super(UnittestBaseCiCd, self).setUp()
10
+        # TODO: should be fixed future with some common approach for all tests
11
+        root_dir = os.path.dirname(os.path.abspath(__file__)).rsplit('/', 1)[0]
12
+        self.apps_dir = os.path.join(root_dir, 'murano-apps')

+ 0
- 71
unittests/test_namespaces.py View File

@@ -1,71 +0,0 @@
1
-import os
2
-import re
3
-import yaml
4
-
5
-import testtools
6
-
7
-
8
-class TestNamespaces(testtools.TestCase):
9
-    def get_list_of_classes(self):
10
-        # TODO: should be fixed future with some common approach for all tests
11
-        root_dir = os.path.dirname(os.path.abspath(__file__)).rsplit('/', 1)[0]
12
-        apps_dir = os.path.join(root_dir, 'murano-apps')
13
-        class_names = []
14
-
15
-        for path, dirs, files in os.walk(apps_dir):
16
-            if path.endswith('Classes'):
17
-                names = [os.path.join(path, f)
18
-                         for f in files if f.endswith('.yaml')]
19
-                class_names.extend(names)
20
-        return class_names
21
-
22
-    def get_namespaces(self, cls_name):
23
-        # workaround for PyYAML bug: http://pyyaml.org/ticket/221
24
-        ###############################
25
-        class YaqlYamlLoader(yaml.Loader):
26
-                pass
27
-
28
-        def yaql_constructor(loader, node):
29
-            return
30
-
31
-        YaqlYamlLoader.add_constructor(u'!yaql', yaql_constructor)
32
-        ###############################
33
-
34
-        # parse file
35
-        parsed_data = ''
36
-        with open(cls_name) as f:
37
-            parsed_data = yaml.load(f, YaqlYamlLoader)
38
-
39
-        n_spaces = parsed_data.get('Namespaces')
40
-        if n_spaces is None:
41
-            msg = 'File "%s" does not content "Namespaces" section' % cls_name
42
-            raise ValueError(msg)
43
-        # get only names of namespaces
44
-        names = n_spaces.keys()
45
-        # remove main namespace from the list
46
-        names.remove('=')
47
-        return names
48
-
49
-    def check_name(self, namespace, cls_name, error_list):
50
-        # read file
51
-        data = ''
52
-        with open(cls_name) as f:
53
-            data = f.read()
54
-
55
-        regexp_str = '[^a-zA-Z]%s:[a-zA-Z]+' % namespace
56
-        regexp = re.compile(regexp_str)
57
-        if len(regexp.findall(data)) == 0:
58
-            msg = ('Namespace "%s" is not used in the "%s" and should '
59
-                   'be removed from list of Namespaces' % (namespace, cls_name))
60
-            error_list.append(msg)
61
-
62
-    def test_namespaces(self):
63
-        error_list = []
64
-        for cls_name in self.get_list_of_classes():
65
-            for ns in self.get_namespaces(cls_name):
66
-                self.check_name(ns, cls_name, error_list)
67
-
68
-        error_string = "\n".join(error_list)
69
-        msg = "Test detects follow list of errors: \n%s" % error_string
70
-
71
-        self.assertEqual(0, len(error_list), msg)

+ 186
- 0
unittests/test_packages.py View File

@@ -0,0 +1,186 @@
1
+import os
2
+import re
3
+import yaml
4
+
5
+import base
6
+
7
+
8
+class TestNamespaces(base.UnittestBaseCiCd):
9
+
10
+    def get_list_of_classes(self):
11
+        class_names = []
12
+
13
+        for path, dirs, files in os.walk(self.apps_dir):
14
+            if path.endswith('Classes'):
15
+                names = [os.path.join(path, f)
16
+                         for f in files if f.endswith('.yaml')]
17
+                class_names.extend(names)
18
+        return class_names
19
+
20
+    def get_namespaces(self, cls_name):
21
+        # workaround for PyYAML bug: http://pyyaml.org/ticket/221
22
+        ###############################
23
+        class YaqlYamlLoader(yaml.Loader):
24
+                pass
25
+
26
+        def yaql_constructor(loader, node):
27
+            return
28
+
29
+        YaqlYamlLoader.add_constructor(u'!yaql', yaql_constructor)
30
+        ###############################
31
+
32
+        # parse file
33
+        parsed_data = ''
34
+        with open(cls_name) as f:
35
+            parsed_data = yaml.load(f, YaqlYamlLoader)
36
+
37
+        n_spaces = parsed_data.get('Namespaces')
38
+        if n_spaces is None:
39
+            msg = 'File "%s" does not content "Namespaces" section' % cls_name
40
+            raise ValueError(msg)
41
+        # get only names of namespaces
42
+        names = n_spaces.keys()
43
+        # remove main namespace from the list
44
+        names.remove('=')
45
+        return names
46
+
47
+    def check_name(self, namespace, cls_name, error_list):
48
+        # read file
49
+        data = ''
50
+        with open(cls_name) as f:
51
+            data = f.read()
52
+
53
+        regexp_str = '[^a-zA-Z]%s:[a-zA-Z]+' % namespace
54
+        regexp = re.compile(regexp_str)
55
+        if len(regexp.findall(data)) == 0:
56
+            msg = ('Namespace "%s" is not used in the "%s" and should '
57
+                   'be removed from list of Namespaces' % (namespace, cls_name))
58
+            error_list.append(msg)
59
+
60
+    def test_namespaces(self):
61
+        error_list = []
62
+        for cls_name in self.get_list_of_classes():
63
+            for ns in self.get_namespaces(cls_name):
64
+                self.check_name(ns, cls_name, error_list)
65
+
66
+        error_string = "\n".join(error_list)
67
+        msg = "Test detects follow list of errors: \n%s" % error_string
68
+
69
+        self.assertEqual(0, len(error_list), msg)
70
+
71
+
72
+class TestPackageStructure(base.UnittestBaseCiCd):
73
+    '''
74
+    Basic package can be described as example below,
75
+    but for test purposes will be used structure similar on output
76
+    for os.walk:
77
+
78
+    class Content(object):
79
+        def __init__(self, dirs=None, files=None):
80
+            self.dirs = dirs
81
+            self.files = files
82
+
83
+    package_structure = Content(
84
+        files=[], dirs={'package':
85
+           Content(dirs={'Classes': Content(dirs=[],
86
+                                            files=['*.yaml']),
87
+                         'Resources': Content(dirs={'scripts': Content()},
88
+                                              files=['*.template']),
89
+                         'UI': Content(dirs=[],
90
+                                       files=['ui.yaml'])
91
+                        },
92
+                   files=['manifest.yaml',
93
+                          'logo.png',
94
+                          'LICENSE'
95
+                         ]
96
+                    )
97
+            }
98
+    )
99
+    '''
100
+    package_structure = {
101
+        '': {
102
+            'files': [],
103
+            'dirs': ['package']},
104
+        'package': {
105
+            'files': ['manifest.yaml', 'logo.png', 'LICENSE',
106
+                      re.compile('\w*.lst')],
107
+            'dirs': ['Classes', 'Resources', 'UI']},
108
+        'package/Classes': {
109
+            'files': [re.compile('\w*.yaml')],
110
+            'dirs': None},
111
+        'package/Resources': {
112
+            'files': [re.compile('\w*.template'), re.compile('.*')],
113
+            'dirs': ['scripts']},
114
+        'package/Resources/scripts': {
115
+            # None means, that there are no any requirements for this value
116
+            'files': None,
117
+            'dirs': None},
118
+        'package/UI': {
119
+            'files': ['ui.yaml'],
120
+            'dirs': []},
121
+    }
122
+
123
+    def find_incorrect_items(self, expected, real, errors):
124
+        if expected is None:
125
+            return
126
+        real_set = set(real)
127
+        for val in expected:
128
+            try:
129
+                matches = filter(val.match, real_set)
130
+            except AttributeError:
131
+                # it's not a pattern and we just need to check,
132
+                # that it's in list
133
+                if val in real_set:
134
+                    real_set.remove(val)
135
+            else:
136
+                # remove matches from real_set
137
+                real_set -= set(matches)
138
+
139
+        if real_set:
140
+            return real_set
141
+
142
+    def show_patterns_in_error(self, expected):
143
+        output = []
144
+        for val in expected:
145
+            try:
146
+                output.append(val.pattern)
147
+            except AttributeError:
148
+                output.append(val)
149
+        return output
150
+
151
+    def check_package_tree(self, package_name):
152
+        errors = []
153
+        base_path = os.path.join(self.apps_dir, package_name)
154
+        for path, dirs, files in os.walk(base_path, topdown=True):
155
+            # remove with backslash symbol '/'
156
+            internal_path = path[len(base_path)+1:]
157
+            if internal_path not in self.package_structure:
158
+                continue
159
+            p_files = self.package_structure[internal_path]['files']
160
+            p_dirs = self.package_structure[internal_path]['dirs']
161
+            wrong_files = self.find_incorrect_items(p_files, files, errors)
162
+            if wrong_files:
163
+                allowed_vals = self.show_patterns_in_error(p_files)
164
+                msg = ('Path: "%s" contains wrong files: %s. Allowed values '
165
+                       'are: %s ' % (path, str(wrong_files), allowed_vals))
166
+                errors.append(msg)
167
+
168
+            wrong_dirs = self.find_incorrect_items(p_dirs, dirs, errors)
169
+            if wrong_dirs:
170
+                allowed_vals = self.show_patterns_in_error(p_dirs)
171
+                msg = ('Path: "%s" contains wrong dirs: %s. Allowed values '
172
+                       'are: %s ' % (path, str(wrong_dirs), allowed_vals))
173
+                errors.append(msg)
174
+
175
+        return errors
176
+
177
+    def test_packages(self):
178
+        error_list = []
179
+        packages = os.listdir(self.apps_dir)
180
+        for package in packages:
181
+            error_list.extend(self.check_package_tree(package))
182
+
183
+        error_string = "\n".join(error_list)
184
+        msg = "Test detects follow list of errors: \n%s" % error_string
185
+
186
+        self.assertEqual(0, len(error_list), msg)

Loading…
Cancel
Save