Merge "Add test for packages structure"

This commit is contained in:
Jenkins 2016-08-08 20:13:44 +00:00 committed by Gerrit Code Review
commit 6dcb389223
3 changed files with 198 additions and 71 deletions

12
unittests/base.py Normal file
View File

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

View File

@ -1,71 +0,0 @@
import os
import re
import yaml
import testtools
class TestNamespaces(testtools.TestCase):
def get_list_of_classes(self):
# TODO: should be fixed future with some common approach for all tests
root_dir = os.path.dirname(os.path.abspath(__file__)).rsplit('/', 1)[0]
apps_dir = os.path.join(root_dir, 'murano-apps')
class_names = []
for path, dirs, files in os.walk(apps_dir):
if path.endswith('Classes'):
names = [os.path.join(path, f)
for f in files if f.endswith('.yaml')]
class_names.extend(names)
return class_names
def get_namespaces(self, cls_name):
# workaround for PyYAML bug: http://pyyaml.org/ticket/221
###############################
class YaqlYamlLoader(yaml.Loader):
pass
def yaql_constructor(loader, node):
return
YaqlYamlLoader.add_constructor(u'!yaql', yaql_constructor)
###############################
# parse file
parsed_data = ''
with open(cls_name) as f:
parsed_data = yaml.load(f, YaqlYamlLoader)
n_spaces = parsed_data.get('Namespaces')
if n_spaces is None:
msg = 'File "%s" does not content "Namespaces" section' % cls_name
raise ValueError(msg)
# get only names of namespaces
names = n_spaces.keys()
# remove main namespace from the list
names.remove('=')
return names
def check_name(self, namespace, cls_name, error_list):
# read file
data = ''
with open(cls_name) as f:
data = f.read()
regexp_str = '[^a-zA-Z]%s:[a-zA-Z]+' % namespace
regexp = re.compile(regexp_str)
if len(regexp.findall(data)) == 0:
msg = ('Namespace "%s" is not used in the "%s" and should '
'be removed from list of Namespaces' % (namespace, cls_name))
error_list.append(msg)
def test_namespaces(self):
error_list = []
for cls_name in self.get_list_of_classes():
for ns in self.get_namespaces(cls_name):
self.check_name(ns, cls_name, error_list)
error_string = "\n".join(error_list)
msg = "Test detects follow list of errors: \n%s" % error_string
self.assertEqual(0, len(error_list), msg)

186
unittests/test_packages.py Normal file
View File

@ -0,0 +1,186 @@
import os
import re
import yaml
import base
class TestNamespaces(base.UnittestBaseCiCd):
def get_list_of_classes(self):
class_names = []
for path, dirs, files in os.walk(self.apps_dir):
if path.endswith('Classes'):
names = [os.path.join(path, f)
for f in files if f.endswith('.yaml')]
class_names.extend(names)
return class_names
def get_namespaces(self, cls_name):
# workaround for PyYAML bug: http://pyyaml.org/ticket/221
###############################
class YaqlYamlLoader(yaml.Loader):
pass
def yaql_constructor(loader, node):
return
YaqlYamlLoader.add_constructor(u'!yaql', yaql_constructor)
###############################
# parse file
parsed_data = ''
with open(cls_name) as f:
parsed_data = yaml.load(f, YaqlYamlLoader)
n_spaces = parsed_data.get('Namespaces')
if n_spaces is None:
msg = 'File "%s" does not content "Namespaces" section' % cls_name
raise ValueError(msg)
# get only names of namespaces
names = n_spaces.keys()
# remove main namespace from the list
names.remove('=')
return names
def check_name(self, namespace, cls_name, error_list):
# read file
data = ''
with open(cls_name) as f:
data = f.read()
regexp_str = '[^a-zA-Z]%s:[a-zA-Z]+' % namespace
regexp = re.compile(regexp_str)
if len(regexp.findall(data)) == 0:
msg = ('Namespace "%s" is not used in the "%s" and should '
'be removed from list of Namespaces' % (namespace, cls_name))
error_list.append(msg)
def test_namespaces(self):
error_list = []
for cls_name in self.get_list_of_classes():
for ns in self.get_namespaces(cls_name):
self.check_name(ns, cls_name, error_list)
error_string = "\n".join(error_list)
msg = "Test detects follow list of errors: \n%s" % error_string
self.assertEqual(0, len(error_list), msg)
class TestPackageStructure(base.UnittestBaseCiCd):
'''
Basic package can be described as example below,
but for test purposes will be used structure similar on output
for os.walk:
class Content(object):
def __init__(self, dirs=None, files=None):
self.dirs = dirs
self.files = files
package_structure = Content(
files=[], dirs={'package':
Content(dirs={'Classes': Content(dirs=[],
files=['*.yaml']),
'Resources': Content(dirs={'scripts': Content()},
files=['*.template']),
'UI': Content(dirs=[],
files=['ui.yaml'])
},
files=['manifest.yaml',
'logo.png',
'LICENSE'
]
)
}
)
'''
package_structure = {
'': {
'files': [],
'dirs': ['package']},
'package': {
'files': ['manifest.yaml', 'logo.png', 'LICENSE',
re.compile('\w*.lst')],
'dirs': ['Classes', 'Resources', 'UI']},
'package/Classes': {
'files': [re.compile('\w*.yaml')],
'dirs': None},
'package/Resources': {
'files': [re.compile('\w*.template'), re.compile('.*')],
'dirs': ['scripts']},
'package/Resources/scripts': {
# None means, that there are no any requirements for this value
'files': None,
'dirs': None},
'package/UI': {
'files': ['ui.yaml'],
'dirs': []},
}
def find_incorrect_items(self, expected, real, errors):
if expected is None:
return
real_set = set(real)
for val in expected:
try:
matches = filter(val.match, real_set)
except AttributeError:
# it's not a pattern and we just need to check,
# that it's in list
if val in real_set:
real_set.remove(val)
else:
# remove matches from real_set
real_set -= set(matches)
if real_set:
return real_set
def show_patterns_in_error(self, expected):
output = []
for val in expected:
try:
output.append(val.pattern)
except AttributeError:
output.append(val)
return output
def check_package_tree(self, package_name):
errors = []
base_path = os.path.join(self.apps_dir, package_name)
for path, dirs, files in os.walk(base_path, topdown=True):
# remove with backslash symbol '/'
internal_path = path[len(base_path)+1:]
if internal_path not in self.package_structure:
continue
p_files = self.package_structure[internal_path]['files']
p_dirs = self.package_structure[internal_path]['dirs']
wrong_files = self.find_incorrect_items(p_files, files, errors)
if wrong_files:
allowed_vals = self.show_patterns_in_error(p_files)
msg = ('Path: "%s" contains wrong files: %s. Allowed values '
'are: %s ' % (path, str(wrong_files), allowed_vals))
errors.append(msg)
wrong_dirs = self.find_incorrect_items(p_dirs, dirs, errors)
if wrong_dirs:
allowed_vals = self.show_patterns_in_error(p_dirs)
msg = ('Path: "%s" contains wrong dirs: %s. Allowed values '
'are: %s ' % (path, str(wrong_dirs), allowed_vals))
errors.append(msg)
return errors
def test_packages(self):
error_list = []
packages = os.listdir(self.apps_dir)
for package in packages:
error_list.extend(self.check_package_tree(package))
error_string = "\n".join(error_list)
msg = "Test detects follow list of errors: \n%s" % error_string
self.assertEqual(0, len(error_list), msg)