Add test for packages structure
Change-Id: I1f9cd14f41edc9f825d86c4867426a9805af2882
This commit is contained in:
parent
9281f08b3e
commit
a2cfd49689
12
unittests/base.py
Normal file
12
unittests/base.py
Normal 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')
|
@ -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
186
unittests/test_packages.py
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user