MultiTestRunner: Cleanup test execution & output.

- Stop writing everything to files.

 - Make test output more standard.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77074 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2009-07-25 14:46:05 +00:00
Родитель a0e52d6251
Коммит a957d9996e
2 изменённых файлов: 82 добавлений и 119 удалений

Просмотреть файл

@ -23,30 +23,22 @@ kTestFileExtensions = set(['.mi','.i','.c','.cpp','.m','.mm','.ll'])
def getTests(inputs):
for path in inputs:
# Always use absolte paths.
path = os.path.abspath(path)
if not os.path.exists(path):
print >>sys.stderr,"WARNING: Invalid test \"%s\""%(path,)
continue
if os.path.isdir(path):
for dirpath,dirnames,filenames in os.walk(path):
dotTests = os.path.join(dirpath,'.tests')
if os.path.exists(dotTests):
for ln in open(dotTests):
if ln.strip():
yield os.path.join(dirpath,ln.strip())
else:
# FIXME: This doesn't belong here
if 'Output' in dirnames:
dirnames.remove('Output')
for f in filenames:
base,ext = os.path.splitext(f)
if ext in kTestFileExtensions:
yield os.path.join(dirpath,f)
else:
if not os.path.isdir(path):
yield path
for dirpath,dirnames,filenames in os.walk(path):
# FIXME: This doesn't belong here
if 'Output' in dirnames:
dirnames.remove('Output')
for f in filenames:
base,ext = os.path.splitext(f)
if ext in kTestFileExtensions:
yield os.path.join(dirpath,f)
class TestingProgressDisplay:
def __init__(self, opts, numTests, progressBar=None):
self.opts = opts
@ -92,22 +84,21 @@ class TestingProgressDisplay:
else:
sys.stdout.write('\n')
extra = ''
if tr.code==TestStatus.Invalid:
extra = ' - (Invalid test)'
elif tr.failed():
extra = ' - %s'%(TestStatus.getName(tr.code).upper(),)
print '%*d/%*d - %s%s'%(self.digits, index+1, self.digits,
self.numTests, tr.path, extra)
status = TestStatus.getName(tr.code).upper()
print '%s: %s (%*d of %*d)' % (status, tr.path,
self.digits, index+1,
self.digits, self.numTests)
if tr.failed() and self.opts.showOutput:
TestRunner.cat(tr.testResults, sys.stdout)
print "%s TEST '%s' FAILED %s" % ('*'*20, tr.path, '*'*20)
print tr.output
print "*" * 20
class TestResult:
def __init__(self, path, code, testResults, elapsed):
def __init__(self, path, code, output, elapsed):
self.path = path
self.code = code
self.testResults = testResults
self.output = output
self.elapsed = elapsed
def failed(self):
@ -153,13 +144,8 @@ class Tester(threading.Thread):
break
self.runTest(item)
def runTest(self, (path,index)):
command = path
def runTest(self, (path, index)):
base = TestRunner.getTestOutputBase('Output', path)
output = base + '.out'
testname = path
testresults = base + '.testresults'
TestRunner.mkdir_p(os.path.dirname(testresults))
numTests = len(self.provider.tests)
digits = len(str(numTests))
code = None
@ -170,9 +156,8 @@ class Tester(threading.Thread):
code = None
else:
startTime = time.time()
code = TestRunner.runOneTest(path, command, output, testname,
opts.clang, opts.clangcc,
output=open(testresults,'w'))
code, output = TestRunner.runOneTest(path, base,
opts.clang, opts.clangcc)
elapsed = time.time() - startTime
except KeyboardInterrupt:
# This is a sad hack. Unfortunately subprocess goes
@ -180,8 +165,7 @@ class Tester(threading.Thread):
print 'Ctrl-C detected, goodbye.'
os.kill(0,9)
self.provider.setResult(index, TestResult(path, code, testresults,
elapsed))
self.provider.setResult(index, TestResult(path, code, output, elapsed))
def detectCPUs():
"""

Просмотреть файл

@ -57,54 +57,29 @@ def mkdir_p(path):
if e.errno != errno.EEXIST:
raise
def remove(path):
try:
os.remove(path)
except OSError:
pass
def cat(path, output):
f = open(path)
output.writelines(f)
f.close()
def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
output=sys.stdout):
OUTPUT = os.path.abspath(OUTPUT)
import StringIO
def runOneTest(testPath, tmpBase, clang, clangcc):
# Make paths absolute.
tmpBase = os.path.abspath(tmpBase)
testPath = os.path.abspath(testPath)
# Create the output directory if it does not already exist.
mkdir_p(os.path.dirname(OUTPUT))
scriptFile = FILENAME
# Verify the script contains a run line.
for ln in open(scriptFile):
if 'RUN:' in ln:
break
else:
print >>output, "******************** TEST '%s' HAS NO RUN LINE! ********************"%(TESTNAME,)
output.flush()
return TestStatus.Fail
FILENAME = os.path.abspath(FILENAME)
SCRIPT = OUTPUT + '.script'
mkdir_p(os.path.dirname(tmpBase))
script = tmpBase + '.script'
if kSystemName == 'Windows':
SCRIPT += '.bat'
TEMPOUTPUT = OUTPUT + '.tmp'
script += '.bat'
substitutions = [('%s',SUBST),
('%S',os.path.dirname(SUBST)),
('%llvmgcc','llvm-gcc -emit-llvm -w'),
('%llvmgxx','llvm-g++ -emit-llvm -w'),
('%prcontext','prcontext.tcl'),
('%t',TEMPOUTPUT),
(' clang ', ' ' + CLANG + ' '),
(' clang-cc ', ' ' + CLANGCC + ' ')]
substitutions = [('%s', testPath),
('%S', os.path.dirname(testPath)),
('%t', tmpBase + '.tmp'),
(' clang ', ' ' + clang + ' '),
(' clang-cc ', ' ' + clangcc + ' ')]
# Collect the test lines from the script.
scriptLines = []
xfailLines = []
for ln in open(scriptFile):
for ln in open(testPath):
if 'RUN:' in ln:
# Isolate the command to run.
index = ln.index('RUN:')
@ -117,6 +92,10 @@ def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
# FIXME: Support something like END, in case we need to process large
# files.
# Verify the script contains a run line.
if not scriptLines:
return (TestStatus.Fail, "Test has no run line!")
# Apply substitutions to the script.
def processLine(ln):
@ -133,19 +112,15 @@ def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
ln = scriptLines[i]
if not ln.endswith('&&'):
print >>output, "MISSING \'&&\': %s" % ln
print >>output, "FOLLOWED BY : %s" % scriptLines[i + 1]
return TestStatus.Fail
return (TestStatus.Fail,
"MISSING \'&&\': %s\n" +
"FOLLOWED BY : %s\n" % (ln,scriptLines[i + 1]))
# Strip off '&&'
scriptLines[i] = ln[:-2]
if xfailLines:
print >>output, "XFAILED '%s':"%(TESTNAME,)
output.writelines(xfailLines)
# Write script file
f = open(SCRIPT,'w')
f = open(script,'w')
if kSystemName == 'Windows':
f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(scriptLines))
else:
@ -153,52 +128,53 @@ def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
f.write('\n')
f.close()
outputFile = open(OUTPUT,'w')
p = None
try:
if kSystemName == 'Windows':
command = ['cmd','/c', SCRIPT]
command = ['cmd','/c', script]
else:
command = ['/bin/sh', SCRIPT]
command = ['/bin/sh', script]
p = subprocess.Popen(command,
cwd=os.path.dirname(FILENAME),
cwd=os.path.dirname(testPath),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=kChildEnv)
out,err = p.communicate()
outputFile.write(out)
outputFile.write(err)
SCRIPT_STATUS = p.wait()
exitCode = p.wait()
# Detect Ctrl-C in subprocess.
if SCRIPT_STATUS == -signal.SIGINT:
if exitCode == -signal.SIGINT:
raise KeyboardInterrupt
except KeyboardInterrupt:
raise
outputFile.close()
if xfailLines:
SCRIPT_STATUS = not SCRIPT_STATUS
if SCRIPT_STATUS:
print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
print >>output, "Command: "
output.writelines(scriptLines)
print >>output, "Incorrect Output:"
cat(OUTPUT, output)
print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
output.flush()
if xfailLines:
return TestStatus.XPass
else:
return TestStatus.Fail
if xfailLines:
return TestStatus.XFail
ok = exitCode != 0
status = (TestStatus.XPass, TestStatus.XFail)[ok]
else:
return TestStatus.Pass
ok = exitCode == 0
status = (TestStatus.Fail, TestStatus.Pass)[ok]
if ok:
return (status,'')
output = StringIO.StringIO()
print >>output, "Script:"
print >>output, "--"
print >>output, '\n'.join(scriptLines)
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 capture(args):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -304,14 +280,17 @@ def main():
opts.clangcc = inferClangCC(opts.clang)
for path in args:
command = path
output = getTestOutputBase('Output', path) + '.out'
testname = path
base = getTestOutputBase('Output', path) + '.out'
res = runOneTest(path, command, output, testname,
opts.clang, opts.clangcc)
status,output = runOneTest(path, base, opts.clang, opts.clangcc)
print '%s: %s' % (TestStatus.getName(status).upper(), path)
if status == TestStatus.Fail or status == TestStatus.XPass:
print "%s TEST '%s' FAILED %s" % ('*'*20, path, '*'*20)
sys.stdout.write(output)
print "*" * 20
sys.exit(1)
sys.exit(res == TestStatus.Fail or res == TestStatus.XPass)
sys.exit(0)
if __name__=='__main__':
main()