16from mevis
import MLAB, MLABPackageManager, MLABTestCaseDatabase
32def inject(executable, context, allowedStdErrRegExp=None):
35 match = re.search(
r"\$\(MLAB_([^_)]+)_([^_)]+)\)", executable)
37 package = MLABPackageManager.packageByIdentifier(match.group(1) +
"/" + match.group(2))
39 executable = executable.replace(match.group(0), package.binariesPath())
40 test =
CodeTest(executable=context.expandFilename(executable))
41 test.injectTestFunctions(context, allowedStdErrRegExp=allowedStdErrRegExp)
44pathToBuildSystemScripts = MLABPackageManager.getPathInPackage(
"MeVis/BuildSystem",
"BuildTools/Scripts")
45if os.path.isdir(pathToBuildSystemScripts):
46 if not pathToBuildSystemScripts
in sys.path:
47 sys.path.insert(0, pathToBuildSystemScripts)
48 from MeVisPython
import MeVisPython
49del pathToBuildSystemScripts
53 colorOk =
"color: rgb(78,154,6);"
54 colorFailed =
"color: rgb(204,0,0);"
55 commonStyle =
"font-family: monospace;"
57 statusFormat =
'<div style="%s"><span style="%s">%%s</span>%%s</div>'
58 errorFormat = statusFormat % (commonStyle, colorFailed)
59 infoFormat = statusFormat % (commonStyle, colorOk)
61 statusRegExp = re.compile(
"(?P<status>\\[\\s*\\S+\\s*\\])(?P<message>.*)")
63 hasNotifiedStdErrOutput =
False
70 lowerStderrMsg = result[
"stderr"].lower()
71 if lowerStderrMsg
and allowedStdErrRegExp
is not None:
72 info(f
"NOTE: Test is configured to ignore stderr output that matches the regex '{allowedStdErrRegExp}'")
73 lowerStderrMsg = re.sub(allowedStdErrRegExp,
"", lowerStderrMsg, flags=re.IGNORECASE)
74 stdErrContainsError = (lowerStderrMsg.find(
"error") >= 0)
or (lowerStderrMsg.find(
"failed") >= 0)
76 needsRestartWithoutSanitizer =
False
77 if stdErrContainsError:
81 lowerStderrMsg.find(
"sanitizer check failed:") >= 0
82 and lowerStderrMsg.find(
"src/libsanitizer/asan/asan_malloc_linux.cc") >= 0
83 and lowerStderrMsg.find(
"allocated_for_dlsym") >= 0
85 needsRestartWithoutSanitizer = allowRestart
87 if not needsRestartWithoutSanitizer:
89 EXPECT_EQ(result[
"status"], 0, msg=
"The test status is not 0.", logOnSuccess=
False)
90 EXPECT_TRUE(result[
"ok"], msg=
"The test run failed.", logOnSuccess=
False)
91 ASSERT_TRUE(
"stdout" in result, msg=
"The test output does not exists.", logOnSuccess=
False)
93 for outChannel
in [
"stdout",
"stderr"]:
94 for line
in result[outChannel].splitlines():
96 if outChannel ==
"stderr" and not hasNotifiedStdErrOutput:
97 if stdErrContainsError:
99 'Note: The stderr channel output contained "error" or "failed" which is handled as test failure.'
101 infoHTML(
"The test printed the following messages to stderr channel:")
102 hasNotifiedStdErrOutput =
True
104 m = statusRegExp.match(line)
106 status = m.group(
"status").replace(
" ",
" ").replace(
"\t",
" " * 4)
107 message = m.group(
"message").replace(
" ",
" ").replace(
"\t",
" " * 4)
108 if "FAILED" in status:
109 errorHTML(errorFormat % (status, message))
111 infoHTML(infoFormat % (status, message))
113 line = line.replace(
" ",
" ").replace(
"\t",
" " * 4)
114 infoHTML((
'<div style="%s">' + line +
"</div>") % commonStyle)
116 return needsRestartWithoutSanitizer
140 def __init__(self, cmakeFile=None, executable=None):
148 if cmakeFile
is not None:
150 elif executable
is not None:
151 self.
name = os.path.basename(executable)
156 while MLABTestCaseDatabase.testCaseInfo(uniqueName):
162 uniqueName = name + str(i)
168 package = MLABPackageManager.findPackageContainingPath(self.
cmakeFile)
170 "package": package.packageIdentifier(),
174 "type":
"CodeTestTestCase",
175 "scriptFile":
"ScriptFileNotAvailable",
188 MLAB.logError(f
"Code test executable for {self.name} not found.")
195 MLAB.logError(f
"Code test executable {self.executable} not found.")
199 def __appendSuffix(executable):
201 exeSuffix =
".exe" if MLAB.isWindows()
else ""
204 if os.path.exists(executable + exeSuffix):
205 executable += exeSuffix
206 elif not MLAB.isDebug()
and os.path.exists(executable +
"_d" + exeSuffix):
207 executable +=
"_d" + exeSuffix
209 executable += exeSuffix
210 executable = executable.replace(
"_d" + exeSuffix, exeSuffix)
214 def __executableExists(executable):
215 return executable
and os.path.exists(executable)
224 arguments = [
"--build",
".",
"--config", (
"Debug" if MLAB.isDebug()
else "Release"),
"--target", self.
name]
225 result = MLAB.runCommandStdInOut(executable, arguments, self.
_getBuildRoot())
230 MLAB.showCritical(self.
_getError(result))
232 if result[
"ok"] !=
True:
234 return result[
"ok"] ==
True
238 stderr = result.get(
"stderr")
239 stdout = result.get(
"stdout")
241 message.append(stdout.encode(
"latin1").decode(
"UTF-8"))
243 message.append(stderr.encode(
"latin1").decode(
"UTF-8"))
244 if not stdout
and not stderr:
245 message.append(
"An unknown error occurred")
246 return "\n".join(message)
249 testRegex = re.compile(
r"^(?!#)\s*mlab_add_test\(\s*(\w*)")
251 with open(cmakeFile,
"r")
as f:
253 match = testRegex.match(line)
254 if match
and match.group(1):
255 target = match.group(1)
260 if "MLAB_BUILD" in os.environ:
261 buildRoot = os.environ[
"MLAB_BUILD"]
263 buildRoot = os.path.normpath(
264 os.path.join(MLABPackageManager.packageByIdentifier(
"MeVisLab/IDE").binariesPath(),
"..",
"..")
271 testArguments = [
"-V",
"-R", self.
name,
"-C", (
"Debug" if MLAB.isDebug()
else "Release"),
"--show-only=json-v1"]
272 result = MLAB.runCommandStdInOut(command, testArguments, self.
_getBuildRoot())
273 if result[
"ok"] ==
True:
274 testDetails = json.loads(result[
"stdout"])
276 "tests" in testDetails
277 and len(testDetails[
"tests"]) > 0
278 and "command" in testDetails[
"tests"][0]
279 and len(testDetails[
"tests"][0][
"command"]) > 0
281 executable = testDetails[
"tests"][0][
"command"][0]
283 if executable
is None and self.
cmakeFile:
284 package = MLABPackageManager.findPackageContainingPath(self.
cmakeFile)
285 executable = self.
__appendSuffix(os.path.join(package.binariesPath(),
"CodeTests",
"bin", self.
name))
294 result = MLAB.runCommandStdInOut(executable, [
"--gtest_list_tests"], os.path.dirname(executable))
295 if result[
"ok"] ==
True:
298 def __getUniqueFunctionName(self, name):
303 uniqueName = name + str(i)
308 identifierRegExp = re.compile(
r"^[\S]+$")
314 for line
in output.splitlines():
315 commentIdx = line.find(
"#")
317 line = line[:commentIdx].rstrip(
" ")
318 if not line.startswith(
" "):
319 name = line.rstrip(
".")
320 if identifierRegExp.match(name):
321 sourceName =
"GROUP%03d_%s" % (groupIdx, name.replace(
"/",
"_"))
327 if identifierRegExp.match(name):
330 if uniqueName.startswith(
"DISABLED_"):
331 uniqueName = uniqueName[len(
"DISABLED_") :]
334 sourceName =
"TEST%03d_%s" % (functionIdx, uniqueName.replace(
"/",
"_"))
336 sourceName =
"DISABLED_" + sourceName
338 group.addFunction(function)
347 globalSymbols = globals()
348 localSymbols = locals()
351 for function
in group.getFunctions():
352 testCode += self.
_functionCode(group, function, allowedStdErrRegExp=allowedStdErrRegExp)
355 eval(compile(testCode,
"<string>",
"exec"), globalSymbols, localSymbols)
359 for f
in group.getFunctions():
360 functions.append(
"'" + f.sourceName +
"'")
361 return """def %(sourceName)s():
362 return %(functions)s,
363ctx.setScriptVariable(%(sourceName)s.__name__, %(sourceName)s)
365 sourceName=group.sourceName, functions=
",".join(functions)
369 mlabRootPath = MLAB.variable(
"MLAB_MeVis_BuildSystem")
372 +
"/BuildTools/linux/"
374 +
"SanitizerSuppressions_gcc"
379 return os.path.isfile(suppressionFile)
and os.path.exists(suppressionFile)
383 compilerInfo = MLAB.compilerInfo()
384 compilerVersion =
"4"
385 if compilerInfo.find(
"GCC_64_7") >= 0:
386 compilerVersion =
"7"
387 elif compilerInfo.find(
"GCC_64_9") >= 0:
388 compilerVersion =
"9"
389 elif compilerInfo.find(
"") >= 0:
390 compilerVersion =
"5"
400 MLAB.log(u"Running in sanitizer environment of gcc%(compilerVer)s ('asan' and 'ubsan' libs with LD_PRELOAD as well as suppression files).")
401 mlabRootPath = MLAB.variable("MLAB_MeVis_BuildSystem")
402 sanitizerEnvVarIntro = "suppressions=" + mlabRootPath + os.sep
403 os.environ["LSAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/LeakSanitizerSuppressions_gcc%(compilerVer)s.supp"
404 os.environ["ASAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/AddressSanitizerSuppressions_gcc%(compilerVer)s.supp"
405 os.environ["UBSAN_OPTIONS"] = sanitizerEnvVarIntro + u"BuildTools/linux/UBSanitizerSuppressions_gcc%(compilerVer)s.supp"
406 os.environ["TSAN_OPTIONS"] = sanitizerEnvVarIntro + u"linux/ThreadSanitizerSuppressions_gcc%(compilerVer)s.supp"
407 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"
409 compilerVer=compilerVersion
413 MLAB.log(u"Could not find (all) sanitizer suppression files: not running test in gcc sanitizer environment.")
420 exePath = exePath.replace(
"\\",
"\\\\")
422 return """def %(sourceName)s():
423 executable = "%(executable)s"
424 for package in MLABPackageManager.packages():
425 os.environ[package.packageEnvVariableName()] = package.scriptsPath()
426%(sanitizerSetUpCode)s
427 result = MLAB.runCommandStdInOut(executable, ['--gtest_also_run_disabled_tests', '--gtest_filter=%(groupName)s.%(functionName)s'], os.path.dirname(executable))
428 from TestSupport.CodeTest import _parseGoogleTestOutput
429 needsRestartWithoutSanitizer = _parseGoogleTestOutput(result, allowRestart=True, allowedStdErrRegExp=r"%(allowedStdErrRegExp)s")
430 if needsRestartWithoutSanitizer:
431 os.environ["LD_PRELOAD"] = ""
432 MLAB.log(u"Sanitizer is incompatible with unittest. Restarting test without sanitzer preload.")
433 result = MLAB.runCommandStdInOut(executable, ['--gtest_also_run_disabled_tests', '--gtest_filter=%(groupName)s.%(functionName)s'], os.path.dirname(executable))
434 _parseGoogleTestOutput(result, allowedStdErrRegExp=r"%(allowedStdErrRegExp)s")
435ctx.setScriptVariable(%(sourceName)s.__name__, %(sourceName)s)
437 sourceName=function.sourceName,
439 sanitizerSetUpCode=saniCode,
440 groupName=group.name,
441 functionName=function.name,
442 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.