16from mevis
import MLAB, MLABPackageManager, MLABTestCaseDatabase
31def inject(executable, context, allowedStdErrRegExp=None):
34 match = re.search(
r"\$\(MLAB_([^_)]+)_([^_)]+)\)", executable)
36 package = MLABPackageManager.packageByIdentifier(match.group(1) +
"/" + match.group(2))
38 executable = executable.replace(match.group(0), package.binariesPath())
39 test =
CodeTest(executable = context.expandFilename(executable))
40 test.injectTestFunctions(context, allowedStdErrRegExp=allowedStdErrRegExp)
42pathToBuildSystemScripts = MLABPackageManager.getPathInPackage(
'MeVis/BuildSystem',
'BuildTools/Scripts')
43if os.path.isdir(pathToBuildSystemScripts):
44 if not pathToBuildSystemScripts
in sys.path:
45 sys.path.insert(0, pathToBuildSystemScripts)
46 from MeVisPython
import MeVisPython
47del pathToBuildSystemScripts
50 colorOk =
'color: rgb(78,154,6);'
51 colorFailed =
'color: rgb(204,0,0);'
52 commonStyle =
'font-family: monospace;'
54 statusFormat =
'<div style="%s"><span style="%s">%%s</span>%%s</div>'
55 errorFormat = statusFormat % (commonStyle, colorFailed)
56 infoFormat = statusFormat % (commonStyle, colorOk)
58 statusRegExp = re.compile(
"(?P<status>\\[\\s*\\S+\\s*\\])(?P<message>.*)")
60 hasNotifiedStdErrOutput =
False
67 lowerStderrMsg = result[
'stderr'].lower()
68 if lowerStderrMsg
and allowedStdErrRegExp
is not None:
69 info(f
"NOTE: Test is configured to ignore stderr output that matches the regex '{allowedStdErrRegExp}'")
70 lowerStderrMsg = re.sub( allowedStdErrRegExp,
"", lowerStderrMsg, flags=re.IGNORECASE )
71 stdErrContainsError = (lowerStderrMsg.find(
"error") >=0)
or (lowerStderrMsg.find(
"failed") >=0)
73 needsRestartWithoutSanitizer =
False
74 if stdErrContainsError:
77 if lowerStderrMsg.find(
"sanitizer check failed:") >=0
and \
78 lowerStderrMsg.find(
"src/libsanitizer/asan/asan_malloc_linux.cc") >= 0
and \
79 lowerStderrMsg.find(
"allocated_for_dlsym") >= 0:
80 needsRestartWithoutSanitizer = allowRestart
82 if not needsRestartWithoutSanitizer:
84 EXPECT_EQ(result[
"status"], 0, msg=
'The test status is not 0.', logOnSuccess=
False)
85 EXPECT_TRUE(result[
"ok"], msg=
'The test run failed.', logOnSuccess=
False)
86 ASSERT_TRUE(
"stdout" in result, msg=
'The test output does not exists.', logOnSuccess=
False)
88 for outChannel
in [
'stdout',
'stderr']:
89 for line
in result[outChannel].splitlines():
91 if outChannel==
'stderr' and not hasNotifiedStdErrOutput:
92 if stdErrContainsError:
93 errorHTML(
'Note: The stderr channel output contained "error" or "failed" which is handled as test failure.')
94 infoHTML(
'The test printed the following messages to stderr channel:')
95 hasNotifiedStdErrOutput =
True
97 m = statusRegExp.match(line)
99 status = m.group(
'status').replace(
' ',
' ').replace(
'\t',
' '*4)
100 message = m.group(
'message').replace(
' ',
' ').replace(
'\t',
' '*4)
101 if 'FAILED' in status:
102 errorHTML(errorFormat % (status, message))
104 infoHTML(infoFormat % (status, message))
106 line = line.replace(
' ',
' ').replace(
'\t',
' '*4)
107 infoHTML((
'<div style="%s">' + line +
'</div>') % commonStyle)
109 return needsRestartWithoutSanitizer
130 def __init__(self, cmakeFile = None, executable = None):
138 if cmakeFile
is not None:
140 elif executable
is not None:
141 self.
name = os.path.basename(executable)
146 while MLABTestCaseDatabase.testCaseInfo(uniqueName):
152 uniqueName = name + str(i)
158 package = MLABPackageManager.findPackageContainingPath(self.
cmakeFile)
159 self.
__infoDict = {
'package': package.packageIdentifier(),
163 'type':
'CodeTestTestCase',
164 'scriptFile':
'ScriptFileNotAvailable'}
176 MLAB.logError(f
"Code test executable for {self.name} not found." )
183 MLAB.logError(f
"Code test executable {self.executable} not found." )
187 def __appendSuffix(executable):
189 exeSuffix =
".exe" if MLAB.isWindows()
else ""
192 if os.path.exists(executable + exeSuffix):
193 executable += exeSuffix
194 elif not MLAB.isDebug()
and os.path.exists(executable +
"_d" + exeSuffix):
195 executable +=
"_d" + exeSuffix
197 executable += exeSuffix
198 executable = executable.replace(
"_d" + exeSuffix, exeSuffix)
202 def __executableExists(executable):
203 return executable
and os.path.exists(executable)
212 arguments = [
'--build',
'.',
'--config', (
'Debug' if MLAB.isDebug()
else 'Release'),
'--target', self.
name]
213 result = MLAB.runCommandStdInOut(executable, arguments, self.
_getBuildRoot())
218 MLAB.showCritical(self.
_getError(result))
220 if result[
'ok'] !=
True:
222 return result[
'ok'] ==
True
226 stderr = result.get(
'stderr')
227 stdout = result.get(
'stdout')
228 if stdout: message.append(stdout.encode(
'latin1').decode(
'UTF-8'))
229 if stderr: message.append(stderr.encode(
'latin1').decode(
'UTF-8'))
230 if not stdout
and not stderr:
231 message.append(
'An unknown error occurred')
232 return '\n'.join(message)
235 testRegex = re.compile(
r'^(?!#)\s*mlab_add_test\(\s*(\w*)')
237 with open(cmakeFile,
'r')
as f:
239 match = testRegex.match(line)
240 if match
and match.group(1):
241 target = match.group(1)
246 if 'MLAB_BUILD' in os.environ:
247 buildRoot = os.environ[
'MLAB_BUILD']
249 buildRoot = os.path.normpath(os.path.join(MLABPackageManager.packageByIdentifier(
'MeVisLab/IDE').binariesPath(),
"..",
".."))
255 testArguments = [
"-V",
"-R", self.
name,
"-C", (
"Debug" if MLAB.isDebug()
else "Release"),
"--show-only=json-v1"]
256 result = MLAB.runCommandStdInOut(command, testArguments, self.
_getBuildRoot())
257 if result[
'ok'] ==
True:
258 testDetails = json.loads(result[
'stdout'])
259 if 'tests' in testDetails
and len(testDetails[
'tests'])>0
and 'command' in testDetails[
'tests'][0]
and len(testDetails[
'tests'][0][
'command']) > 0:
260 executable = testDetails[
'tests'][0][
'command'][0]
262 if executable
is None and self.
cmakeFile:
263 package = MLABPackageManager.findPackageContainingPath(self.
cmakeFile)
264 executable = self.
__appendSuffix(os.path.join( package.binariesPath(),
"CodeTests",
"bin", self.
name))
273 result = MLAB.runCommandStdInOut(executable, [
"--gtest_list_tests"], os.path.dirname(executable))
274 if result[
'ok'] ==
True:
277 def __getUniqueFunctionName(self, name):
282 uniqueName = name + str(i)
287 identifierRegExp = re.compile(
r'^[\S]+$')
293 for line
in output.splitlines():
294 commentIdx = line.find(
'#')
296 line = line[:commentIdx].rstrip(
' ')
297 if not line.startswith(
' '):
298 name = line.rstrip(
'.')
299 if identifierRegExp.match(name):
300 sourceName =
'GROUP%03d_%s' % (groupIdx, name.replace(
'/',
'_'))
306 if identifierRegExp.match(name):
309 if uniqueName.startswith(
'DISABLED_'):
310 uniqueName = uniqueName[len(
'DISABLED_'):]
313 sourceName =
'TEST%03d_%s' % (functionIdx, uniqueName.replace(
'/',
'_'))
315 sourceName =
'DISABLED_' + sourceName
317 group.addFunction(function)
326 globalSymbols = globals()
327 localSymbols= locals()
330 for function
in group.getFunctions():
331 testCode += self.
_functionCode(group, function, allowedStdErrRegExp=allowedStdErrRegExp)
334 eval(compile(testCode,
'<string>',
'exec'), globalSymbols, localSymbols)
338 for f
in group.getFunctions():
339 functions.append(
"'" + f.sourceName +
"'")
340 return '''def %(sourceName)s():
341 return %(functions)s,
342ctx.setScriptVariable(%(sourceName)s.__name__, %(sourceName)s)
343''' % dict(sourceName = group.sourceName, functions =
",".join(functions))
346 mlabRootPath = MLAB.variable(
'MLAB_MeVis_BuildSystem')
347 suppressionFile = mlabRootPath +
'/BuildTools/linux/' + sanitizerPrefix +
u'SanitizerSuppressions_gcc' + compilerVersion +
'.supp'
349 return os.path.isfile(suppressionFile)
and os.path.exists(suppressionFile)
353 compilerInfo = MLAB.compilerInfo()
354 compilerVersion =
'4'
355 if compilerInfo.find(
u'GCC_64_7') >= 0:
356 compilerVersion =
u'7'
357 elif compilerInfo.find(
u'GCC_64_9') >= 0:
358 compilerVersion =
u'9'
359 elif compilerInfo.find(
u'') >= 0:
360 compilerVersion =
u'5'
368 MLAB.log(u"Running in sanitizer environment of gcc%(compilerVer)s ('asan' and 'ubsan' libs with LD_PRELOAD as well as suppression files).")
369 mlabRootPath = MLAB.variable("MLAB_MeVis_BuildSystem")
370 sanitizerEnvVarIntro = "suppressions=" + mlabRootPath + os.sep
371 os.environ["LSAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/LeakSanitizerSuppressions_gcc%(compilerVer)s.supp"
372 os.environ["ASAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/AddressSanitizerSuppressions_gcc%(compilerVer)s.supp"
373 os.environ["UBSAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/UBSanitizerSuppressions_gcc%(compilerVer)s.supp"
374 os.environ["TSAN_OPTIONS"] = sanitizerEnvVarIntro + u"linux/ThreadSanitizerSuppressions_gcc%(compilerVer)s.supp"
375 os.environ["LD_PRELOAD"] = u"/usr/lib/gcc/x86_64-linux-gnu/%(compilerVer)s/libasan.so:/usr/lib/gcc/x86_64-linux-gnu/%(compilerVer)s/libubsan.so"
376 ''' % dict(compilerVer = compilerVersion)
379 MLAB.log(u"Could not find (all) sanitizer suppression files: not running test in gcc sanitizer environment.")
386 exePath = exePath.replace(
'\\',
'\\\\')
388 return '''def %(sourceName)s():
389 executable = "%(executable)s"
390 for package in MLABPackageManager.packages():
391 os.environ[package.packageEnvVariableName()] = package.scriptsPath()
392%(sanitizerSetUpCode)s
393 result = MLAB.runCommandStdInOut(executable, ['--gtest_also_run_disabled_tests', '--gtest_filter=%(groupName)s.%(functionName)s'], os.path.dirname(executable))
394 from TestSupport.CodeTest import _parseGoogleTestOutput
395 needsRestartWithoutSanitizer = _parseGoogleTestOutput(result, allowRestart=True, allowedStdErrRegExp=r"%(allowedStdErrRegExp)s")
396 if needsRestartWithoutSanitizer:
397 os.environ["LD_PRELOAD"] = ""
398 MLAB.log(u"Sanitizer is incompatible with unittest. Restarting test without sanitzer preload.")
399 result = MLAB.runCommandStdInOut(executable, ['--gtest_also_run_disabled_tests', '--gtest_filter=%(groupName)s.%(functionName)s'], os.path.dirname(executable))
400 _parseGoogleTestOutput(result, allowedStdErrRegExp=r"%(allowedStdErrRegExp)s")
401ctx.setScriptVariable(%(sourceName)s.__name__, %(sourceName)s)
402''' % dict(sourceName = function.sourceName, executable = exePath, sanitizerSetUpCode = saniCode, groupName = group.name, functionName = function.name, allowedStdErrRegExp=allowedStdErrRegExp)
_functionCode(self, group, function, allowedStdErrRegExp=None)
injectTestFunctions(self, context, allowedStdErrRegExp=None)
_determineSanitizerSetUpCode(self)
_getUniqueTestCaseName(self, name)
__init__(self, cmakeFile=None, executable=None)
__getUniqueFunctionName(self, name)
_parseCMakeFile(self, cmakeFile)
__executableExists(executable)
_parseTestFunctionsFromOutput(self, output)
_hasSanitizerSuppression(self, sanitizerPrefix, envVar, compilerVersion)
__appendSuffix(executable)
getTestFunctionGroups(self)
__init__(self, name, sourceName)
addFunction(self, function)
__init__(self, name, sourceName)
_parseGoogleTestOutput(result, allowRestart=False, allowedStdErrRegExp=None)
inject(executable, context, allowedStdErrRegExp=None)
Package to provide logging functions.
Adds GoogleTest like methods.