|
@@ -0,0 +1,466 @@
|
|
1
|
+#!/usr/bin/env python
|
|
2
|
+# -*- coding: utf-8 -*-
|
|
3
|
+#
|
|
4
|
+import fstools
|
|
5
|
+import report
|
|
6
|
+import reqif
|
|
7
|
+
|
|
8
|
+import json
|
|
9
|
+import os
|
|
10
|
+import platform
|
|
11
|
+import getpass
|
|
12
|
+import sys
|
|
13
|
+import subprocess
|
|
14
|
+import imp
|
|
15
|
+import xml.dom.minidom
|
|
16
|
+try:
|
|
17
|
+ import jinja2
|
|
18
|
+except ImportError:
|
|
19
|
+ jinja2 = None
|
|
20
|
+import shutil
|
|
21
|
+
|
|
22
|
+HEADER = '\033[95m'
|
|
23
|
+OKBLUE = '\033[94m'
|
|
24
|
+OKGREEN = '\033[92m'
|
|
25
|
+WARNING = '\033[93m'
|
|
26
|
+FAIL = '\033[91m'
|
|
27
|
+ENDC = '\033[0m'
|
|
28
|
+BOLD = '\033[1m'
|
|
29
|
+UNDERLINE = '\033[4m'
|
|
30
|
+
|
|
31
|
+ARG_CLEAN = 'clean'
|
|
32
|
+ARG_RUN = 'run'
|
|
33
|
+ARG_FINALISE = 'finalise'
|
|
34
|
+ARG_PDF = 'pdf'
|
|
35
|
+ARG_STATUS = 'status'
|
|
36
|
+ARG_COPY = 'copy'
|
|
37
|
+ARG_RELEASE = 'release'
|
|
38
|
+
|
|
39
|
+UNITTEST_KEY_SYSTEM_INFO = 'system_information'
|
|
40
|
+UNITTEST_KEY_UNITTEST_INFO = 'unittest_information'
|
|
41
|
+UNITTEST_KEY_TESTOBJECT_INFO = 'testobject_information'
|
|
42
|
+UNITTEST_KEY_TESTRUNS = 'testrun_list'
|
|
43
|
+UNITTEST_KEY_COVERAGE_INFO = 'coverage_information'
|
|
44
|
+UNITTEST_KEY_SPECIFICATION = 'specification'
|
|
45
|
+
|
|
46
|
+FILES = {
|
|
47
|
+ 'data-collection': 'unittest.json',
|
|
48
|
+ 'tex-report': 'unittest.tex',
|
|
49
|
+ 'coverage-xml': 'coverage.xml'
|
|
50
|
+}
|
|
51
|
+
|
|
52
|
+REPORT_FILES = [FILES['data-collection'], FILES['coverage-xml'], 'unittest.pdf']
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+class coverage_info(list):
|
|
56
|
+ KEY_NAME = 'name'
|
|
57
|
+ KEY_FILEPATH = 'filepath'
|
|
58
|
+ KEY_LINE_COVERAGE = 'line_coverage'
|
|
59
|
+ KEY_BRANCH_COVERAGE = 'branch_coverage'
|
|
60
|
+ KEY_FILES = 'files'
|
|
61
|
+ KEY_FRAGMENTS = 'fragments'
|
|
62
|
+ KEY_START_LINE = 'start'
|
|
63
|
+ KEY_END_LINE = 'end'
|
|
64
|
+ KEY_COVERAGE_STATE = 'coverage_state'
|
|
65
|
+ COVERED = 'covered'
|
|
66
|
+ UNCOVERED = 'uncovered'
|
|
67
|
+ CLEAN = 'clean'
|
|
68
|
+ PARTIALLY_COVERED = 'partially-covered'
|
|
69
|
+
|
|
70
|
+ def __init__(self, xml_filename, module_basepath):
|
|
71
|
+ list.__init__(self)
|
|
72
|
+ xmldoc = xml.dom.minidom.parse(xml_filename)
|
|
73
|
+ itemlist = xmldoc.getElementsByTagName('package')
|
|
74
|
+ for p in itemlist:
|
|
75
|
+ module = {}
|
|
76
|
+ module[self.KEY_NAME] = p.attributes['name'].value[len(module_basepath) + 1:]
|
|
77
|
+ module[self.KEY_FILEPATH] = p.attributes['name'].value.replace('.', os.path.sep)
|
|
78
|
+ module[self.KEY_LINE_COVERAGE] = float(p.attributes['line-rate'].value) * 100.
|
|
79
|
+ try:
|
|
80
|
+ module[self.KEY_BRANCH_COVERAGE] = float(p.attributes['branch-rate'].value) * 100.
|
|
81
|
+ except AttributeError:
|
|
82
|
+ module[self.KEY_BRANCH_COVERAGE] = None
|
|
83
|
+ module[self.KEY_FILES] = []
|
|
84
|
+ for c in p.getElementsByTagName('class'):
|
|
85
|
+ f = {}
|
|
86
|
+ f[self.KEY_NAME] = c.attributes['filename'].value[len(module_basepath) + 1:].replace(os.path.sep, '.')
|
|
87
|
+ f[self.KEY_FILEPATH] = c.attributes['filename'].value
|
|
88
|
+ f[self.KEY_LINE_COVERAGE] = float(c.attributes['line-rate'].value) * 100.
|
|
89
|
+ try:
|
|
90
|
+ f[self.KEY_BRANCH_COVERAGE] = float(p.attributes['branch-rate'].value) * 100.
|
|
91
|
+ except:
|
|
92
|
+ f[self.KEY_BRANCH_COVERAGE] = None
|
|
93
|
+ f[self.KEY_FRAGMENTS] = []
|
|
94
|
+ last_hit = None
|
|
95
|
+ start_line = 1
|
|
96
|
+ end_line = 1
|
|
97
|
+ for line in c.getElementsByTagName('line'):
|
|
98
|
+ line_no = int(line.attributes['number'].value)
|
|
99
|
+ hit = bool(int(line.attributes['hits'].value))
|
|
100
|
+ if hit:
|
|
101
|
+ cc = line.attributes.get('condition-coverage')
|
|
102
|
+ if cc is not None and not cc.value.startswith('100%'):
|
|
103
|
+ hit = self.PARTIALLY_COVERED
|
|
104
|
+ else:
|
|
105
|
+ hit = self.COVERED
|
|
106
|
+ else:
|
|
107
|
+ hit = self.UNCOVERED
|
|
108
|
+ if line_no == 1:
|
|
109
|
+ last_hit = hit
|
|
110
|
+ elif last_hit != hit or line_no > end_line + 1:
|
|
111
|
+ if last_hit is not None:
|
|
112
|
+ line = {}
|
|
113
|
+ line[self.KEY_START_LINE] = start_line
|
|
114
|
+ line[self.KEY_END_LINE] = end_line
|
|
115
|
+ line[self.KEY_COVERAGE_STATE] = last_hit
|
|
116
|
+ f[self.KEY_FRAGMENTS].append(line)
|
|
117
|
+ if line_no > end_line + 1:
|
|
118
|
+ line = {}
|
|
119
|
+ if last_hit is not None:
|
|
120
|
+ line[self.KEY_START_LINE] = end_line + 1
|
|
121
|
+ else:
|
|
122
|
+ line[self.KEY_START_LINE] = start_line
|
|
123
|
+ line[self.KEY_END_LINE] = line_no - 1
|
|
124
|
+ line[self.KEY_COVERAGE_STATE] = self.CLEAN
|
|
125
|
+ f[self.KEY_FRAGMENTS].append(line)
|
|
126
|
+ start_line = line_no
|
|
127
|
+ end_line = line_no
|
|
128
|
+ last_hit = hit
|
|
129
|
+ elif line_no == end_line + 1:
|
|
130
|
+ end_line = line_no
|
|
131
|
+ if last_hit is not None:
|
|
132
|
+ line = {}
|
|
133
|
+ line[self.KEY_START_LINE] = start_line
|
|
134
|
+ line[self.KEY_END_LINE] = end_line
|
|
135
|
+ line[self.KEY_COVERAGE_STATE] = last_hit
|
|
136
|
+ f[self.KEY_FRAGMENTS].append(line)
|
|
137
|
+ line = {}
|
|
138
|
+ if last_hit is not None:
|
|
139
|
+ line[self.KEY_START_LINE] = end_line + 1
|
|
140
|
+ else:
|
|
141
|
+ line[self.KEY_START_LINE] = start_line
|
|
142
|
+ line[self.KEY_END_LINE] = None
|
|
143
|
+ line[self.KEY_COVERAGE_STATE] = self.CLEAN
|
|
144
|
+ f[self.KEY_FRAGMENTS].append(line)
|
|
145
|
+ module[self.KEY_FILES].append(f)
|
|
146
|
+ self.append(module)
|
|
147
|
+
|
|
148
|
+ def __str__(self):
|
|
149
|
+ rv = ''
|
|
150
|
+ for module in self:
|
|
151
|
+ rv += '%s (%.1f%% - %s)\n' % (module.get(self.KEY_NAME), module.get(self.KEY_LINE_COVERAGE), module.get(self.KEY_FILEPATH))
|
|
152
|
+ for py_file in module.get(self.KEY_FILES):
|
|
153
|
+ rv += ' %s (%.1f%% - %s)\n' % (py_file.get(self.KEY_NAME), py_file.get(self.KEY_LINE_COVERAGE), py_file.get(self.KEY_FILEPATH))
|
|
154
|
+ for fragment in py_file.get(self.KEY_FRAGMENTS):
|
|
155
|
+ if fragment.get(self.KEY_END_LINE) is not None:
|
|
156
|
+ rv += ' %d - %d: %s\n' % (fragment.get(self.KEY_START_LINE), fragment.get(self.KEY_END_LINE), repr(fragment.get(self.KEY_COVERAGE_STATE)))
|
|
157
|
+ else:
|
|
158
|
+ rv += ' %d - : %s\n' % (fragment.get(self.KEY_START_LINE), repr(fragment.get(self.KEY_COVERAGE_STATE)))
|
|
159
|
+ return rv
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+def unittest_filename(base_folder, filename):
|
|
163
|
+ return os.path.join(base_folder, 'testresults', filename)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+def print_header(txt, color=BOLD + WARNING):
|
|
167
|
+ print(color + txt + ENDC)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+def print_action(txt, color=BOLD):
|
|
171
|
+ print(color + ' * ' + txt + ENDC)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+def print_info(txt, color=ENDC):
|
|
175
|
+ print(' ' + color + txt + ENDC)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+def remove_file(filename):
|
|
179
|
+ if os.path.exists(filename) and not filename.endswith('.gitkeep'):
|
|
180
|
+ try:
|
|
181
|
+ print_info('Removing %s' % filename)
|
|
182
|
+ os.remove(filename)
|
|
183
|
+ except OSError:
|
|
184
|
+ pass
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+def module_uid(path):
|
|
188
|
+ return fstools.uid_filelist(path, '*.py', rekursive=True)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+def unittest(options, args, unittest_folder):
|
|
192
|
+ if ARG_CLEAN in args:
|
|
193
|
+ unittest_init(unittest_folder)
|
|
194
|
+ elif ARG_RUN in args:
|
|
195
|
+ unittest_run(unittest_folder, options)
|
|
196
|
+ elif ARG_FINALISE in args:
|
|
197
|
+ unittest_finalise(unittest_folder)
|
|
198
|
+ elif ARG_PDF in args:
|
|
199
|
+ unittest_pdf(unittest_folder)
|
|
200
|
+ elif ARG_STATUS in args:
|
|
201
|
+ unittest_status(unittest_folder)
|
|
202
|
+ elif ARG_COPY in args:
|
|
203
|
+ unittest_copy(unittest_folder)
|
|
204
|
+ elif ARG_RELEASE in args:
|
|
205
|
+ unittest_release(unittest_folder)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+def unittest_init(unittest_folder):
|
|
209
|
+ config = imp.load_source('', os.path.join(unittest_folder, 'src', 'config.py'))
|
|
210
|
+ #
|
|
211
|
+ print_header("Initiating unittest for first testrun...")
|
|
212
|
+ if not os.path.exists(unittest_filename(unittest_folder, '')):
|
|
213
|
+ print_action('Creating outpout folder %s' % unittest_filename(unittest_folder, ''))
|
|
214
|
+ fstools.mkdir(unittest_filename(unittest_folder, ''))
|
|
215
|
+ #
|
|
216
|
+ print_action('Cleaning up data from last testrun')
|
|
217
|
+ for fn in os.listdir(unittest_filename(unittest_folder, '')):
|
|
218
|
+ remove_file(unittest_filename(unittest_folder, fn))
|
|
219
|
+ remove_file(unittest_filename(unittest_folder, FILES['coverage-xml']))
|
|
220
|
+ #
|
|
221
|
+ print_action('Creating unittest data-collection: %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
222
|
+ #
|
|
223
|
+ system_info = {}
|
|
224
|
+ system_info['Architecture'] = platform.architecture()[0]
|
|
225
|
+ system_info['Machine'] = platform.machine()
|
|
226
|
+ system_info['Hostname'] = platform.node()
|
|
227
|
+ system_info['Distribution'] = ' '.join(platform.dist())
|
|
228
|
+ system_info['System'] = platform.system()
|
|
229
|
+ system_info['Kernel'] = platform.release() + ' (%s)' % platform.version()
|
|
230
|
+ system_info['Username'] = getpass.getuser()
|
|
231
|
+ system_info['Path'] = unittest_folder
|
|
232
|
+ #
|
|
233
|
+ unittest_info = {}
|
|
234
|
+ unittest_info['Version'] = module_uid(os.path.join(unittest_folder, 'src', 'tests'))
|
|
235
|
+ #
|
|
236
|
+ testobject_info = {}
|
|
237
|
+ testobject_info['Name'] = config.lib.__name__
|
|
238
|
+ testobject_info['Version'] = module_uid(config.lib.__path__[0])
|
|
239
|
+ testobject_info['Description'] = config.lib.__DESCRIPTION__
|
|
240
|
+ testobject_info['Supported Interpreters'] = ', '.join(['python%d' % vers for vers in config.lib.__INTERPRETER__])
|
|
241
|
+ testobject_info['State'] = 'Released' if config.release_unittest_version == module_uid(os.path.join(unittest_folder, 'src', 'tests')) else 'In development'
|
|
242
|
+ testobject_info['Dependencies'] = []
|
|
243
|
+ for dependency in config.lib.__DEPENDENCIES__:
|
|
244
|
+ testobject_info['Dependencies'].append((dependency, module_uid(os.path.join(unittest_folder, 'src', dependency))))
|
|
245
|
+ #
|
|
246
|
+ spec_filename = os.path.join(unittest_folder, '..', 'requirements', 'specification.reqif')
|
|
247
|
+ print_action("Adding Requirement Specification from %s" % spec_filename)
|
|
248
|
+ try:
|
|
249
|
+ spec = reqif.reqif_dict(spec_filename, 'Heading', 'Software Specification')
|
|
250
|
+ except FileNotFoundError:
|
|
251
|
+ print_info('FAILED', FAIL)
|
|
252
|
+ spec = {}
|
|
253
|
+ else:
|
|
254
|
+ print_info('SUCCESS', OKGREEN)
|
|
255
|
+ #
|
|
256
|
+ data_collection = {
|
|
257
|
+ UNITTEST_KEY_SYSTEM_INFO: system_info,
|
|
258
|
+ UNITTEST_KEY_UNITTEST_INFO: unittest_info,
|
|
259
|
+ UNITTEST_KEY_TESTOBJECT_INFO: testobject_info,
|
|
260
|
+ UNITTEST_KEY_SPECIFICATION: spec,
|
|
261
|
+ UNITTEST_KEY_TESTRUNS: [],
|
|
262
|
+ }
|
|
263
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'w') as fh:
|
|
264
|
+ fh.write(json.dumps(data_collection, indent=4, sort_keys=True))
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+def unittest_run(unittest_folder, options):
|
|
268
|
+ tests = imp.load_source('', os.path.join(unittest_folder, 'src', 'tests', '__init__.py'))
|
|
269
|
+ config = imp.load_source('', os.path.join(unittest_folder, 'src', 'config.py'))
|
|
270
|
+ #
|
|
271
|
+ interpreter_version = 'python ' + '.'.join(['%d' % n for n in sys.version_info[:3]]) + ' (%s)' % sys.version_info[3]
|
|
272
|
+ #
|
|
273
|
+ execution_level = report.TCEL_REVERSE_NAMED.get(options.execution_level, report.TCEL_FULL)
|
|
274
|
+ #
|
|
275
|
+ if sys.version_info.major in config.lib.__INTERPRETER__:
|
|
276
|
+ print_header("Running Unittest with %s" % interpreter_version)
|
|
277
|
+ print_action('Loading Testrun data from %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
278
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'r') as fh:
|
|
279
|
+ data_collection = json.loads(fh.read())
|
|
280
|
+ print_action('Executing Testcases')
|
|
281
|
+ heading_dict = {}
|
|
282
|
+ for key in data_collection[UNITTEST_KEY_SPECIFICATION].get('item_dict', {}):
|
|
283
|
+ heading_dict[key] = data_collection[UNITTEST_KEY_SPECIFICATION]['item_dict'][key]['Heading']
|
|
284
|
+ test_session = report.testSession(
|
|
285
|
+ ['__unittest__', config.lib.logger_name] + config.additional_loggers_to_catch,
|
|
286
|
+ interpreter=interpreter_version,
|
|
287
|
+ testcase_execution_level=execution_level,
|
|
288
|
+ testrun_id='p%d' % sys.version_info[0],
|
|
289
|
+ heading_dict=heading_dict
|
|
290
|
+ )
|
|
291
|
+ tests.testrun(test_session)
|
|
292
|
+ #
|
|
293
|
+ print_action('Adding Testrun data to %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
294
|
+ data_collection[UNITTEST_KEY_TESTRUNS].append(test_session)
|
|
295
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'w') as fh:
|
|
296
|
+ fh.write(json.dumps(data_collection, indent=4, sort_keys=True))
|
|
297
|
+ else:
|
|
298
|
+ print_header("Library does not support %s." % interpreter_version)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+def unittest_finalise(unittest_folder):
|
|
302
|
+ config = imp.load_source('', os.path.join(unittest_folder, 'src', 'config.py'))
|
|
303
|
+ #
|
|
304
|
+ print_action('Adding Testrun data to %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
305
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'r') as fh:
|
|
306
|
+ data_collection = json.loads(fh.read())
|
|
307
|
+ #
|
|
308
|
+ print_header("Adding Requirement information")
|
|
309
|
+ #
|
|
310
|
+ data_collection['lost_souls'] = {}
|
|
311
|
+ #
|
|
312
|
+ print_action("Adding Lost Requirement Soul")
|
|
313
|
+ data_collection['lost_souls']['item_list'] = []
|
|
314
|
+ for req_id in data_collection['specification'].get('item_dict', {}):
|
|
315
|
+ item = data_collection['specification']['item_dict'][req_id]
|
|
316
|
+ if item['system_type_uid'] == '_MR7eNHYYEem_kd-7nxt1sg':
|
|
317
|
+ testcase_available = False
|
|
318
|
+ for testrun in data_collection['testrun_list']:
|
|
319
|
+ if req_id in testrun['testcases']:
|
|
320
|
+ testcase_available = True
|
|
321
|
+ break
|
|
322
|
+ if not testcase_available:
|
|
323
|
+ data_collection['lost_souls']['item_list'].append(req_id)
|
|
324
|
+ print_info('%s - "%s" has no corresponding testcase' % (item['system_uid'], item['Heading']), FAIL)
|
|
325
|
+ #
|
|
326
|
+ print_action("Adding Lost Testcase Soul")
|
|
327
|
+ data_collection['lost_souls']['testcase_list'] = []
|
|
328
|
+ for testrun in data_collection['testrun_list']:
|
|
329
|
+ for tc_id in testrun.get('testcases', {}):
|
|
330
|
+ if tc_id not in data_collection['specification'].get('item_dict', {}) and tc_id not in data_collection['lost_souls']['testcase_list']:
|
|
331
|
+ data_collection['lost_souls']['testcase_list'].append(tc_id)
|
|
332
|
+ print_info('"%s" has no corresponding testcase' % tc_id, FAIL)
|
|
333
|
+ #
|
|
334
|
+ print_header("Adding Coverage information")
|
|
335
|
+ print_action('Adding Coverage Information to %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
336
|
+ data_collection[UNITTEST_KEY_COVERAGE_INFO] = coverage_info(unittest_filename(unittest_folder, 'coverage.xml'), os.path.dirname(config.lib_path))
|
|
337
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'w') as fh:
|
|
338
|
+ fh.write(json.dumps(data_collection, indent=4, sort_keys=True))
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+def unittest_pdf(unittest_folder):
|
|
342
|
+ print_header("Creating PDF-Report of Unittest")
|
|
343
|
+ print_action('Loading Testrun data from %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
344
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'r') as fh:
|
|
345
|
+ data_collection = json.loads(fh.read())
|
|
346
|
+
|
|
347
|
+ if jinja2 is None:
|
|
348
|
+ print_action('You need to install jinja2 to create a PDF-Report!', FAIL)
|
|
349
|
+ else:
|
|
350
|
+ fn = unittest_filename(unittest_folder, FILES['tex-report'])
|
|
351
|
+ print_action('Creating LaTeX-File %s' % fn)
|
|
352
|
+ with open(fn, 'w') as fh:
|
|
353
|
+ #
|
|
354
|
+ template_path = os.path.join(os.path.dirname(__file__), 'templates')
|
|
355
|
+ template_filename = 'unittest.tex'
|
|
356
|
+ jenv = jinja2.Environment(loader=jinja2.FileSystemLoader(template_path))
|
|
357
|
+ template = jenv.get_template(template_filename)
|
|
358
|
+ fh.write(template.render(data=data_collection))
|
|
359
|
+ print_action('Creating PDF %s' % unittest_filename(unittest_folder, 'unittest.pdf'))
|
|
360
|
+ for i in range(3):
|
|
361
|
+ sys.stdout.write(' Starting run %d/3 of pdflatex... ' % (i + 1))
|
|
362
|
+ sys.stdout.flush()
|
|
363
|
+ exit_value = os.system("pdflatex -interaction nonstopmode --output-directory %(path)s %(path)s/unittest.tex 1> /dev/null" % {'path': unittest_filename(unittest_folder, '')})
|
|
364
|
+ if exit_value != 0:
|
|
365
|
+ print(FAIL + 'FAILED' + ENDC)
|
|
366
|
+ break
|
|
367
|
+ else:
|
|
368
|
+ print(OKGREEN + 'SUCCESS' + ENDC)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+def unittest_status(unittest_folder):
|
|
372
|
+ config = imp.load_source('', os.path.join(unittest_folder, 'src', 'config.py'))
|
|
373
|
+ #
|
|
374
|
+ print_header('Checking status of all submodules')
|
|
375
|
+ print_action('Updating all submodules (fetch)')
|
|
376
|
+ process = subprocess.Popen("LANGUAGE='en_US.UTF-8 git' git submodule foreach git fetch", cwd=os.path.dirname(unittest_folder), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
377
|
+ stderroutput = process.communicate()[1]
|
|
378
|
+ if stderroutput == b'':
|
|
379
|
+ print_info('SUCCESS', color=OKGREEN)
|
|
380
|
+ else:
|
|
381
|
+ print_info('FAILED', color=FAIL)
|
|
382
|
+
|
|
383
|
+ print_action('Checking status...')
|
|
384
|
+ process = subprocess.Popen("LANGUAGE='en_US.UTF-8 git' git submodule foreach git status", cwd=os.path.dirname(unittest_folder), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
385
|
+ stdoutput, stderroutput = process.communicate()
|
|
386
|
+ if stderroutput == b'':
|
|
387
|
+ module = None
|
|
388
|
+ data = {}
|
|
389
|
+ for line in stdoutput.splitlines():
|
|
390
|
+ line = str(line)
|
|
391
|
+ if 'Entering' in line:
|
|
392
|
+ m = line[line.index("'") + 1:]
|
|
393
|
+ m = str(m[:m.index("'")])
|
|
394
|
+ if m != module:
|
|
395
|
+ data[m] = ''
|
|
396
|
+ module = m
|
|
397
|
+ else:
|
|
398
|
+ data[m] += line
|
|
399
|
+ for key in data:
|
|
400
|
+ if "working tree clean" not in data[key] and "working directory clean" not in data[key]:
|
|
401
|
+ data[key] = ("local changes", WARNING)
|
|
402
|
+ elif "Your branch is behind" in data[key]:
|
|
403
|
+ data[key] = ("no up to date (try git pull)", FAIL)
|
|
404
|
+ elif "HEAD detached at" in data[key]:
|
|
405
|
+ data[key] = ("no up to date (try git checkout master)", FAIL)
|
|
406
|
+ elif "Your branch is ahead of" in data[key]:
|
|
407
|
+ data[key] = ("push required", WARNING)
|
|
408
|
+ elif "nothing to commit" in data[key]:
|
|
409
|
+ data[key] = ("clean", OKGREEN)
|
|
410
|
+ else:
|
|
411
|
+ data[key] = ("unknown", FAIL)
|
|
412
|
+ print_info('Submodule %s... %s' % (key, data[key][1] + data[key][0]))
|
|
413
|
+ else:
|
|
414
|
+ print_info('FAILED', color=FAIL)
|
|
415
|
+ #
|
|
416
|
+ print_header('Checking status of unittest and testresults in the library')
|
|
417
|
+ print_action('Loading Testrun data from %s' % unittest_filename(unittest_folder, FILES['data-collection']))
|
|
418
|
+ with open(unittest_filename(unittest_folder, FILES['data-collection']), 'r') as fh:
|
|
419
|
+ data_collection = json.loads(fh.read())
|
|
420
|
+ print_action('Checking release state of this testrun... ')
|
|
421
|
+ if data_collection['testobject_information']['State'] != 'Released':
|
|
422
|
+ print_info("FAILED", FAIL)
|
|
423
|
+ else:
|
|
424
|
+ print_info("SUCCESS", OKGREEN)
|
|
425
|
+ #
|
|
426
|
+ print_action('Checking up to dateness of testrults in library...')
|
|
427
|
+ try:
|
|
428
|
+ with open(os.path.join(unittest_folder, '..', 'pylibs', config.lib.__name__, '_testresults_', FILES['data-collection']), 'r') as fh:
|
|
429
|
+ lib_result = json.loads(fh.read())
|
|
430
|
+ except FileNotFoundError:
|
|
431
|
+ print_info("FAILED: Testresults not in library", FAIL)
|
|
432
|
+ else:
|
|
433
|
+ if data_collection['testobject_information'] != lib_result['testobject_information'] or data_collection['unittest_information'] != lib_result['unittest_information']:
|
|
434
|
+ print_info("FAILED", FAIL)
|
|
435
|
+ else:
|
|
436
|
+ print_info("SUCCESS", OKGREEN)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+def unittest_copy(unittest_folder):
|
|
440
|
+ config = imp.load_source('', os.path.join(unittest_folder, 'src', 'config.py'))
|
|
441
|
+ #
|
|
442
|
+ print_header('Copy unittest files to library')
|
|
443
|
+ target_folder = os.path.join(config.lib_path, '_testresults_')
|
|
444
|
+ print_action('Copying Unittest Files to %s' % target_folder)
|
|
445
|
+ if not os.path.exists(target_folder):
|
|
446
|
+ print_info('Creating folder %s' % target_folder)
|
|
447
|
+ fstools.mkdir(target_folder)
|
|
448
|
+ else:
|
|
449
|
+ for fn in os.listdir(target_folder):
|
|
450
|
+ remove_file(os.path.join(target_folder, fn))
|
|
451
|
+ for fn in REPORT_FILES:
|
|
452
|
+ src = unittest_filename(unittest_folder, fn)
|
|
453
|
+ dst = os.path.join(target_folder, fn)
|
|
454
|
+ print_info('copying %s -> %s' % (src, dst))
|
|
455
|
+ shutil.copyfile(src, dst)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+def unittest_release(unittest_folder):
|
|
459
|
+ with open(os.path.join(unittest_folder, 'src', 'config.py'), 'r') as fh:
|
|
460
|
+ conf_file = fh.read()
|
|
461
|
+ with open(os.path.join(unittest_folder, 'src', 'config.py'), 'w') as fh:
|
|
462
|
+ for line in conf_file.splitlines():
|
|
463
|
+ if line.startswith('release_unittest_version'):
|
|
464
|
+ fh.write("release_unittest_version = '%s'\n" % module_uid(os.path.join(unittest_folder, 'src', 'tests')))
|
|
465
|
+ else:
|
|
466
|
+ fh.write(line + '\n')
|