blob: 39bf7cbbc34659022bbb4e369fa50353bb367a2a [file] [log] [blame]
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +01001import os
2import subprocess
3import yaml
4from argparse import ArgumentParser
Milosz Wasilewskib5045412016-12-07 11:27:10 +00005from csv import DictWriter
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +01006from jinja2 import Environment, FileSystemLoader
7
8
9def render(obj, template="testplan.html", name=None):
10 if name is None:
11 name = template
12 _env = Environment(loader=FileSystemLoader('templates'))
13 _template = _env.get_template(template)
14 _obj = _template.render(obj=obj)
15 with open("{}".format(name), "wb") as _file:
16 _file.write(_obj.encode('utf-8'))
17
18
19# get list of repositories and cache them
20def repository_list(testplan):
21 repositories = set()
Milosz Wasilewskid5e1dd92018-02-12 12:08:44 +000022 tp_version = testplan['metadata']['format']
23 if tp_version == "Linaro Test Plan v2":
24 if 'manual' in testplan['tests'].keys() and testplan['tests']['manual'] is not None:
25 for test in testplan['tests']['manual']:
26 repositories.add(test['repository'])
27
28 if 'automated' in testplan['tests'].keys() and testplan['tests']['automated'] is not None:
29 for test in testplan['tests']['automated']:
30 repositories.add(test['repository'])
31 if tp_version == "Linaro Test Plan v1":
32 for req in testplan['requirements']:
33 if 'tests' in req.keys() and req['tests'] is not None:
34 if 'manual' in req['tests'].keys() and req['tests']['manual'] is not None:
35 for test in req['tests']['manual']:
36 repositories.add(test['repository'])
37 if 'automated' in req['tests'].keys() and req['tests']['automated'] is not None:
38 for test in req['tests']['automated']:
39 repositories.add(test['repository'])
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +010040 return repositories
41
42
43def clone_repository(repository_url, base_path, ignore=False):
44 path_suffix = repository_url.rsplit("/", 1)[1]
45 if path_suffix.endswith(".git"):
46 path_suffix = path_suffix[:-4]
47
Milosz Wasilewskib5045412016-12-07 11:27:10 +000048 path = os.path.abspath(os.path.join(base_path, path_suffix))
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +010049 if os.path.exists(path) and ignore:
50 return(repository_url, path)
51 # git clone repository_url
52 subprocess.call(['git', 'clone', repository_url, path])
53 # return tuple (repository_url, system_path)
54 return (repository_url, path)
55
56
Milosz Wasilewskib5045412016-12-07 11:27:10 +000057def test_exists(test, repositories, args):
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +010058 test_file_path = os.path.join(
59 repositories[test['repository']],
60 test['path']
61 )
62 current_dir = os.getcwd()
63 print current_dir
64 os.chdir(repositories[test['repository']])
65 if 'revision' in test.keys():
66 subprocess.call(['git', 'checkout', test['revision']])
67 else:
68 # if no revision is specified, use current HEAD
69 output = subprocess.check_output(['git', 'rev-parse', 'HEAD'])
70 test['revision'] = output
71
72 if not os.path.exists(test_file_path) or not os.path.isfile(test_file_path):
73 test['missing'] = True
74 os.chdir(current_dir)
75 return not test['missing']
76 test['missing'] = False
77 # open the file and render the test
78 subprocess.call(['git', 'checkout', 'master'])
79 print current_dir
80 os.chdir(current_dir)
81 print os.getcwd()
82 test_file = open(test_file_path, "r")
83 test_yaml = yaml.load(test_file.read())
84 params_string = ""
85 if 'parameters' in test.keys():
86 params_string = "_".join(["{0}-{1}".format(param_name, param_value).replace("/", "").replace(" ", "") for param_name, param_value in test['parameters'].iteritems()])
87 test_yaml['params'].update(test['parameters'])
88 print params_string
89 test_name = "{0}_{1}.html".format(test_yaml['metadata']['name'], params_string)
90 test['filename'] = test_name
Milosz Wasilewskib5045412016-12-07 11:27:10 +000091 test_path = os.path.join(os.path.abspath(args.output), test_name)
92 render(test_yaml, template="test.html", name=test_path)
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +010093 return not test['missing']
94
95
Milosz Wasilewskib5045412016-12-07 11:27:10 +000096def add_csv_row(requirement, test, args, manual=False):
97 fieldnames = [
98 "req_name",
99 "req_owner",
100 "req_category",
101 "path",
102 "repository",
103 "revision",
104 "parameters",
105 "mandatory",
106 "kind",
107 ]
108 csv_file_path = os.path.join(os.path.abspath(args.output), args.csv_name)
109 has_header = False
110 if os.path.isfile(csv_file_path):
111 has_header = True
112 with open(csv_file_path, "ab+") as csv_file:
113 csvdict = DictWriter(csv_file, fieldnames=fieldnames)
114 if not has_header:
115 csvdict.writeheader()
116 csvdict.writerow(
117 {
118 "req_name": requirement.get('name'),
119 "req_owner": requirement.get('owner'),
120 "req_category": requirement.get('category'),
121 "path": test.get('path'),
122 "repository": test.get('repository'),
123 "revision": test.get('revision'),
124 "parameters": test.get('parameters'),
125 "mandatory": test.get('mandatory'),
126 "kind": "manual" if manual else "automated",
127 }
128 )
129
130
131def check_coverage(requirement, repositories, args):
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100132 requirement['covered'] = False
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000133 if 'tests' not in requirement.keys() or requirement['tests'] is None:
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100134 return
135 if 'manual' in requirement['tests'].keys() and requirement['tests']['manual'] is not None:
136 for test in requirement['tests']['manual']:
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000137 if test_exists(test, repositories, args):
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100138 requirement['covered'] = True
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000139 if args.csv_name:
140 add_csv_row(requirement, test, args, True)
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100141 if 'automated' in requirement['tests'].keys() and requirement['tests']['automated'] is not None:
142 for test in requirement['tests']['automated']:
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000143 if test_exists(test, repositories, args):
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100144 requirement['covered'] = True
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000145 if args.csv_name:
146 add_csv_row(requirement, test, args)
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100147
148
149def main():
150 parser = ArgumentParser()
151 parser.add_argument("-f",
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000152 "--file",
153 dest="testplan_list",
154 required=True,
155 nargs="+",
156 help="Test plan file to be used")
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100157 parser.add_argument("-r",
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000158 "--repositories",
159 dest="repository_path",
160 default="repositories",
161 help="Test plan file to be used")
162 parser.add_argument("-o",
163 "--output",
164 dest="output",
165 default="output",
166 help="Destination directory for generated files")
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100167 parser.add_argument("-i",
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000168 "--ignore-clone",
169 dest="ignore_clone",
170 action="store_true",
171 default=False,
172 help="Ignore cloning repositories and use previously cloned")
173 parser.add_argument("-c",
174 "--csv",
175 dest="csv_name",
176 required=False,
177 help="Name of CSV to store overall list of requirements and test. If name is absent, the file will not be generated")
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100178
179 args = parser.parse_args()
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000180 if not os.path.exists(os.path.abspath(args.output)):
181 os.makedirs(os.path.abspath(args.output), 0755)
182 for testplan in args.testplan_list:
183 if os.path.exists(testplan) and os.path.isfile(testplan):
184 testplan_file = open(testplan, "r")
185 tp_obj = yaml.load(testplan_file.read())
186 repo_list = repository_list(tp_obj)
187 repositories = {}
188 for repo in repo_list:
189 repo_url, repo_path = clone_repository(repo, args.repository_path, args.ignore_clone)
190 repositories.update({repo_url: repo_path})
191 # ToDo: check test plan structure
Milosz Wasilewskid5e1dd92018-02-12 12:08:44 +0000192
193 tp_version = tp_obj['metadata']['format']
194 if tp_version == "Linaro Test Plan v1":
195 for requirement in tp_obj['requirements']:
196 check_coverage(requirement, repositories, args)
197 if tp_version == "Linaro Test Plan v2":
198 if 'manual' in tp_obj['tests'].keys() and tp_obj['tests']['manual'] is not None:
199 for test in tp_obj['tests']['manual']:
200 test_exists(test, repositories, args)
201 if 'automated' in tp_obj['tests'].keys() and tp_obj['tests']['automated'] is not None:
202 for test in tp_obj['tests']['automated']:
203 test_exists(test, repositories, args)
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000204 tp_name = tp_obj['metadata']['name'] + ".html"
205 tp_file_name = os.path.join(os.path.abspath(args.output), tp_name)
Milosz Wasilewskid5e1dd92018-02-12 12:08:44 +0000206 if tp_version == "Linaro Test Plan v1":
207 render(tp_obj, name=tp_file_name)
208 if tp_version == "Linaro Test Plan v2":
209 render(tp_obj, name=tp_file_name, template="testplan_v2.html")
Milosz Wasilewskib5045412016-12-07 11:27:10 +0000210 testplan_file.close()
Milosz Wasilewskif5ccdbd2016-10-25 18:49:20 +0100211# go through requiremets and for each test:
212# - if file exists render test as separate html file
213# - if file is missing, indicate missing test (red)
214# render test plan with links to test files
215# add option to render as single file (for pdf generation)
216
217if __name__ == "__main__":
218 main()