summaryrefslogtreecommitdiffstats
path: root/utils/lit/TestRunner.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/lit/TestRunner.py')
-rw-r--r--utils/lit/TestRunner.py517
1 files changed, 0 insertions, 517 deletions
diff --git a/utils/lit/TestRunner.py b/utils/lit/TestRunner.py
deleted file mode 100644
index 20fbc6c..0000000
--- a/utils/lit/TestRunner.py
+++ /dev/null
@@ -1,517 +0,0 @@
-import os, signal, subprocess, sys
-import StringIO
-
-import ShUtil
-import Test
-import Util
-
-import platform
-import tempfile
-
-class InternalShellError(Exception):
- def __init__(self, command, message):
- self.command = command
- self.message = message
-
-# Don't use close_fds on Windows.
-kUseCloseFDs = platform.system() != 'Windows'
-
-# Use temporary files to replace /dev/null on Windows.
-kAvoidDevNull = platform.system() == 'Windows'
-
-def executeCommand(command, cwd=None, env=None):
- p = subprocess.Popen(command, cwd=cwd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- env=env)
- out,err = p.communicate()
- exitCode = p.wait()
-
- # Detect Ctrl-C in subprocess.
- if exitCode == -signal.SIGINT:
- raise KeyboardInterrupt
-
- return out, err, exitCode
-
-def executeShCmd(cmd, cfg, cwd, results):
- if isinstance(cmd, ShUtil.Seq):
- if cmd.op == ';':
- res = executeShCmd(cmd.lhs, cfg, cwd, results)
- return executeShCmd(cmd.rhs, cfg, cwd, results)
-
- if cmd.op == '&':
- raise NotImplementedError,"unsupported test command: '&'"
-
- if cmd.op == '||':
- res = executeShCmd(cmd.lhs, cfg, cwd, results)
- if res != 0:
- res = executeShCmd(cmd.rhs, cfg, cwd, results)
- return res
- if cmd.op == '&&':
- res = executeShCmd(cmd.lhs, cfg, cwd, results)
- if res is None:
- return res
-
- if res == 0:
- res = executeShCmd(cmd.rhs, cfg, cwd, results)
- return res
-
- raise ValueError,'Unknown shell command: %r' % cmd.op
-
- assert isinstance(cmd, ShUtil.Pipeline)
- procs = []
- input = subprocess.PIPE
- stderrTempFiles = []
- # To avoid deadlock, we use a single stderr stream for piped
- # output. This is null until we have seen some output using
- # stderr.
- for i,j in enumerate(cmd.commands):
- # Apply the redirections, we use (N,) as a sentinal to indicate stdin,
- # stdout, stderr for N equal to 0, 1, or 2 respectively. Redirects to or
- # from a file are represented with a list [file, mode, file-object]
- # where file-object is initially None.
- redirects = [(0,), (1,), (2,)]
- for r in j.redirects:
- if r[0] == ('>',2):
- redirects[2] = [r[1], 'w', None]
- elif r[0] == ('>>',2):
- redirects[2] = [r[1], 'a', None]
- elif r[0] == ('>&',2) and r[1] in '012':
- redirects[2] = redirects[int(r[1])]
- elif r[0] == ('>&',) or r[0] == ('&>',):
- redirects[1] = redirects[2] = [r[1], 'w', None]
- elif r[0] == ('>',):
- redirects[1] = [r[1], 'w', None]
- elif r[0] == ('>>',):
- redirects[1] = [r[1], 'a', None]
- elif r[0] == ('<',):
- redirects[0] = [r[1], 'r', None]
- else:
- raise NotImplementedError,"Unsupported redirect: %r" % (r,)
-
- # Map from the final redirections to something subprocess can handle.
- final_redirects = []
- for index,r in enumerate(redirects):
- if r == (0,):
- result = input
- elif r == (1,):
- if index == 0:
- raise NotImplementedError,"Unsupported redirect for stdin"
- elif index == 1:
- result = subprocess.PIPE
- else:
- result = subprocess.STDOUT
- elif r == (2,):
- if index != 2:
- raise NotImplementedError,"Unsupported redirect on stdout"
- result = subprocess.PIPE
- else:
- if r[2] is None:
- if kAvoidDevNull and r[0] == '/dev/null':
- r[2] = tempfile.TemporaryFile(mode=r[1])
- else:
- r[2] = open(r[0], r[1])
- # Workaround a Win32 and/or subprocess bug when appending.
- if r[1] == 'a':
- r[2].seek(0, 2)
- result = r[2]
- final_redirects.append(result)
-
- stdin, stdout, stderr = final_redirects
-
- # If stderr wants to come from stdout, but stdout isn't a pipe, then put
- # stderr on a pipe and treat it as stdout.
- if (stderr == subprocess.STDOUT and stdout != subprocess.PIPE):
- stderr = subprocess.PIPE
- stderrIsStdout = True
- else:
- stderrIsStdout = False
-
- # Don't allow stderr on a PIPE except for the last
- # process, this could deadlock.
- #
- # FIXME: This is slow, but so is deadlock.
- if stderr == subprocess.PIPE and j != cmd.commands[-1]:
- stderr = tempfile.TemporaryFile(mode='w+b')
- stderrTempFiles.append((i, stderr))
-
- # Resolve the executable path ourselves.
- args = list(j.args)
- args[0] = Util.which(args[0], cfg.environment['PATH'])
- if not args[0]:
- raise InternalShellError(j, '%r: command not found' % j.args[0])
-
- procs.append(subprocess.Popen(args, cwd=cwd,
- stdin = stdin,
- stdout = stdout,
- stderr = stderr,
- env = cfg.environment,
- close_fds = kUseCloseFDs))
-
- # Immediately close stdin for any process taking stdin from us.
- if stdin == subprocess.PIPE:
- procs[-1].stdin.close()
- procs[-1].stdin = None
-
- # Update the current stdin source.
- if stdout == subprocess.PIPE:
- input = procs[-1].stdout
- elif stderrIsStdout:
- input = procs[-1].stderr
- else:
- input = subprocess.PIPE
-
- # FIXME: There is probably still deadlock potential here. Yawn.
- procData = [None] * len(procs)
- procData[-1] = procs[-1].communicate()
-
- for i in range(len(procs) - 1):
- if procs[i].stdout is not None:
- out = procs[i].stdout.read()
- else:
- out = ''
- if procs[i].stderr is not None:
- err = procs[i].stderr.read()
- else:
- err = ''
- procData[i] = (out,err)
-
- # Read stderr out of the temp files.
- for i,f in stderrTempFiles:
- f.seek(0, 0)
- procData[i] = (procData[i][0], f.read())
-
- exitCode = None
- for i,(out,err) in enumerate(procData):
- res = procs[i].wait()
- # Detect Ctrl-C in subprocess.
- if res == -signal.SIGINT:
- raise KeyboardInterrupt
-
- results.append((cmd.commands[i], out, err, res))
- if cmd.pipe_err:
- # Python treats the exit code as a signed char.
- if res < 0:
- exitCode = min(exitCode, res)
- else:
- exitCode = max(exitCode, res)
- else:
- exitCode = res
-
- if cmd.negate:
- exitCode = not exitCode
-
- return exitCode
-
-def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
- ln = ' &&\n'.join(commands)
- try:
- cmd = ShUtil.ShParser(ln, litConfig.isWindows).parse()
- except:
- return (Test.FAIL, "shell parser error on: %r" % ln)
-
- results = []
- try:
- exitCode = executeShCmd(cmd, test.config, cwd, results)
- except InternalShellError,e:
- out = ''
- err = e.message
- exitCode = 255
-
- out = err = ''
- for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
- out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
- out += 'Command %d Result: %r\n' % (i, res)
- out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
- out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
-
- return out, err, exitCode
-
-def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
- import TclUtil
- cmds = []
- for ln in commands:
- # Given the unfortunate way LLVM's test are written, the line gets
- # backslash substitution done twice.
- ln = TclUtil.TclLexer(ln).lex_unquoted(process_all = True)
-
- try:
- tokens = list(TclUtil.TclLexer(ln).lex())
- except:
- return (Test.FAIL, "Tcl lexer error on: %r" % ln)
-
- # Validate there are no control tokens.
- for t in tokens:
- if not isinstance(t, str):
- return (Test.FAIL,
- "Invalid test line: %r containing %r" % (ln, t))
-
- try:
- cmds.append(TclUtil.TclExecCommand(tokens).parse_pipeline())
- except:
- return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln)
-
- cmd = cmds[0]
- for c in cmds[1:]:
- cmd = ShUtil.Seq(cmd, '&&', c)
-
- # FIXME: This is lame, we shouldn't need bash. See PR5240.
- bashPath = litConfig.getBashPath()
- if litConfig.useTclAsSh and bashPath:
- script = tmpBase + '.script'
-
- # Write script file
- f = open(script,'w')
- print >>f, 'set -o pipefail'
- cmd.toShell(f, pipefail = True)
- f.close()
-
- if 0:
- print >>sys.stdout, cmd
- print >>sys.stdout, open(script).read()
- print >>sys.stdout
- return '', '', 0
-
- command = [litConfig.getBashPath(), script]
- out,err,exitCode = executeCommand(command, cwd=cwd,
- env=test.config.environment)
-
- # Tcl commands fail on standard error output.
- if err:
- exitCode = 1
- out = 'Command has output on stderr!\n\n' + out
-
- return out,err,exitCode
- else:
- results = []
- try:
- exitCode = executeShCmd(cmd, test.config, cwd, results)
- except InternalShellError,e:
- results.append((e.command, '', e.message + '\n', 255))
- exitCode = 255
-
- out = err = ''
-
- # Tcl commands fail on standard error output.
- if [True for _,_,err,res in results if err]:
- exitCode = 1
- out += 'Command has output on stderr!\n\n'
-
- for i,(cmd, cmd_out, cmd_err, res) in enumerate(results):
- out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
- out += 'Command %d Result: %r\n' % (i, res)
- out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
- out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
-
- return out, err, exitCode
-
-def executeScript(test, litConfig, tmpBase, commands, cwd):
- script = tmpBase + '.script'
- if litConfig.isWindows:
- script += '.bat'
-
- # Write script file
- f = open(script,'w')
- if litConfig.isWindows:
- f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
- else:
- f.write(' &&\n'.join(commands))
- f.write('\n')
- f.close()
-
- if litConfig.isWindows:
- command = ['cmd','/c', script]
- else:
- command = ['/bin/sh', script]
- if litConfig.useValgrind:
- # FIXME: Running valgrind on sh is overkill. We probably could just
- # run on clang with no real loss.
- valgrindArgs = ['valgrind', '-q',
- '--tool=memcheck', '--trace-children=yes',
- '--error-exitcode=123']
- valgrindArgs.extend(litConfig.valgrindArgs)
-
- command = valgrindArgs + command
-
- return executeCommand(command, cwd=cwd, env=test.config.environment)
-
-def isExpectedFail(xfails, xtargets, target_triple):
- # Check if any xfail matches this target.
- for item in xfails:
- if item == '*' or item in target_triple:
- break
- else:
- return False
-
- # If so, see if it is expected to pass on this target.
- #
- # FIXME: Rename XTARGET to something that makes sense, like XPASS.
- for item in xtargets:
- if item == '*' or item in target_triple:
- return False
-
- return True
-
-def parseIntegratedTestScript(test):
- """parseIntegratedTestScript - Scan an LLVM/Clang style integrated test
- script and extract the lines to 'RUN' as well as 'XFAIL' and 'XTARGET'
- information. The RUN lines also will have variable substitution performed.
- """
-
- # Get the temporary location, this is always relative to the test suite
- # root, not test source root.
- #
- # FIXME: This should not be here?
- sourcepath = test.getSourcePath()
- execpath = test.getExecPath()
- execdir,execbase = os.path.split(execpath)
- tmpBase = os.path.join(execdir, 'Output', execbase)
- if test.index is not None:
- tmpBase += '_%d' % test.index
-
- # We use #_MARKER_# to hide %% while we do the other substitutions.
- substitutions = [('%%', '#_MARKER_#')]
- substitutions.extend(test.config.substitutions)
- substitutions.extend([('%s', sourcepath),
- ('%S', os.path.dirname(sourcepath)),
- ('%p', os.path.dirname(sourcepath)),
- ('%t', tmpBase + '.tmp'),
- # FIXME: Remove this once we kill DejaGNU.
- ('%abs_tmp', tmpBase + '.tmp'),
- ('#_MARKER_#', '%')])
-
- # Collect the test lines from the script.
- script = []
- xfails = []
- xtargets = []
- for ln in open(sourcepath):
- if 'RUN:' in ln:
- # Isolate the command to run.
- index = ln.index('RUN:')
- ln = ln[index+4:]
-
- # Trim trailing whitespace.
- ln = ln.rstrip()
-
- # Collapse lines with trailing '\\'.
- if script and script[-1][-1] == '\\':
- script[-1] = script[-1][:-1] + ln
- else:
- script.append(ln)
- elif 'XFAIL:' in ln:
- items = ln[ln.index('XFAIL:') + 6:].split(',')
- xfails.extend([s.strip() for s in items])
- elif 'XTARGET:' in ln:
- items = ln[ln.index('XTARGET:') + 8:].split(',')
- xtargets.extend([s.strip() for s in items])
- elif 'END.' in ln:
- # Check for END. lines.
- if ln[ln.index('END.'):].strip() == 'END.':
- break
-
- # Apply substitutions to the script.
- def processLine(ln):
- # Apply substitutions
- for a,b in substitutions:
- ln = ln.replace(a,b)
-
- # Strip the trailing newline and any extra whitespace.
- return ln.strip()
- script = map(processLine, script)
-
- # Verify the script contains a run line.
- if not script:
- return (Test.UNRESOLVED, "Test has no run line!")
-
- if script[-1][-1] == '\\':
- return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')")
-
- isXFail = isExpectedFail(xfails, xtargets, test.suite.config.target_triple)
- return script,isXFail,tmpBase,execdir
-
-def formatTestOutput(status, out, err, exitCode, script):
- output = StringIO.StringIO()
- print >>output, "Script:"
- print >>output, "--"
- print >>output, '\n'.join(script)
- print >>output, "--"
- print >>output, "Exit Code: %r" % exitCode
- print >>output, "Command Output (stdout):"
- print >>output, "--"
- output.write(out)
- print >>output, "--"
- print >>output, "Command Output (stderr):"
- print >>output, "--"
- output.write(err)
- print >>output, "--"
- return (status, output.getvalue())
-
-def executeTclTest(test, litConfig):
- if test.config.unsupported:
- return (Test.UNSUPPORTED, 'Test is unsupported')
-
- res = parseIntegratedTestScript(test)
- if len(res) == 2:
- return res
-
- script, isXFail, tmpBase, execdir = res
-
- if litConfig.noExecute:
- return (Test.PASS, '')
-
- # Create the output directory if it does not already exist.
- Util.mkdir_p(os.path.dirname(tmpBase))
-
- res = executeTclScriptInternal(test, litConfig, tmpBase, script, execdir)
- if len(res) == 2:
- return res
-
- out,err,exitCode = res
- if isXFail:
- ok = exitCode != 0
- status = (Test.XPASS, Test.XFAIL)[ok]
- else:
- ok = exitCode == 0
- status = (Test.FAIL, Test.PASS)[ok]
-
- if ok:
- return (status,'')
-
- return formatTestOutput(status, out, err, exitCode, script)
-
-def executeShTest(test, litConfig, useExternalSh):
- if test.config.unsupported:
- return (Test.UNSUPPORTED, 'Test is unsupported')
-
- res = parseIntegratedTestScript(test)
- if len(res) == 2:
- return res
-
- script, isXFail, tmpBase, execdir = res
-
- if litConfig.noExecute:
- return (Test.PASS, '')
-
- # Create the output directory if it does not already exist.
- Util.mkdir_p(os.path.dirname(tmpBase))
-
- if useExternalSh:
- res = executeScript(test, litConfig, tmpBase, script, execdir)
- else:
- res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
- if len(res) == 2:
- return res
-
- out,err,exitCode = res
- if isXFail:
- ok = exitCode != 0
- status = (Test.XPASS, Test.XFAIL)[ok]
- else:
- ok = exitCode == 0
- status = (Test.FAIL, Test.PASS)[ok]
-
- if ok:
- return (status,'')
-
- return formatTestOutput(status, out, err, exitCode, script)
OpenPOWER on IntegriCloud