-
Notifications
You must be signed in to change notification settings - Fork 8
/
stat_main.py
208 lines (169 loc) · 7.04 KB
/
stat_main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/env python
# SPDX-FileCopyrightText: (c) 2020 Western Digital Corporation or its affiliates,
# Arseniy Aharonov <[email protected]>
#
# SPDX-License-Identifier: MIT
from __future__ import print_function
import sys
from multiprocessing import Pool, freeze_support
import stat_attributes as attributes
from stat_argument_parser import StatArgumentParser
from stat_configuration import StatConfiguration
from stat_debug import Profiler
from stat_makefile_generator import StatMakefileGenerator
from services import writeJsonFile, remove, mkdir
from ide_writer import IdeWorkspaceWriter
from tests_runner import TestsRunner, TestsRunnerException
STAT_OUTPUT_DELIMITER = "=" * 70
STAT_SUMMARY = "Total: {total} Runs {passed} Passed {failed} Failed"
STAT_SILENT_OUTPUT = "{0:50}:{1}"
MAKEFILE_CORRUPTION = 'Processing "{filename}" failed with exception: \n{exception}'
def runTestPackage(makefile, makeArguments, shallRun, shallBeVerbose):
try:
runner = TestsRunner(makefile, makeArguments, shallBeVerbose)
try:
runner.compile()
if shallRun:
runner.run()
except TestsRunnerException as exception:
errorMessage = str(exception)
runner.writeLog(errorMessage)
status, description = 'FAILED', errorMessage
except Exception as exception:
errorMessage = str(exception)
runner.writeLog(errorMessage)
status, description = 'CRASHED', str(errorMessage)
else:
status, description = 'PASSED', ''
except Exception as exception:
status, description = 'CRASHED', MAKEFILE_CORRUPTION.format(filename=makefile, exception=str(exception))
return makefile, status, description
def prepareOutputDirectories():
remove(attributes.LOGS_DIRECTORY)
mkdir(attributes.LOGS_DIRECTORY)
mkdir(attributes.OUTPUT_DIRECTORY, exist_ok=True)
class StatMain(object):
@staticmethod
def run(manualArguments=None):
"""
:param manualArguments: if specified, used instead of system command-line arguments
"""
main = StatMain()
main._run(manualArguments)
def __init__(self):
self.__config = StatConfiguration()
self.__parser = StatArgumentParser(self.__config.products, self.__config.defaultProduct)
self.__makeArguments = ['INSTALL_BY_COPY="TRUE"']
self.__report = StatReport()
def _run(self, manualArguments):
self.__parser.parse(manualArguments)
self.adjustCommandLineWithCleaningLevel()
if self.__parser.ide is not None:
self.__createIdeWorkspace()
else:
self.__runTests()
if self.__parser.redundant:
raise StatWarning('WARNING: The arguments {0} are redundant!'.format(self.__parser.redundant))
def adjustCommandLineWithCleaningLevel(self):
cleaningLevel = self.__parser.getRequestedCleaningLevel()
# self.__makeArguments.append("--debug=b")
if cleaningLevel > 0:
if cleaningLevel > 1:
self.__makeArguments.append(attributes.CLEAN_TARGET)
self.__makeArguments.append(attributes.REBUILD_TARGET)
def __runTests(self):
prepareOutputDirectories()
for target in self.__parser.targetProducts:
self.__runTestsOnTarget(target)
self.__report.write()
print(STAT_OUTPUT_DELIMITER)
print(STAT_SUMMARY.format(total=self.__report.total, passed=self.__report.passed, failed=self.__report.failed))
if self.__report.failed:
raise StatException('The following packages failed:\n\t{0}'.format('\n\t'.join(self.__report.failedList)))
def __runTestsOnTarget(self, target):
if self.__parser.processes:
self.__runTestsOnTargetInParallel(target)
else:
self.__runTestsOnTargetInSerial(target)
def __runTestsOnTargetInSerial(self, target):
self.__prepareTarget(target)
for makefile in self.__parser.makeFiles:
result = runTestPackage(makefile, self.__makeArguments, self.__parser.shallRun(),
self.__parser.shallBeVerbose())
self.__log(*result)
def __runTestsOnTargetInParallel(self, target):
def handleResult(result):
self.__log(*result)
self.__prepareTarget(target)
pool = Pool(self.__parser.processes)
for makefile in self.__parser.makeFiles:
args = (makefile, self.__makeArguments, self.__parser.shallRun(), self.__parser.shallBeVerbose())
pool.apply_async(runTestPackage, args, callback=handleResult)
pool.close()
pool.join()
def __createIdeWorkspace(self):
self.__prepareTarget(self.__parser.targetProducts[0])
writer = IdeWorkspaceWriter(self.__parser.ide, self.__parser.makeFiles[0])
writer.write()
def __prepareTarget(self, name):
self.__report.logTarget(name)
if self.__config.isStale() or self.__parser.targetProducts != [self.__config.defaultProduct]:
targetMakefile = StatMakefileGenerator(name + ".mak")
targetMakefile.generate()
def __log(self, makefile, status, info):
self.__report[makefile] = status, info
if not self.__parser.shallBeVerbose():
print(STAT_SILENT_OUTPUT.format(makefile, status))
class StatReport(object):
def __init__(self):
self.__finalReport = {}
self.__targetReport = self.__finalReport
@property
def total(self):
return len([makefile for target in self.__finalReport for makefile in self.__finalReport[target]])
@property
def passed(self):
return self.total - self.failed
@property
def failed(self):
return len(self.__extractFailedOnes())
@property
def failedList(self):
return set(self.__extractFailedOnes())
def logTarget(self, name):
self.__targetReport = {}
self.__finalReport[name] = self.__targetReport
def write(self):
writeJsonFile(attributes.REPORT_FILENAME, self.__finalReport)
def __setitem__(self, makefile, results):
status, info = results
self.__targetReport[makefile] = {'Status': status, 'Info': info}
def __extractFailedOnes(self):
return [makefile for target in self.__finalReport for makefile in self.__finalReport[target]
if not self.__finalReport[target][makefile]['Status'] == 'PASSED']
class StatWarning(Exception):
"""
Custom exception for the STAT-framework managed warnings
"""
class StatException(Exception):
"""
Custom exception for the STAT-framework managed failures
"""
if __name__ == '__main__':
freeze_support()
try:
if '--debug=profile' in sys.argv:
with Profiler():
StatMain.run()
else:
StatMain.run()
except StatWarning as w:
print("\n")
print(w)
print("\n=== PASSED ===")
except Exception as e:
print(e)
print("\n=== FAILED ===")
sys.exit(-1)
else:
print("\n=== PASSED ===")