summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-08-08 20:13:44 +0000
committerGerrit Code Review <review@openstack.org>2016-08-08 20:13:44 +0000
commit6dcb389223256f5c516311044d510b3947d1094c (patch)
tree042c6eaa1a281270db45b18f873b0e5770ea8da0
parent6cb8f9d518f6df70885ce9c95b1464f576577276 (diff)
parenta2cfd4968989fbac4e247c7758ed9cf25e6fc1ef (diff)
Merge "Add test for packages structure"
-rw-r--r--unittests/base.py12
-rw-r--r--unittests/test_namespaces.py71
-rw-r--r--unittests/test_packages.py186
3 files changed, 198 insertions, 71 deletions
diff --git a/unittests/base.py b/unittests/base.py
new file mode 100644
index 0000000..4e2d90c
--- /dev/null
+++ b/unittests/base.py
@@ -0,0 +1,12 @@
1import os
2
3import testtools
4
5
6class 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')
diff --git a/unittests/test_namespaces.py b/unittests/test_namespaces.py
deleted file mode 100644
index 2f03f49..0000000
--- a/unittests/test_namespaces.py
+++ /dev/null
@@ -1,71 +0,0 @@
1import os
2import re
3import yaml
4
5import testtools
6
7
8class 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)
diff --git a/unittests/test_packages.py b/unittests/test_packages.py
new file mode 100644
index 0000000..c0486e4
--- /dev/null
+++ b/unittests/test_packages.py
@@ -0,0 +1,186 @@
1import os
2import re
3import yaml
4
5import base
6
7
8class 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
72class 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)