aos/tools/harness/harness.py
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

176 lines
6.9 KiB
Python
Executable File

#
# Copyright (c) 2009-2011, ETH Zurich.
# All rights reserved.
#
# This file is distributed under the terms in the attached LICENSE file.
# If you do not find this file, copies can be found by writing to:
# ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
#
import os
import types
import string
import datetime
import debug
import re
class Harness:
RAW_FILE_NAME = 'raw.txt'
MENU_LST_FILE_NAME = 'menu.lst'
BOOT_FILE_NAME = 'bootlog.txt'
TERM_FILTER = re.compile("\[\d\d?m")
def _clean_line(self, line):
# filter output line of control characters
filtered_out = filter(lambda c: c in string.printable, line.rstrip())
# Delete terminal color codes from output
filtered_out = self.TERM_FILTER.sub('', filtered_out)
return filtered_out
def _write_menu_lst_debug(self, test, build, machine, path):
# Ignore for tests that do not implement get_modules
if hasattr(test, "get_modules"):
menu_lst_file_name = os.path.join(path, self.MENU_LST_FILE_NAME)
debug.verbose("harness: writing menu.lst to %s" % menu_lst_file_name)
with open(menu_lst_file_name, "w") as menu:
menu.write( test.get_modules(build, machine).get_menu_data("/") )
def run_test(self, build, machine, test, path):
# Open files for raw output from the victim and log data from the test
raw_file_name = os.path.join(path, self.RAW_FILE_NAME)
debug.verbose('open %s for raw output' % raw_file_name)
raw_file = open(raw_file_name, 'w')
# run the test, dumping the output to the raw file as we go
try:
debug.verbose('harness: setup test')
test.setup(build, machine, path)
self._write_menu_lst_debug(test, build, machine, path)
debug.verbose('harness: run test')
starttime = datetime.datetime.now()
for out in test.run(build, machine, path):
# timedelta for the time this line was emitted from the start of the run
timestamp = datetime.datetime.now() - starttime
# format as string, discarding sub-second precision
timestr = str(timestamp).split('.', 1)[0]
debug.debug('[%s] %s' % (timestr, self._clean_line(out)))
# log full raw line (without timestamp) to output file
raw_file.write(out)
debug.verbose('harness: output complete')
except KeyboardInterrupt:
# let the user know that we are on our way out
debug.error('Interrupted! Performing cleanup...')
raise
finally:
raw_file.close()
debug.verbose('harness: cleanup test')
test.cleanup(machine)
def process_output(self, test, path):
"""Process raw.txt and return array of output lines that begins with grubs
output, avoids having encoding issues when generating other report files"""
raw_file_name = os.path.join(path, self.RAW_FILE_NAME)
if os.path.exists(raw_file_name):
idx = 0
with open(raw_file_name, 'r') as rf:
lines = rf.readlines()
for idx, line in enumerate(lines):
if line.strip() == "root (nd)" or \
line.strip().startswith("Kernel starting at address") or \
"Barrelfish CPU driver starting on ARMv8" in line:
break
if idx == len(lines)-1:
debug.verbose('magic string "root (nd)" or "Kernel starting at address" not found, assuming no garbage in output')
idx=0
return [ unicode(self._clean_line(l), errors='replace') for l in lines[idx:] ]
# file did not exist
return ["could not open %s to process test output" % raw_file_name]
def extract_errors(self, test, path):
raw_file_name = os.path.join(path, self.RAW_FILE_NAME)
debug.verbose('open %s for raw input' % raw_file_name)
raw_file = open(raw_file_name, 'r')
try:
results = test.process_data(path, raw_file)
finally:
raw_file.close()
errors = [results.reason()]
try:
errors += results.errors
except:
pass
return errors
def process_results(self, test, path):
# open raw file for input processing
raw_file_name = os.path.join(path, self.RAW_FILE_NAME)
debug.verbose('open %s for raw input' % raw_file_name)
raw_file = open(raw_file_name, 'r')
try:
results = test.process_data(path, raw_file)
finally:
raw_file.close()
if not results:
debug.verbose('no results')
return True # no results, assume success
retval = True # everything OK
# Process raw.txt and make a bootlog.txt that begins with grubs or
# Barrelfish's output, avoids having encoding issues when viewing logfiles
boot_file_name = os.path.join(path, self.BOOT_FILE_NAME)
if os.path.exists(raw_file_name):
idx = 0
with open(raw_file_name, 'r') as rf:
lines = rf.readlines()
for idx, line in enumerate(lines):
if line.strip() == "root (nd)" or \
"Barrelfish CPU driver starting" in line.strip():
break
if idx > 0:
with open(boot_file_name, 'w') as wf:
wf.writelines(lines[idx:])
else:
debug.verbose('Magic string root (nd) not found, do not write bootlog.txt')
else:
debug.verbose('No file named %s exists. Do not create bootlog.txt.' % raw_file_name)
# if a single result, turn it into a list
if not isinstance(results, types.ListType):
results = [results]
for result in results:
# see if it passed
try:
passed = result.passed()
except NotImplementedError:
passed = None
if passed is False:
debug.log('Test %s FAILED %s' % (test.name, '(' + result.reason() + ')') )
retval = False
elif passed:
debug.verbose('Test %s PASSED' % test.name)
# write it to a file
name = result.name if result.name else 'results'
data_file_name = os.path.join(path, name + '.dat')
debug.verbose('create %s for processed output' % data_file_name)
data_file = open(data_file_name, 'w')
try:
result.to_file(data_file)
data_file.close()
except NotImplementedError:
debug.verbose('no processed output, remove %s' % data_file_name)
data_file.close()
os.remove(data_file_name)
return retval