js/src/tests/lib/tests.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/tests/lib/tests.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,154 @@
     1.4 +# Library for JSTest tests.
     1.5 +#
     1.6 +# This contains classes that represent an individual test, including
     1.7 +# metadata, and know how to run the tests and determine failures.
     1.8 +
     1.9 +import datetime, os, sys, time
    1.10 +from subprocess import Popen, PIPE
    1.11 +from threading import Thread
    1.12 +
    1.13 +from results import TestOutput
    1.14 +
    1.15 +# When run on tbpl, we run each test multiple times with the following arguments.
    1.16 +TBPL_FLAGS = [
    1.17 +    [], # no flags, normal baseline and ion
    1.18 +    ['--ion-eager', '--ion-parallel-compile=off'], # implies --baseline-eager
    1.19 +    ['--ion-eager', '--ion-parallel-compile=off', '--ion-check-range-analysis', '--no-sse3'],
    1.20 +    ['--baseline-eager'],
    1.21 +    ['--baseline-eager', '--no-fpu'],
    1.22 +    ['--no-baseline', '--no-ion'],
    1.23 +]
    1.24 +
    1.25 +def do_run_cmd(cmd):
    1.26 +    l = [ None, None ]
    1.27 +    th_run_cmd(cmd, l)
    1.28 +    return l[1]
    1.29 +
    1.30 +def set_limits():
    1.31 +    # resource module not supported on all platforms
    1.32 +    try:
    1.33 +        import resource
    1.34 +        GB = 2**30
    1.35 +        resource.setrlimit(resource.RLIMIT_AS, (2*GB, 2*GB))
    1.36 +    except:
    1.37 +        return
    1.38 +
    1.39 +def th_run_cmd(cmd, l):
    1.40 +    t0 = datetime.datetime.now()
    1.41 +
    1.42 +    # close_fds and preexec_fn are not supported on Windows and will
    1.43 +    # cause a ValueError.
    1.44 +    options = {}
    1.45 +    if sys.platform != 'win32':
    1.46 +        options["close_fds"] = True
    1.47 +        options["preexec_fn"] = set_limits
    1.48 +    p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
    1.49 +
    1.50 +    l[0] = p
    1.51 +    out, err = p.communicate()
    1.52 +    t1 = datetime.datetime.now()
    1.53 +    dd = t1-t0
    1.54 +    dt = dd.seconds + 1e-6 * dd.microseconds
    1.55 +    l[1] = (out, err, p.returncode, dt)
    1.56 +
    1.57 +def run_cmd(cmd, timeout=60.0):
    1.58 +    if timeout is None:
    1.59 +        return do_run_cmd(cmd)
    1.60 +
    1.61 +    l = [ None, None ]
    1.62 +    timed_out = False
    1.63 +    th = Thread(target=th_run_cmd, args=(cmd, l))
    1.64 +    th.start()
    1.65 +    th.join(timeout)
    1.66 +    while th.isAlive():
    1.67 +        if l[0] is not None:
    1.68 +            try:
    1.69 +                # In Python 3, we could just do l[0].kill().
    1.70 +                import signal
    1.71 +                if sys.platform != 'win32':
    1.72 +                    os.kill(l[0].pid, signal.SIGKILL)
    1.73 +                time.sleep(.1)
    1.74 +                timed_out = True
    1.75 +            except OSError:
    1.76 +                # Expecting a "No such process" error
    1.77 +                pass
    1.78 +    th.join()
    1.79 +    return l[1] + (timed_out,)
    1.80 +
    1.81 +class Test(object):
    1.82 +    """A runnable test."""
    1.83 +    def __init__(self, path):
    1.84 +        self.path = path         # str:  path of JS file relative to tests root dir
    1.85 +
    1.86 +    @staticmethod
    1.87 +    def prefix_command(path):
    1.88 +        """Return the '-f shell.js' options needed to run a test with the given path."""
    1.89 +        if path == '':
    1.90 +            return [ '-f', 'shell.js' ]
    1.91 +        head, base = os.path.split(path)
    1.92 +        return Test.prefix_command(head) + [ '-f', os.path.join(path, 'shell.js') ]
    1.93 +
    1.94 +    def get_command(self, js_cmd_prefix):
    1.95 +        dirname, filename = os.path.split(self.path)
    1.96 +        cmd = js_cmd_prefix + self.options + Test.prefix_command(dirname) + [ '-f', self.path ]
    1.97 +        return cmd
    1.98 +
    1.99 +    def run(self, js_cmd_prefix, timeout=30.0):
   1.100 +        cmd = self.get_command(js_cmd_prefix)
   1.101 +        out, err, rc, dt, timed_out = run_cmd(cmd, timeout)
   1.102 +        return TestOutput(self, cmd, out, err, rc, dt, timed_out)
   1.103 +
   1.104 +class TestCase(Test):
   1.105 +    """A test case consisting of a test and an expected result."""
   1.106 +    js_cmd_prefix = None
   1.107 +
   1.108 +    def __init__(self, path):
   1.109 +        Test.__init__(self, path)
   1.110 +        self.enable = True   # bool: True => run test, False => don't run
   1.111 +        self.expect = True   # bool: expected result, True => pass
   1.112 +        self.random = False  # bool: True => ignore output as 'random'
   1.113 +        self.slow = False    # bool: True => test may run slowly
   1.114 +        self.options = []    # [str]: Extra options to pass to the shell
   1.115 +
   1.116 +        # The terms parsed to produce the above properties.
   1.117 +        self.terms = None
   1.118 +
   1.119 +        # The tag between |...| in the test header.
   1.120 +        self.tag = None
   1.121 +
   1.122 +        # Anything occuring after -- in the test header.
   1.123 +        self.comment = None
   1.124 +
   1.125 +    def __str__(self):
   1.126 +        ans = self.path
   1.127 +        if not self.enable:
   1.128 +            ans += ', skip'
   1.129 +        if not self.expect:
   1.130 +            ans += ', fails'
   1.131 +        if self.random:
   1.132 +            ans += ', random'
   1.133 +        if self.slow:
   1.134 +            ans += ', slow'
   1.135 +        if '-d' in self.options:
   1.136 +            ans += ', debugMode'
   1.137 +        return ans
   1.138 +
   1.139 +    @classmethod
   1.140 +    def set_js_cmd_prefix(self, js_path, js_args, debugger_prefix):
   1.141 +        parts = []
   1.142 +        if debugger_prefix:
   1.143 +            parts += debugger_prefix
   1.144 +        parts.append(js_path)
   1.145 +        if js_args:
   1.146 +            parts += js_args
   1.147 +        self.js_cmd_prefix = parts
   1.148 +
   1.149 +    def __cmp__(self, other):
   1.150 +        if self.path == other.path:
   1.151 +            return 0
   1.152 +        elif self.path < other.path:
   1.153 +            return -1
   1.154 +        return 1
   1.155 +
   1.156 +    def __hash__(self):
   1.157 +        return self.path.__hash__()

mercurial