summaryrefslogtreecommitdiff
path: root/test/run-tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/run-tests.py')
-rwxr-xr-xtest/run-tests.py167
1 files changed, 93 insertions, 74 deletions
diff --git a/test/run-tests.py b/test/run-tests.py
index 63a5bb91..6d559e7d 100755
--- a/test/run-tests.py
+++ b/test/run-tests.py
@@ -31,19 +31,18 @@ import shlex
import shutil
import subprocess
import sys
-import tempfile
import threading
import time
import find_exe
-import findtests
from utils import Error
IS_WINDOWS = sys.platform == 'win32'
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-REPO_ROOT_DIR = os.path.dirname(SCRIPT_DIR)
-ROUNDTRIP_PY = os.path.join(SCRIPT_DIR, 'run-roundtrip.py')
+TEST_DIR = os.path.dirname(os.path.abspath(__file__))
+REPO_ROOT_DIR = os.path.dirname(TEST_DIR)
+OUT_DIR = os.path.join(REPO_ROOT_DIR, 'out')
+ROUNDTRIP_PY = os.path.join(TEST_DIR, 'run-roundtrip.py')
DEFAULT_TIMEOUT = 10 # seconds
SLOW_TIMEOUT_MULTIPLIER = 2
@@ -257,12 +256,10 @@ def RunCommandWithTimeout(command, cwd, timeout, console_out=False):
class TestInfo(object):
def __init__(self):
- self.name = ''
- self.generated_input_filename = ''
self.filename = ''
self.header = []
self.input_filename = ''
- self.input_ = []
+ self.input_ = ''
self.expected_stdout = ''
self.expected_stderr = ''
self.tool = 'wast2wasm'
@@ -276,8 +273,6 @@ class TestInfo(object):
def CreateRoundtripInfo(self):
result = TestInfo()
- result.name = '%s (roundtrip)' % self.name
- result.generated_input_filename = AppendBeforeExt(self.name, '-roundtrip')
result.filename = self.filename
result.header = self.header
result.input_filename = self.input_filename
@@ -294,6 +289,25 @@ class TestInfo(object):
result.is_roundtrip = True
return result
+ def GetName(self):
+ name = self.filename
+ if self.is_roundtrip:
+ name += ' (roundtrip)'
+ return name
+
+ def GetGeneratedInputFilename(self):
+ path = OUT_DIR
+ if self.input_filename:
+ path = os.path.join(path, self.input_filename)
+ else:
+ path = os.path.join(path, self.filename)
+
+ if self.is_roundtrip:
+ dirname = os.path.dirname(path)
+ basename = os.path.basename(path)
+ path = os.path.join(dirname, 'roundtrip', basename)
+ return path
+
def ShouldCreateRoundtrip(self):
return self.tool in ROUNDTRIP_TOOLS
@@ -302,7 +316,6 @@ class TestInfo(object):
self.exe = value
elif key == 'STDIN_FILE':
self.input_filename = value
- self.generated_input_filename = value
elif key == 'FLAGS':
self.flags += shlex.split(value)
elif key == 'ERROR':
@@ -325,11 +338,10 @@ class TestInfo(object):
raise Error('Unknown directive: %s' % key)
def Parse(self, filename):
- self.name = filename
- self.filename = os.path.join(SCRIPT_DIR, filename)
- self.generated_input_filename = self.name
+ self.filename = filename
- with open(self.filename) as f:
+ test_path = os.path.join(REPO_ROOT_DIR, filename)
+ with open(test_path) as f:
seen_keys = set()
state = 'header'
empty = True
@@ -411,32 +423,31 @@ class TestInfo(object):
self.last_cmd = cmd
return cmd
- def CreateInputFile(self, temp_dir):
- file_path = os.path.join(temp_dir, self.generated_input_filename)
- file_dir = os.path.dirname(file_path)
+ def CreateInputFile(self):
+ gen_input_path = self.GetGeneratedInputFilename()
+ gen_input_dir = os.path.dirname(gen_input_path)
try:
- os.makedirs(file_dir)
+ os.makedirs(gen_input_dir)
except OSError as e:
- if not os.path.isdir(file_dir):
+ if not os.path.isdir(gen_input_dir):
raise
- file_ = open(file_path, 'wb')
- # add an empty line for each header line so the line numbers match
- if self.input_filename:
- with open(self.input_filename, 'rb') as input_filename:
- file_.write(input_filename.read())
- else:
- file_.write(('\n' * self.header.count('\n')).encode('ascii'))
- file_.write(self.input_.encode('ascii'))
- file_.flush()
- file_.close()
-
- # make filenames relative to temp_dir so the autogenerated name is not
- # included in the error output.
- return os.path.relpath(file_.name, temp_dir)
+ # Read/write as binary because spec tests may have invalid UTF-8 codes.
+ with open(gen_input_path, 'wb') as gen_input_file:
+ if self.input_filename:
+ input_path = os.path.join(REPO_ROOT_DIR, self.input_filename)
+ with open(input_path, 'rb') as input_file:
+ gen_input_file.write(input_file.read())
+ else:
+ # add an empty line for each header line so the line numbers match
+ gen_input_file.write(('\n' * self.header.count('\n')).encode('ascii'))
+ gen_input_file.write(self.input_.encode('ascii'))
+ gen_input_file.flush()
+ return gen_input_file.name
def Rebase(self, stdout, stderr):
- with open(self.filename, 'wb') as f:
+ test_path = os.path.join(REPO_ROOT_DIR, self.filename)
+ with open(test_path, 'w', newline='') as f:
f.write(self.header)
f.write(self.input_)
if stderr:
@@ -483,7 +494,7 @@ class Status(object):
def Passed(self, info, duration):
self.passed += 1
if self.verbose:
- sys.stderr.write('+ %s (%.3fs)\n' % (info.name, duration))
+ sys.stderr.write('+ %s (%.3fs)\n' % (info.GetName(), duration))
else:
self.Clear()
self._PrintShortStatus(info)
@@ -494,12 +505,12 @@ class Status(object):
self.failed_tests.append(info)
if not self.verbose:
self.Clear()
- sys.stderr.write('- %s\n%s\n' % (info.name, Indent(error_msg, 2)))
+ sys.stderr.write('- %s\n%s\n' % (info.GetName(), Indent(error_msg, 2)))
def Skipped(self, info):
self.skipped += 1
if self.verbose:
- sys.stderr.write('. %s (skipped)\n' % info.name)
+ sys.stderr.write('. %s (skipped)\n' % info.GetName())
def UpdateTimer(self):
self._PrintShortStatus(self.last_finished)
@@ -510,7 +521,7 @@ class Status(object):
def _PrintShortStatus(self, info):
total_duration = time.time() - self.start_time
- name = info.name if info else ''
+ name = info.GetName() if info else ''
if (self.total - self.skipped):
percent = 100 * (self.passed + self.failed) / (self.total - self.skipped)
else:
@@ -526,6 +537,17 @@ class Status(object):
sys.stderr.write('%s\r' % (' ' * self.last_length))
+def FindTestFiles(ext, filter_pattern_re):
+ tests = []
+ for root, dirs, files in os.walk(TEST_DIR):
+ for f in files:
+ path = os.path.join(root, f)
+ if os.path.splitext(f)[1] == ext:
+ tests.append(os.path.relpath(path, REPO_ROOT_DIR))
+ tests.sort()
+ return [test for test in tests if re.match(filter_pattern_re, test)]
+
+
def GetAllTestInfo(test_names, status):
infos = []
for test_name in test_names:
@@ -535,23 +557,29 @@ def GetAllTestInfo(test_names, status):
infos.append(info)
except Error as e:
status.Failed(info, str(e))
-
return infos
+
def RunTest(info, options, variables, verbose_level = 0):
timeout = options.timeout
if info.slow:
timeout *= SLOW_TIMEOUT_MULTIPLIER
+ # Clone variables dict so it can be safely modified.
+ variables = dict(variables)
+
try:
- rel_file_path = info.CreateInputFile(variables['out_dir'])
- cmd = info.GetCommand(rel_file_path, variables, options.arg, verbose_level)
- out = RunCommandWithTimeout(cmd, variables['out_dir'], timeout,
- verbose_level > 0)
- return out
+ cwd = REPO_ROOT_DIR
+ gen_input_path = info.CreateInputFile()
+ rel_gen_input_path = os.path.relpath(gen_input_path, cwd)
+ variables['out_dir'] = os.path.dirname(rel_gen_input_path)
+ cmd = info.GetCommand(rel_gen_input_path, variables, options.arg,
+ verbose_level)
+ return RunCommandWithTimeout(cmd, cwd, timeout, verbose_level > 0)
except Exception as e:
return e
+
def ThreadWorker(i, options, variables, inq, outq, should_run):
try:
while should_run.Get():
@@ -567,6 +595,7 @@ def ThreadWorker(i, options, variables, inq, outq, should_run):
except KeyboardInterrupt:
pass
+
def HandleTestResult(status, info, result, rebase=False):
try:
if isinstance(result, Exception):
@@ -601,6 +630,7 @@ def HandleTestResult(status, info, result, rebase=False):
except Exception as e:
status.Failed(info, str(e))
+
#Source : http://stackoverflow.com/questions/3041986/python-command-line-yes-no-input
def YesNoPrompt(question, default='yes'):
"""Ask a yes/no question via raw_input() and return their answer.
@@ -634,15 +664,12 @@ def YesNoPrompt(question, default='yes'):
sys.stdout.write('Please respond with \'yes\' or \'no\' '
'(or \'y\' or \'n\').\n')
-def WaitWorkersTerminate(workers, timeout=5):
- for worker in workers:
- if worker.is_alive():
- worker.join(timeout)
-def RunMultiThreaded(infos_to_run, test_count, status, options, variables):
+def RunMultiThreaded(infos_to_run, status, options, variables):
should_stop_on_error = options.stop_interactive
continued_errors = 0
num_threads = options.jobs
+ test_count = len(infos_to_run)
all_threads = []
try:
@@ -676,7 +703,10 @@ def RunMultiThreaded(infos_to_run, test_count, status, options, variables):
continued_errors += 1
finally:
should_run.Set(False)
- WaitWorkersTerminate(all_threads)
+ for thread in all_threads:
+ if thread.is_alive():
+ thread.join(timeout=5)
+
def RunSingleThreaded(infos_to_run, status, options, variables):
continued_errors = 0
@@ -700,6 +730,7 @@ def RunSingleThreaded(infos_to_run, status, options, variables):
RunTest(info, options, variables, verbose_level=1)
continued_errors += 1
+
def GetDefaultJobCount():
cpu_count = multiprocessing.cpu_count()
if cpu_count <= 1:
@@ -707,13 +738,12 @@ def GetDefaultJobCount():
else:
return cpu_count // 2
+
def main(args):
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--arg',
help='additional args to pass to executable',
action='append')
- parser.add_argument('-o', '--out-dir', metavar='PATH',
- help='output directory for files.')
parser.add_argument('--exe-dir', metavar='PATH',
help='directory to search for all executables. '
'This can be overridden by the other executable '
@@ -759,7 +789,7 @@ def main(args):
else:
pattern_re = '.*'
- test_names = findtests.FindTestFiles(SCRIPT_DIR, '.txt', pattern_re)
+ test_names = FindTestFiles('.txt', pattern_re)
if options.list:
for test_name in test_names:
@@ -770,7 +800,7 @@ def main(args):
return 1
variables = {}
- variables['test_dir'] = os.path.abspath(SCRIPT_DIR)
+ variables['test_dir'] = os.path.abspath(TEST_DIR)
for exe_basename in find_exe.EXECUTABLES:
attr_name = exe_basename.replace('-', '_')
@@ -792,33 +822,21 @@ def main(args):
continue
infos_to_run.append(info)
- if options.roundtrip:
- if info.ShouldCreateRoundtrip():
- infos_to_run.append(info.CreateRoundtripInfo())
+ if options.roundtrip and info.ShouldCreateRoundtrip():
+ infos_to_run.append(info.CreateRoundtripInfo())
- test_count = len(infos_to_run)
- status.Start(test_count)
+ if not os.path.exists(OUT_DIR):
+ os.makedirs(OUT_DIR)
- if options.out_dir:
- out_dir = options.out_dir
- out_dir_is_temp = False
- if not os.path.exists(out_dir):
- os.makedirs(out_dir)
- else:
- out_dir = tempfile.mkdtemp(prefix='wabt-')
- out_dir_is_temp = True
- variables['out_dir'] = os.path.abspath(out_dir)
+ status.Start(len(infos_to_run))
try:
if options.jobs > 1:
- RunMultiThreaded(infos_to_run, test_count, status, options, variables)
+ RunMultiThreaded(infos_to_run, status, options, variables)
else:
RunSingleThreaded(infos_to_run, status, options, variables)
except KeyboardInterrupt:
print('\nInterrupted testing\n')
- finally:
- if out_dir_is_temp:
- shutil.rmtree(out_dir)
status.Clear()
@@ -827,7 +845,8 @@ def main(args):
if status.failed:
sys.stderr.write('**** FAILED %s\n' % ('*' * (80 - 14)))
for info in status.failed_tests:
- sys.stderr.write('- %s\n %s\n' % (info.name, ' '.join(info.last_cmd)))
+ sys.stderr.write('- %s\n %s\n' % (info.GetName(),
+ ' '.join(info.last_cmd)))
ret = 1
status.Print()