This adds support for running XTS from piglit. This patch was original written by Eric Anholt, but I've cleaned it up and reworked parts of it for upstreaming, and as a result I've attached my name as the author so ``git bisect'' and ``git blame'' will send angry mail my way instead of Eric's.
Signed-off-by: Dylan Baker <[email protected]> --- framework/exectest.py | 7 +- framework/summary.py | 3 +- templates/test_result.mako | 27 +++++- tests/xts.py | 206 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 237 insertions(+), 6 deletions(-) create mode 100644 tests/xts.py diff --git a/framework/exectest.py b/framework/exectest.py index c6c5067..3648c6d 100644 --- a/framework/exectest.py +++ b/framework/exectest.py @@ -234,9 +234,10 @@ class Test(object): if env: results['environment'] = env - results['info'] = unicode("Returncode: {0}\n\nErrors:\n{1}\n\n" - "Output:\n{2}").format(returncode, - err, out) + results['info'] = \ + unicode("Returncode: {0}\n\nErrors:\n{1}\n\n" + "Output:\n{2}").format(returncode, err, out) + \ + results.get('info', '') results['returncode'] = returncode results['command'] = ' '.join(self.command) diff --git a/framework/summary.py b/framework/summary.py index 6d2a7bb..51923ad 100644 --- a/framework/summary.py +++ b/framework/summary.py @@ -423,7 +423,8 @@ class Summary: info=value.get('info', 'None'), traceback=value.get('traceback', 'None'), command=value.get('command', 'None'), - dmesg=dmesg, + images=value.get('images', None), + dmesg=value.get('dmesg', None), css=path.relpath(result_css, temp_path), index=path.relpath(index, temp_path))) diff --git a/templates/test_result.mako b/templates/test_result.mako index 490c009..c8d9ea8 100644 --- a/templates/test_result.mako +++ b/templates/test_result.mako @@ -28,20 +28,41 @@ <td>Time</td> <td>${time}</b> </tr> + % if images: + <tr> + <td>Images</td> + <td> + <table> + <tr> + <td/> + <td>reference</td> + <td>rendered</td> + </tr> + % for image in images: + <tr> + <td>${image['image_desc']}</td> + <td><img src="file://${image['image_ref']}" /></td> + <td><img src="file://${image['image_render']}" /></td> + </tr> + % endfor + </table> + </td> + </tr> + % endif <tr> <td>Info</td> <td> <pre>${info | h}</pre> </td> </tr> - % if env: + % if env: <tr> <td>Environment</td> <td> <pre>${env | h}</pre> </td> </tr> - % endif + % endif <tr> <td>Command</td> <td> @@ -54,12 +75,14 @@ <pre>${traceback | h}</pre> </td> </tr> + % if dmesg: <tr> <td>dmesg</td> <td> <pre>${dmesg | h}</pre> </td> </tr> + % endif </table> <p><a href="${index}">Back to summary</a></p> </body> diff --git a/tests/xts.py b/tests/xts.py new file mode 100644 index 0000000..1325023 --- /dev/null +++ b/tests/xts.py @@ -0,0 +1,206 @@ +# Copyright (c) 2013-2014 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# This permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR(S) BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +""" Test integreation for the X Test Suite """ + +import os +import re +import sys +import subprocess +import itertools +from framework.core import TestProfile +from framework.exectest import Test, testBinDir + +__all__ = ['profile'] + + +class XTSProfile(TestProfile): + """ A sublcass of TestProfile that provides a setup hook for XTS """ + def pre_run_hook(self): + """ This hook sets the XTSTest.results_path variable + + Setting this variable allows images created by XTS to moved into the + results directory + + """ + XTSTest.RESULTS_PATH = self.results_dir + + try: + os.mkdir(os.path.join(self.results_dir, 'images')) + except OSError as e: + # If the exception is not 'directory already exists', raise the + # exception + if e.errno != 17: + raise + + +class XTSTest(Test): + """ X Test Suite class + + Runs a single test or subtest from XTS. For best results it's recomended + that you run this using Xephyr, the nested x-server + + Arguments: + name -- the name of the test + testname -- the name of the test file + testnum -- the number of the test file + + """ + RESULTS_PATH = None + + def __init__(self, name, testname, testnum): + super(XTSTest, self).__init__( + ['./' + os.path.basename(name), '-i', str(testnum)]) + self.testname = '{0}-{1}'.format(testname, testnum) + self.cwd = os.path.dirname(os.path.realpath(name)) + self.test_results_file = os.path.join(self.cwd, self.testname) + self.env.update( + {"TET_RESFILE": self.test_results_file, + "XT_RESET_DELAY": '0', + "XT_FONTPATH_GOOD": '/usr/share/fonts/X11/misc', + "XT_FONTPATH": os.path.join(X_TEST_SUITE, 'xts5', 'fonts'), + #XXX: Are the next 3 necissary + "XT_LOCAL": 'Yes', + "XT_TCP": 'No', + "XT_DISPLAYHOST": ''}) + + def __process_log_for_images(self, log): + """ Parse the image logfile """ + images = [] + search = re.compile('See file (Err[0-9]+.err)') + + for line in log.splitlines(): + match = search.search(line) + if match is not None: + # Can we parse any other useful information out to give a + # better description of each image? + desc = match.group(1) + + # The error logs are text, with a header with width, height, + # and depth, then run-length-encoded pixel values (in + # hexadecimal). Use xtsttopng to convert the error log to a + # pair of PNGs so we can put them in the summary. + command = ['xtsttopng', os.path.join(self.cwd, match.group(1))] + try: + out = subprocess.check_output(command, cwd=self.cwd) + except OSError: + images.append({'image_desc': 'image processing failed'}) + continue + + # Each Err*.err log contains a rendered image, and a reference + # image that it was compared to. We relocate the to our tree + # with more useful names. (Otherwise, since tests generate + # error logs with numbers sequentially starting from 0, each + # subtest with an error would overwrite the previous test's + # images). + # + # XXX: This *should* be sending the images to the results + # directory, but since nothing fails on my system (and I cant + # hack on the test suite I can't know for sure + ref_path = '{0}/images/{1}-{2}-ref.png'.format( + XTSTest.RESULTS_PATH, self.testname, match.group(1)) + render_path = '{0}/images/{1}-{2}-render.png'.format( + XTSTest.RESULTS_PATH, self.testname, match.group(1)) + + split = out.splitlines() + os.rename(os.path.join(self.cwd, split[0]), render_path) + os.rename(os.path.join(self.cwd, split[1]), ref_path) + + images.append({'image_desc': desc, + 'image_ref': ref_path, + 'image_render': render_path}) + + return images + + def interpretResult(self, out, returncode, results): + try: + with open(self.test_results_file, 'r') as rfile: + log = rfile.read() + results['info'] = log + os.remove(self.test_results_file) + except IOError: + results['info'] = "No results file found" + + if returncode == 0: + if re.search('FAIL', out) is not None: + results['result'] = 'fail' + elif re.search('PASS', out) is not None: + results['result'] = 'pass' + else: + results['result'] = 'fail' + elif returncode == 77: + results['result'] = 'skip' + elif returncode == 1: + if re.search('Could not open all VSW5 fonts', log): + results['result'] = 'warn' + else: + results['result'] = 'fail' + else: + results['result'] = 'fail' + + results['images'] = self.__process_log_for_images(log) + + return out + + +def populate_profile(): + """ Populate the profile attribute """ + # Add all tests to the profile + profile = XTSProfile() + fpath = os.path.join(X_TEST_SUITE, 'xts5') + for dirpath, _, filenames in os.walk(fpath): + for fname in filenames: + # only look at the .m test files + testname, ext = os.path.splitext(fname) + if ext != '.m': + continue + + # incrementing number generator + counts = (x for x in itertools.count(1, 1)) + + # Walk the file looking for >>ASSERTION, each of these corresponds + # to a generated subtest, there can be multiple subtests per .m + # file + with open(os.path.join(dirpath, fname), 'r') as rfile: + for line in rfile: + if line.startswith('>>ASSERTION'): + num = next(counts) + group = '{0}/{1}/{2}'.format( + os.path.relpath(dirpath, X_TEST_SUITE), + testname, num) + + profile.tests[group] = XTSTest( + os.path.join(dirpath, testname), + testname, + num) + return profile + + +X_TEST_SUITE = os.path.join(testBinDir, 'xtest') + +profile = populate_profile() + +# If the symlink for the XTS has not been created exit +if not os.path.exists(X_TEST_SUITE): + print "xtest symlink not found!" + sys.exit(0) -- 1.9.1 _______________________________________________ Piglit mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/piglit
