js/src/tests/lib/jittests.py

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rwxr-xr-x

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 #!/usr/bin/env python
     2 # This Source Code Form is subject to the terms of the Mozilla Public
     3 # License, v. 2.0. If a copy of the MPL was not distributed with this
     4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     7 # jit_test.py -- Python harness for JavaScript trace tests.
     9 from __future__ import print_function
    10 import os, posixpath, sys, tempfile, traceback, time
    11 import subprocess
    12 from subprocess import Popen, PIPE
    13 from threading import Thread
    14 import signal
    15 import StringIO
    17 try:
    18     from multiprocessing import Process, Manager, cpu_count
    19     HAVE_MULTIPROCESSING = True
    20 except ImportError:
    21     HAVE_MULTIPROCESSING = False
    23 from progressbar import ProgressBar, NullProgressBar
    24 from results import TestOutput
    26 TESTS_LIB_DIR = os.path.dirname(os.path.abspath(__file__))
    27 JS_DIR = os.path.dirname(os.path.dirname(TESTS_LIB_DIR))
    28 TOP_SRC_DIR = os.path.dirname(os.path.dirname(JS_DIR))
    29 TEST_DIR = os.path.join(JS_DIR, 'jit-test', 'tests')
    30 LIB_DIR = os.path.join(JS_DIR, 'jit-test', 'lib') + os.path.sep
    31 JS_CACHE_DIR = os.path.join(JS_DIR, 'jit-test', '.js-cache')
    32 JS_TESTS_DIR = posixpath.join(JS_DIR, 'tests')
    34 # Backported from Python 3.1 posixpath.py
    35 def _relpath(path, start=None):
    36     """Return a relative version of a path"""
    38     if not path:
    39         raise ValueError("no path specified")
    41     if start is None:
    42         start = os.curdir
    44     start_list = os.path.abspath(start).split(os.sep)
    45     path_list = os.path.abspath(path).split(os.sep)
    47     # Work out how much of the filepath is shared by start and path.
    48     i = len(os.path.commonprefix([start_list, path_list]))
    50     rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
    51     if not rel_list:
    52         return os.curdir
    53     return os.path.join(*rel_list)
    55 os.path.relpath = _relpath
    57 class Test:
    59     VALGRIND_CMD = []
    60     paths = (d for d in os.environ['PATH'].split(os.pathsep))
    61     valgrinds = (os.path.join(d, 'valgrind') for d in paths)
    62     if any(os.path.exists(p) for p in valgrinds):
    63         VALGRIND_CMD = [
    64             'valgrind', '-q', '--smc-check=all-non-file',
    65             '--error-exitcode=1', '--gen-suppressions=all',
    66             '--show-possibly-lost=no', '--leak-check=full',
    67         ]
    68         if os.uname()[0] == 'Darwin':
    69             VALGRIND_CMD.append('--dsymutil=yes')
    71     del paths
    72     del valgrinds
    74     def __init__(self, path):
    75         # Absolute path of the test file.
    76         self.path = path
    78         # Path relative to the top mozilla/ directory.
    79         self.relpath_top = os.path.relpath(path, TOP_SRC_DIR)
    81         # Path relative to mozilla/js/src/jit-test/tests/.
    82         self.relpath_tests = os.path.relpath(path, TEST_DIR)
    84         self.jitflags = []     # jit flags to enable
    85         self.slow = False      # True means the test is slow-running
    86         self.allow_oom = False # True means that OOM is not considered a failure
    87         self.valgrind = False  # True means run under valgrind
    88         self.tz_pacific = False # True means force Pacific time for the test
    89         self.expect_error = '' # Errors to expect and consider passing
    90         self.expect_status = 0 # Exit status to expect from shell
    92     def copy(self):
    93         t = Test(self.path)
    94         t.jitflags = self.jitflags[:]
    95         t.slow = self.slow
    96         t.allow_oom = self.allow_oom
    97         t.valgrind = self.valgrind
    98         t.tz_pacific = self.tz_pacific
    99         t.expect_error = self.expect_error
   100         t.expect_status = self.expect_status
   101         return t
   103     COOKIE = '|jit-test|'
   104     CacheDir = JS_CACHE_DIR
   106     @classmethod
   107     def from_file(cls, path, options):
   108         test = cls(path)
   110         line = open(path).readline()
   111         i = line.find(cls.COOKIE)
   112         if i != -1:
   113             meta = line[i + len(cls.COOKIE):].strip('\n')
   114             parts = meta.split(';')
   115             for part in parts:
   116                 part = part.strip()
   117                 if not part:
   118                     continue
   119                 name, _, value = part.partition(':')
   120                 if value:
   121                     value = value.strip()
   122                     if name == 'error':
   123                         test.expect_error = value
   124                     elif name == 'exitstatus':
   125                         try:
   126                             test.expect_status = int(value, 0);
   127                         except ValueError:
   128                             print("warning: couldn't parse exit status %s" % value)
   129                     elif name == 'thread-count':
   130                         try:
   131                             test.jitflags.append('--thread-count=' + int(value, 0));
   132                         except ValueError:
   133                             print("warning: couldn't parse thread-count %s" % value)
   134                     else:
   135                         print('warning: unrecognized |jit-test| attribute %s' % part)
   136                 else:
   137                     if name == 'slow':
   138                         test.slow = True
   139                     elif name == 'allow-oom':
   140                         test.allow_oom = True
   141                     elif name == 'valgrind':
   142                         test.valgrind = options.valgrind
   143                     elif name == 'tz-pacific':
   144                         test.tz_pacific = True
   145                     elif name == 'debug':
   146                         test.jitflags.append('--debugjit')
   147                     elif name == 'ion-eager':
   148                         test.jitflags.append('--ion-eager')
   149                     elif name == 'no-ion':
   150                         test.jitflags.append('--no-ion')
   151                     elif name == 'dump-bytecode':
   152                         test.jitflags.append('--dump-bytecode')
   153                     else:
   154                         print('warning: unrecognized |jit-test| attribute %s' % part)
   156         if options.valgrind_all:
   157             test.valgrind = True
   159         return test
   161     def command(self, prefix, libdir, remote_prefix=None):
   162         path = self.path
   163         if remote_prefix:
   164             path = self.path.replace(TEST_DIR, remote_prefix)
   166         scriptdir_var = os.path.dirname(path);
   167         if not scriptdir_var.endswith('/'):
   168             scriptdir_var += '/'
   170         # Platforms where subprocess immediately invokes exec do not care
   171         # whether we use double or single quotes. On windows and when using
   172         # a remote device, however, we have to be careful to use the quote
   173         # style that is the opposite of what the exec wrapper uses.
   174         # This uses %r to get single quotes on windows and special cases
   175         # the remote device.
   176         fmt = 'const platform=%r; const libdir=%r; const scriptdir=%r'
   177         if remote_prefix:
   178             fmt = 'const platform="%s"; const libdir="%s"; const scriptdir="%s"'
   179         expr = fmt % (sys.platform, libdir, scriptdir_var)
   181         # We may have specified '-a' or '-d' twice: once via --jitflags, once
   182         # via the "|jit-test|" line.  Remove dups because they are toggles.
   183         cmd = prefix + ['--js-cache', Test.CacheDir]
   184         cmd += list(set(self.jitflags)) + ['-e', expr, '-f', path]
   185         if self.valgrind:
   186             cmd = self.VALGRIND_CMD + cmd
   187         return cmd
   189 def find_tests(substring=None):
   190     ans = []
   191     for dirpath, dirnames, filenames in os.walk(TEST_DIR):
   192         dirnames.sort()
   193         filenames.sort()
   194         if dirpath == '.':
   195             continue
   196         for filename in filenames:
   197             if not filename.endswith('.js'):
   198                 continue
   199             if filename in ('shell.js', 'browser.js', 'jsref.js'):
   200                 continue
   201             test = os.path.join(dirpath, filename)
   202             if substring is None or substring in os.path.relpath(test, TEST_DIR):
   203                 ans.append(test)
   204     return ans
   206 def tmppath(token):
   207     fd, path = tempfile.mkstemp(prefix=token)
   208     os.close(fd)
   209     return path
   211 def read_and_unlink(path):
   212     f = open(path)
   213     d = f.read()
   214     f.close()
   215     os.unlink(path)
   216     return d
   218 def th_run_cmd(cmdline, options, l):
   219     # close_fds is not supported on Windows and will cause a ValueError.
   220     if sys.platform != 'win32':
   221         options["close_fds"] = True
   222     p = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
   224     l[0] = p
   225     out, err = p.communicate()
   226     l[1] = (out, err, p.returncode)
   228 def run_timeout_cmd(cmdline, options, timeout=60.0):
   229     l = [ None, None ]
   230     timed_out = False
   231     th = Thread(target=th_run_cmd, args=(cmdline, options, l))
   233     # If our SIGINT handler is set to SIG_IGN (ignore)
   234     # then we are running as a child process for parallel
   235     # execution and we must ensure to kill our child
   236     # when we are signaled to exit.
   237     sigint_handler = signal.getsignal(signal.SIGINT)
   238     sigterm_handler = signal.getsignal(signal.SIGTERM)
   239     if (sigint_handler == signal.SIG_IGN):
   240         def handleChildSignal(sig, frame):
   241             try:
   242                 if sys.platform != 'win32':
   243                     os.kill(l[0].pid, signal.SIGKILL)
   244                 else:
   245                     import ctypes
   246                     ctypes.windll.kernel32.TerminateProcess(int(l[0]._handle), -1)
   247             except OSError:
   248                 pass
   249             if (sig == signal.SIGTERM):
   250                 sys.exit(0)
   251         signal.signal(signal.SIGINT, handleChildSignal)
   252         signal.signal(signal.SIGTERM, handleChildSignal)
   254     th.start()
   255     th.join(timeout)
   256     while th.isAlive():
   257         if l[0] is not None:
   258             try:
   259                 # In Python 3, we could just do l[0].kill().
   260                 if sys.platform != 'win32':
   261                     os.kill(l[0].pid, signal.SIGKILL)
   262                 else:
   263                     import ctypes
   264                     ctypes.windll.kernel32.TerminateProcess(int(l[0]._handle), -1)
   265                 time.sleep(.1)
   266                 timed_out = True
   267             except OSError:
   268                 # Expecting a "No such process" error
   269                 pass
   270     th.join()
   272     # Restore old signal handlers
   273     if (sigint_handler == signal.SIG_IGN):
   274         signal.signal(signal.SIGINT, signal.SIG_IGN)
   275         signal.signal(signal.SIGTERM, sigterm_handler)
   277     (out, err, code) = l[1]
   279     return (out, err, code, timed_out)
   281 def run_cmd(cmdline, env, timeout):
   282     return run_timeout_cmd(cmdline, { 'env': env }, timeout)
   284 def run_cmd_avoid_stdio(cmdline, env, timeout):
   285     stdoutPath, stderrPath = tmppath('jsstdout'), tmppath('jsstderr')
   286     env['JS_STDOUT'] = stdoutPath
   287     env['JS_STDERR'] = stderrPath
   288     _, __, code = run_timeout_cmd(cmdline, { 'env': env }, timeout)
   289     return read_and_unlink(stdoutPath), read_and_unlink(stderrPath), code
   291 def run_test(test, prefix, options):
   292     cmd = test.command(prefix, LIB_DIR)
   293     if options.show_cmd:
   294         print(subprocess.list2cmdline(cmd))
   296     if options.avoid_stdio:
   297         run = run_cmd_avoid_stdio
   298     else:
   299         run = run_cmd
   301     env = os.environ.copy()
   302     if test.tz_pacific:
   303         env['TZ'] = 'PST8PDT'
   305     # Ensure interpreter directory is in shared library path.
   306     pathvar = ''
   307     if sys.platform.startswith('linux'):
   308         pathvar = 'LD_LIBRARY_PATH'
   309     elif sys.platform.startswith('darwin'):
   310         pathvar = 'DYLD_LIBRARY_PATH'
   311     elif sys.platform.startswith('win'):
   312         pathvar = 'PATH'
   313     if pathvar:
   314         bin_dir = os.path.dirname(cmd[0])
   315         if pathvar in env:
   316             env[pathvar] = '%s%s%s' % (bin_dir, os.pathsep, env[pathvar])
   317         else:
   318             env[pathvar] = bin_dir
   320     out, err, code, timed_out = run(cmd, env, options.timeout)
   321     return TestOutput(test, cmd, out, err, code, None, timed_out)
   323 def run_test_remote(test, device, prefix, options):
   324     cmd = test.command(prefix, posixpath.join(options.remote_test_root, 'lib/'), posixpath.join(options.remote_test_root, 'tests'))
   325     if options.show_cmd:
   326         print(subprocess.list2cmdline(cmd))
   328     env = {}
   329     if test.tz_pacific:
   330         env['TZ'] = 'PST8PDT'
   332     env['LD_LIBRARY_PATH'] = options.remote_test_root
   334     buf = StringIO.StringIO()
   335     returncode = device.shell(cmd, buf, env=env, cwd=options.remote_test_root,
   336                               timeout=int(options.timeout))
   338     out = buf.getvalue()
   339     # We can't distinguish between stdout and stderr so we pass
   340     # the same buffer to both.
   341     return TestOutput(test, cmd, out, out, returncode, None, False)
   343 def check_output(out, err, rc, timed_out, test):
   344     if timed_out:
   345         # The shell sometimes hangs on shutdown on Windows 7 and Windows
   346         # Server 2008. See bug 970063 comment 7 for a description of the
   347         # problem. Until bug 956899 is fixed, ignore timeouts on these
   348         # platforms (versions 6.0 and 6.1).
   349         if sys.platform == 'win32':
   350             ver = sys.getwindowsversion()
   351             if ver.major == 6 and ver.minor <= 1:
   352                 return True
   353         return False
   355     if test.expect_error:
   356         # The shell exits with code 3 on uncaught exceptions.
   357         # Sometimes 0 is returned on Windows for unknown reasons.
   358         # See bug 899697.
   359         if sys.platform in ['win32', 'cygwin']:
   360             if rc != 3 and rc != 0:
   361                 return False
   362         else:
   363             if rc != 3:
   364                 return False
   366         return test.expect_error in err
   368     for line in out.split('\n'):
   369         if line.startswith('Trace stats check failed'):
   370             return False
   372     for line in err.split('\n'):
   373         if 'Assertion failed:' in line:
   374             return False
   376     if rc != test.expect_status:
   377         # Tests which expect a timeout check for exit code 6.
   378         # Sometimes 0 is returned on Windows for unknown reasons.
   379         # See bug 899697.
   380         if sys.platform in ['win32', 'cygwin'] and rc == 0:
   381             return True
   383         # Allow a non-zero exit code if we want to allow OOM, but only if we
   384         # actually got OOM.
   385         return test.allow_oom and 'out of memory' in err and 'Assertion failure' not in err
   387     return True
   389 def print_tinderbox(ok, res):
   390     # Output test failures in a TBPL parsable format, eg:
   391     # TEST-RESULT | filename.js | Failure description (code N, args "--foobar")
   392     #
   393     # Example:
   394     # TEST-PASS | foo/bar/baz.js | (code 0, args "--ion-eager")
   395     # TEST-UNEXPECTED-FAIL | foo/bar/baz.js | TypeError: or something (code -9, args "--no-ion")
   396     # INFO exit-status     : 3
   397     # INFO timed-out       : False
   398     # INFO stdout          > foo
   399     # INFO stdout          > bar
   400     # INFO stdout          > baz
   401     # INFO stderr         2> TypeError: or something
   402     # TEST-UNEXPECTED-FAIL | jit_test.py: Test execution interrupted by user
   403     result = "TEST-PASS" if ok else "TEST-UNEXPECTED-FAIL"
   404     message = "Success" if ok else res.describe_failure()
   405     jitflags = " ".join(res.test.jitflags)
   406     print("{} | {} | {} (code {}, args \"{}\")".format(
   407           result, res.test.relpath_top, message, res.rc, jitflags))
   409     # For failed tests, print as much information as we have, to aid debugging.
   410     if ok:
   411         return
   412     print("INFO exit-status     : {}".format(res.rc))
   413     print("INFO timed-out       : {}".format(res.timed_out))
   414     for line in res.out.splitlines():
   415         print("INFO stdout          > " + line.strip())
   416     for line in res.err.splitlines():
   417         print("INFO stderr         2> " + line.strip())
   419 def wrap_parallel_run_test(test, prefix, resultQueue, options):
   420     # Ignore SIGINT in the child
   421     signal.signal(signal.SIGINT, signal.SIG_IGN)
   422     result = run_test(test, prefix, options)
   423     resultQueue.put(result)
   424     return result
   426 def run_tests_parallel(tests, prefix, options):
   427     # This queue will contain the results of the various tests run.
   428     # We could make this queue a global variable instead of using
   429     # a manager to share, but this will not work on Windows.
   430     queue_manager = Manager()
   431     async_test_result_queue = queue_manager.Queue()
   433     # This queue will be used by the result process to indicate
   434     # that it has received a result and we can start a new process
   435     # on our end. The advantage is that we don't have to sleep and
   436     # check for worker completion ourselves regularly.
   437     notify_queue = queue_manager.Queue()
   439     # This queue will contain the return value of the function
   440     # processing the test results.
   441     total_tests = len(tests) * options.repeat
   442     result_process_return_queue = queue_manager.Queue()
   443     result_process = Process(target=process_test_results_parallel,
   444                              args=(async_test_result_queue, result_process_return_queue,
   445                                    notify_queue, total_tests, options))
   446     result_process.start()
   448     # Ensure that a SIGTERM is handled the same way as SIGINT
   449     # to terminate all child processes.
   450     sigint_handler = signal.getsignal(signal.SIGINT)
   451     signal.signal(signal.SIGTERM, sigint_handler)
   453     worker_processes = []
   455     def remove_completed_workers(workers):
   456         new_workers = []
   457         for worker in workers:
   458             if worker.is_alive():
   459                 new_workers.append(worker)
   460             else:
   461                 worker.join()
   462         return new_workers
   464     try:
   465         testcnt = 0
   466         # Initially start as many jobs as allowed to run parallel
   467         for i in range(min(options.max_jobs,total_tests)):
   468             notify_queue.put(True)
   470         # For every item in the notify queue, start one new worker.
   471         # Every completed worker adds a new item to this queue.
   472         while notify_queue.get():
   473             if (testcnt < total_tests):
   474                 # Start one new worker
   475                 test = tests[testcnt % len(tests)]
   476                 worker_process = Process(target=wrap_parallel_run_test, args=(test, prefix, async_test_result_queue, options))
   477                 worker_processes.append(worker_process)
   478                 worker_process.start()
   479                 testcnt += 1
   481                 # Collect completed workers
   482                 worker_processes = remove_completed_workers(worker_processes)
   483             else:
   484                 break
   486         # Wait for all processes to terminate
   487         while len(worker_processes) > 0:
   488             worker_processes = remove_completed_workers(worker_processes)
   490         # Signal completion to result processor, then wait for it to complete on its own
   491         async_test_result_queue.put(None)
   492         result_process.join()
   494         # Return what the result process has returned to us
   495         return result_process_return_queue.get()
   496     except (Exception, KeyboardInterrupt) as e:
   497         # Print the exception if it's not an interrupt,
   498         # might point to a bug or other faulty condition
   499         if not isinstance(e,KeyboardInterrupt):
   500             traceback.print_exc()
   502         for worker in worker_processes:
   503             try:
   504                 worker.terminate()
   505             except:
   506                 pass
   508         result_process.terminate()
   510     return False
   512 def get_parallel_results(async_test_result_queue, notify_queue):
   513     while True:
   514         async_test_result = async_test_result_queue.get()
   516         # Check if we are supposed to terminate
   517         if (async_test_result == None):
   518             return
   520         # Notify parent that we got a result
   521         notify_queue.put(True)
   523         yield async_test_result
   525 def process_test_results_parallel(async_test_result_queue, return_queue, notify_queue, num_tests, options):
   526     gen = get_parallel_results(async_test_result_queue, notify_queue)
   527     ok = process_test_results(gen, num_tests, options)
   528     return_queue.put(ok)
   530 def print_test_summary(num_tests, failures, complete, doing, options):
   531     if failures:
   532         if options.write_failures:
   533             try:
   534                 out = open(options.write_failures, 'w')
   535                 # Don't write duplicate entries when we are doing multiple failures per job.
   536                 written = set()
   537                 for res in failures:
   538                     if res.test.path not in written:
   539                         out.write(os.path.relpath(res.test.path, TEST_DIR) + '\n')
   540                         if options.write_failure_output:
   541                             out.write(res.out)
   542                             out.write(res.err)
   543                             out.write('Exit code: ' + str(res.rc) + "\n")
   544                         written.add(res.test.path)
   545                 out.close()
   546             except IOError:
   547                 sys.stderr.write("Exception thrown trying to write failure file '%s'\n"%
   548                                  options.write_failures)
   549                 traceback.print_exc()
   550                 sys.stderr.write('---\n')
   552         def show_test(res):
   553             if options.show_failed:
   554                 print('    ' + subprocess.list2cmdline(res.cmd))
   555             else:
   556                 print('    ' + ' '.join(res.test.jitflags + [res.test.path]))
   558         print('FAILURES:')
   559         for res in failures:
   560             if not res.timed_out:
   561                 show_test(res)
   563         print('TIMEOUTS:')
   564         for res in failures:
   565             if res.timed_out:
   566                 show_test(res)
   567     else:
   568         print('PASSED ALL' + ('' if complete else ' (partial run -- interrupted by user %s)' % doing))
   570     if options.tinderbox:
   571         num_failures = len(failures) if failures else 0
   572         print('Result summary:')
   573         print('Passed: %d' % (num_tests - num_failures))
   574         print('Failed: %d' % num_failures)
   576     return not failures
   578 def process_test_results(results, num_tests, options):
   579     pb = NullProgressBar()
   580     if not options.hide_progress and not options.show_cmd and ProgressBar.conservative_isatty():
   581         fmt = [
   582             {'value': 'PASS',    'color': 'green'},
   583             {'value': 'FAIL',    'color': 'red'},
   584             {'value': 'TIMEOUT', 'color': 'blue'},
   585             {'value': 'SKIP',    'color': 'brightgray'},
   586         ]
   587         pb = ProgressBar(num_tests, fmt)
   589     failures = []
   590     timeouts = 0
   591     complete = False
   592     doing = 'before starting'
   593     try:
   594         for i, res in enumerate(results):
   595             if options.show_output:
   596                 sys.stdout.write(res.out)
   597                 sys.stdout.write(res.err)
   598                 sys.stdout.write('Exit code: %s\n' % res.rc)
   599             if res.test.valgrind:
   600                 sys.stdout.write(res.err)
   602             ok = check_output(res.out, res.err, res.rc, res.timed_out, res.test)
   603             doing = 'after %s' % res.test.relpath_tests
   604             if not ok:
   605                 failures.append(res)
   606                 if res.timed_out:
   607                     pb.message("TIMEOUT - %s" % res.test.relpath_tests)
   608                     timeouts += 1
   609                 else:
   610                     pb.message("FAIL - %s" % res.test.relpath_tests)
   612             if options.tinderbox:
   613                 print_tinderbox(ok, res)
   615             n = i + 1
   616             pb.update(n, {
   617                 'PASS': n - len(failures),
   618                 'FAIL': len(failures),
   619                 'TIMEOUT': timeouts,
   620                 'SKIP': 0}
   621             )
   622         complete = True
   623     except KeyboardInterrupt:
   624         print("TEST-UNEXPECTED-FAIL | jit_test.py" +
   625               " : Test execution interrupted by user")
   627     pb.finish(True)
   628     return print_test_summary(num_tests, failures, complete, doing, options)
   630 def get_serial_results(tests, prefix, options):
   631     for i in xrange(0, options.repeat):
   632         for test in tests:
   633             yield run_test(test, prefix, options)
   635 def run_tests(tests, prefix, options):
   636     gen = get_serial_results(tests, prefix, options)
   637     ok = process_test_results(gen, len(tests) * options.repeat, options)
   638     return ok
   640 def get_remote_results(tests, device, prefix, options):
   641     for i in xrange(0, options.repeat):
   642         for test in tests:
   643             yield run_test_remote(test, device, prefix, options)
   645 def push_libs(options, device):
   646     # This saves considerable time in pushing unnecessary libraries
   647     # to the device but needs to be updated if the dependencies change.
   648     required_libs = ['libnss3.so', 'libmozglue.so']
   650     for file in os.listdir(options.local_lib):
   651         if file in required_libs:
   652             remote_file = posixpath.join(options.remote_test_root, file)
   653             device.pushFile(os.path.join(options.local_lib, file), remote_file)
   655 def push_progs(options, device, progs):
   656     for local_file in progs:
   657         remote_file = posixpath.join(options.remote_test_root, os.path.basename(local_file))
   658         device.pushFile(local_file, remote_file)
   660 def run_tests_remote(tests, prefix, options):
   661     # Setup device with everything needed to run our tests.
   662     from mozdevice import devicemanager, devicemanagerADB, devicemanagerSUT
   664     if options.device_transport == 'adb':
   665         if options.device_ip:
   666             dm = devicemanagerADB.DeviceManagerADB(options.device_ip, options.device_port, deviceSerial=options.device_serial, packageName=None, deviceRoot=options.remote_test_root)
   667         else:
   668             dm = devicemanagerADB.DeviceManagerADB(deviceSerial=options.device_serial, packageName=None, deviceRoot=options.remote_test_root)
   669     else:
   670         dm = devicemanagerSUT.DeviceManagerSUT(options.device_ip, options.device_port, deviceRoot=options.remote_test_root)
   671         if options.device_ip == None:
   672             print('Error: you must provide a device IP to connect to via the --device option')
   673             sys.exit(1)
   675     # Update the test root to point to our test directory.
   676     jit_tests_dir = posixpath.join(options.remote_test_root, 'jit-tests')
   677     options.remote_test_root = posixpath.join(jit_tests_dir, 'jit-tests')
   679     # Push js shell and libraries.
   680     if dm.dirExists(jit_tests_dir):
   681         dm.removeDir(jit_tests_dir)
   682     dm.mkDirs(options.remote_test_root)
   683     push_libs(options, dm)
   684     push_progs(options, dm, [prefix[0]])
   685     dm.chmodDir(options.remote_test_root)
   687     Test.CacheDir = posixpath.join(options.remote_test_root, '.js-cache')
   688     dm.mkDir(Test.CacheDir)
   690     dm.pushDir(JS_TESTS_DIR, posixpath.join(jit_tests_dir, 'tests'), timeout=600)
   692     dm.pushDir(os.path.dirname(TEST_DIR), options.remote_test_root, timeout=600)
   693     prefix[0] = os.path.join(options.remote_test_root, 'js')
   695     # Run all tests.
   696     gen = get_remote_results(tests, dm, prefix, options)
   697     ok = process_test_results(gen, len(tests) * options.repeat, options)
   698     return ok
   700 def parse_jitflags(options):
   701     jitflags = [ [ '-' + flag for flag in flags ]
   702                  for flags in options.jitflags.split(',') ]
   703     for flags in jitflags:
   704         for flag in flags:
   705             if flag not in ('-m', '-a', '-p', '-d', '-n'):
   706                 print('Invalid jit flag: "%s"' % flag)
   707                 sys.exit(1)
   708     return jitflags
   710 def platform_might_be_android():
   711     try:
   712         # The python package for SL4A provides an |android| module.
   713         # If that module is present, we're likely in SL4A-python on
   714         # device.  False positives and negatives are possible,
   715         # however.
   716         import android
   717         return True
   718     except ImportError:
   719         return False
   721 def stdio_might_be_broken():
   722     return platform_might_be_android()
   724 if __name__ == '__main__':
   725     print('Use ../jit-test/jit_test.py to run these tests.')

mercurial