11cb0ef41Sopenharmony_ci#!/usr/bin/env python3
21cb0ef41Sopenharmony_ci#
31cb0ef41Sopenharmony_ci# Copyright 2008 the V8 project authors. All rights reserved.
41cb0ef41Sopenharmony_ci# Redistribution and use in source and binary forms, with or without
51cb0ef41Sopenharmony_ci# modification, are permitted provided that the following conditions are
61cb0ef41Sopenharmony_ci# met:
71cb0ef41Sopenharmony_ci#
81cb0ef41Sopenharmony_ci#     * Redistributions of source code must retain the above copyright
91cb0ef41Sopenharmony_ci#       notice, this list of conditions and the following disclaimer.
101cb0ef41Sopenharmony_ci#     * Redistributions in binary form must reproduce the above
111cb0ef41Sopenharmony_ci#       copyright notice, this list of conditions and the following
121cb0ef41Sopenharmony_ci#       disclaimer in the documentation and/or other materials provided
131cb0ef41Sopenharmony_ci#       with the distribution.
141cb0ef41Sopenharmony_ci#     * Neither the name of Google Inc. nor the names of its
151cb0ef41Sopenharmony_ci#       contributors may be used to endorse or promote products derived
161cb0ef41Sopenharmony_ci#       from this software without specific prior written permission.
171cb0ef41Sopenharmony_ci#
181cb0ef41Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
191cb0ef41Sopenharmony_ci# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
201cb0ef41Sopenharmony_ci# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
211cb0ef41Sopenharmony_ci# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
221cb0ef41Sopenharmony_ci# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
231cb0ef41Sopenharmony_ci# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
241cb0ef41Sopenharmony_ci# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251cb0ef41Sopenharmony_ci# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261cb0ef41Sopenharmony_ci# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
271cb0ef41Sopenharmony_ci# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281cb0ef41Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cifrom __future__ import print_function
321cb0ef41Sopenharmony_cifrom typing import Dict
331cb0ef41Sopenharmony_ciimport logging
341cb0ef41Sopenharmony_ciimport optparse
351cb0ef41Sopenharmony_ciimport os
361cb0ef41Sopenharmony_ciimport re
371cb0ef41Sopenharmony_ciimport signal
381cb0ef41Sopenharmony_ciimport subprocess
391cb0ef41Sopenharmony_ciimport sys
401cb0ef41Sopenharmony_ciimport tempfile
411cb0ef41Sopenharmony_ciimport time
421cb0ef41Sopenharmony_ciimport threading
431cb0ef41Sopenharmony_ciimport utils
441cb0ef41Sopenharmony_ciimport multiprocessing
451cb0ef41Sopenharmony_ciimport errno
461cb0ef41Sopenharmony_ciimport copy
471cb0ef41Sopenharmony_ciimport io
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciif sys.version_info >= (3, 5):
511cb0ef41Sopenharmony_ci  from importlib import machinery, util
521cb0ef41Sopenharmony_ci  def get_module(name, path):
531cb0ef41Sopenharmony_ci    loader_details = (machinery.SourceFileLoader, machinery.SOURCE_SUFFIXES)
541cb0ef41Sopenharmony_ci    spec = machinery.FileFinder(path, loader_details).find_spec(name)
551cb0ef41Sopenharmony_ci    module = util.module_from_spec(spec)
561cb0ef41Sopenharmony_ci    spec.loader.exec_module(module)
571cb0ef41Sopenharmony_ci    return module
581cb0ef41Sopenharmony_cielse:
591cb0ef41Sopenharmony_ci  import imp
601cb0ef41Sopenharmony_ci  def get_module(name, path):
611cb0ef41Sopenharmony_ci    file = None
621cb0ef41Sopenharmony_ci    try:
631cb0ef41Sopenharmony_ci      (file, pathname, description) = imp.find_module(name, [path])
641cb0ef41Sopenharmony_ci      return imp.load_module(name, file, pathname, description)
651cb0ef41Sopenharmony_ci    finally:
661cb0ef41Sopenharmony_ci      if file:
671cb0ef41Sopenharmony_ci        file.close()
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cifrom io import open
711cb0ef41Sopenharmony_cifrom os.path import join, dirname, abspath, basename, isdir, exists
721cb0ef41Sopenharmony_cifrom datetime import datetime, timedelta
731cb0ef41Sopenharmony_citry:
741cb0ef41Sopenharmony_ci    from queue import Queue, Empty  # Python 3
751cb0ef41Sopenharmony_ciexcept ImportError:
761cb0ef41Sopenharmony_ci    from Queue import Queue, Empty  # Python 2
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_cifrom functools import reduce
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_citry:
811cb0ef41Sopenharmony_ci  from urllib.parse import unquote    # Python 3
821cb0ef41Sopenharmony_ciexcept ImportError:
831cb0ef41Sopenharmony_ci  from urllib import unquote          # Python 2
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cilogger = logging.getLogger('testrunner')
871cb0ef41Sopenharmony_ciskip_regex = re.compile(r'# SKIP\S*\s+(.*)', re.IGNORECASE)
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciVERBOSE = False
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_cios.umask(0o022)
921cb0ef41Sopenharmony_cios.environ['NODE_OPTIONS'] = ''
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci# ---------------------------------------------
951cb0ef41Sopenharmony_ci# --- P r o g r e s s   I n d i c a t o r s ---
961cb0ef41Sopenharmony_ci# ---------------------------------------------
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ciclass ProgressIndicator(object):
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  def __init__(self, cases, flaky_tests_mode, measure_flakiness):
1021cb0ef41Sopenharmony_ci    self.cases = cases
1031cb0ef41Sopenharmony_ci    self.serial_id = 0
1041cb0ef41Sopenharmony_ci    self.flaky_tests_mode = flaky_tests_mode
1051cb0ef41Sopenharmony_ci    self.measure_flakiness = measure_flakiness
1061cb0ef41Sopenharmony_ci    self.parallel_queue = Queue(len(cases))
1071cb0ef41Sopenharmony_ci    self.sequential_queue = Queue(len(cases))
1081cb0ef41Sopenharmony_ci    for case in cases:
1091cb0ef41Sopenharmony_ci      if case.parallel:
1101cb0ef41Sopenharmony_ci        self.parallel_queue.put_nowait(case)
1111cb0ef41Sopenharmony_ci      else:
1121cb0ef41Sopenharmony_ci        self.sequential_queue.put_nowait(case)
1131cb0ef41Sopenharmony_ci    self.succeeded = 0
1141cb0ef41Sopenharmony_ci    self.remaining = len(cases)
1151cb0ef41Sopenharmony_ci    self.total = len(cases)
1161cb0ef41Sopenharmony_ci    self.failed = [ ]
1171cb0ef41Sopenharmony_ci    self.flaky_failed = [ ]
1181cb0ef41Sopenharmony_ci    self.crashed = 0
1191cb0ef41Sopenharmony_ci    self.lock = threading.Lock()
1201cb0ef41Sopenharmony_ci    self.shutdown_event = threading.Event()
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  def GetFailureOutput(self, failure):
1231cb0ef41Sopenharmony_ci    output = []
1241cb0ef41Sopenharmony_ci    if failure.output.stderr:
1251cb0ef41Sopenharmony_ci      output += ["--- stderr ---" ]
1261cb0ef41Sopenharmony_ci      output += [failure.output.stderr.strip()]
1271cb0ef41Sopenharmony_ci    if failure.output.stdout:
1281cb0ef41Sopenharmony_ci      output += ["--- stdout ---"]
1291cb0ef41Sopenharmony_ci      output += [failure.output.stdout.strip()]
1301cb0ef41Sopenharmony_ci    output += ["Command: %s" % EscapeCommand(failure.command)]
1311cb0ef41Sopenharmony_ci    if failure.HasCrashed():
1321cb0ef41Sopenharmony_ci      output += ["--- %s ---" % PrintCrashed(failure.output.exit_code)]
1331cb0ef41Sopenharmony_ci    if failure.HasTimedOut():
1341cb0ef41Sopenharmony_ci      output += ["--- TIMEOUT ---"]
1351cb0ef41Sopenharmony_ci    output = "\n".join(output)
1361cb0ef41Sopenharmony_ci    return output
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  def PrintFailureOutput(self, failure):
1391cb0ef41Sopenharmony_ci    print(self.GetFailureOutput(failure))
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  def PrintFailureHeader(self, test):
1421cb0ef41Sopenharmony_ci    if test.IsNegative():
1431cb0ef41Sopenharmony_ci      negative_marker = '[negative] '
1441cb0ef41Sopenharmony_ci    else:
1451cb0ef41Sopenharmony_ci      negative_marker = ''
1461cb0ef41Sopenharmony_ci    print("=== %(label)s %(negative)s===" % {
1471cb0ef41Sopenharmony_ci      'label': test.GetLabel(),
1481cb0ef41Sopenharmony_ci      'negative': negative_marker
1491cb0ef41Sopenharmony_ci    })
1501cb0ef41Sopenharmony_ci    print("Path: %s" % "/".join(test.path))
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  def Run(self, tasks) -> Dict:
1531cb0ef41Sopenharmony_ci    self.Starting()
1541cb0ef41Sopenharmony_ci    threads = []
1551cb0ef41Sopenharmony_ci    # Spawn N-1 threads and then use this thread as the last one.
1561cb0ef41Sopenharmony_ci    # That way -j1 avoids threading altogether which is a nice fallback
1571cb0ef41Sopenharmony_ci    # in case of threading problems.
1581cb0ef41Sopenharmony_ci    for i in range(tasks - 1):
1591cb0ef41Sopenharmony_ci      thread = threading.Thread(target=self.RunSingle, args=[True, i + 1])
1601cb0ef41Sopenharmony_ci      threads.append(thread)
1611cb0ef41Sopenharmony_ci      thread.start()
1621cb0ef41Sopenharmony_ci    try:
1631cb0ef41Sopenharmony_ci      self.RunSingle(False, 0)
1641cb0ef41Sopenharmony_ci      # Wait for the remaining threads
1651cb0ef41Sopenharmony_ci      for thread in threads:
1661cb0ef41Sopenharmony_ci        # Use a timeout so that signals (ctrl-c) will be processed.
1671cb0ef41Sopenharmony_ci        thread.join(timeout=1000000)
1681cb0ef41Sopenharmony_ci    except (KeyboardInterrupt, SystemExit):
1691cb0ef41Sopenharmony_ci      self.shutdown_event.set()
1701cb0ef41Sopenharmony_ci    except Exception:
1711cb0ef41Sopenharmony_ci      # If there's an exception we schedule an interruption for any
1721cb0ef41Sopenharmony_ci      # remaining threads.
1731cb0ef41Sopenharmony_ci      self.shutdown_event.set()
1741cb0ef41Sopenharmony_ci      # ...and then reraise the exception to bail out
1751cb0ef41Sopenharmony_ci      raise
1761cb0ef41Sopenharmony_ci    self.Done()
1771cb0ef41Sopenharmony_ci    return {
1781cb0ef41Sopenharmony_ci      'allPassed': not self.failed,
1791cb0ef41Sopenharmony_ci      'failed': self.failed,
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  def RunSingle(self, parallel, thread_id):
1831cb0ef41Sopenharmony_ci    while not self.shutdown_event.is_set():
1841cb0ef41Sopenharmony_ci      try:
1851cb0ef41Sopenharmony_ci        test = self.parallel_queue.get_nowait()
1861cb0ef41Sopenharmony_ci      except Empty:
1871cb0ef41Sopenharmony_ci        if parallel:
1881cb0ef41Sopenharmony_ci          return
1891cb0ef41Sopenharmony_ci        try:
1901cb0ef41Sopenharmony_ci          test = self.sequential_queue.get_nowait()
1911cb0ef41Sopenharmony_ci        except Empty:
1921cb0ef41Sopenharmony_ci          return
1931cb0ef41Sopenharmony_ci      case = test
1941cb0ef41Sopenharmony_ci      case.thread_id = thread_id
1951cb0ef41Sopenharmony_ci      self.lock.acquire()
1961cb0ef41Sopenharmony_ci      case.serial_id = self.serial_id
1971cb0ef41Sopenharmony_ci      self.serial_id += 1
1981cb0ef41Sopenharmony_ci      self.AboutToRun(case)
1991cb0ef41Sopenharmony_ci      self.lock.release()
2001cb0ef41Sopenharmony_ci      try:
2011cb0ef41Sopenharmony_ci        start = datetime.now()
2021cb0ef41Sopenharmony_ci        output = case.Run()
2031cb0ef41Sopenharmony_ci        # SmartOS has a bug that causes unexpected ECONNREFUSED errors.
2041cb0ef41Sopenharmony_ci        # See https://smartos.org/bugview/OS-2767
2051cb0ef41Sopenharmony_ci        # If ECONNREFUSED on SmartOS, retry the test one time.
2061cb0ef41Sopenharmony_ci        if (output.UnexpectedOutput() and
2071cb0ef41Sopenharmony_ci          sys.platform == 'sunos5' and
2081cb0ef41Sopenharmony_ci          'ECONNREFUSED' in output.output.stderr):
2091cb0ef41Sopenharmony_ci            output = case.Run()
2101cb0ef41Sopenharmony_ci            output.diagnostic.append('ECONNREFUSED received, test retried')
2111cb0ef41Sopenharmony_ci        case.duration = (datetime.now() - start)
2121cb0ef41Sopenharmony_ci      except IOError:
2131cb0ef41Sopenharmony_ci        return
2141cb0ef41Sopenharmony_ci      if self.shutdown_event.is_set():
2151cb0ef41Sopenharmony_ci        return
2161cb0ef41Sopenharmony_ci      self.lock.acquire()
2171cb0ef41Sopenharmony_ci      if output.UnexpectedOutput():
2181cb0ef41Sopenharmony_ci        if FLAKY in output.test.outcomes and self.flaky_tests_mode == DONTCARE:
2191cb0ef41Sopenharmony_ci          self.flaky_failed.append(output)
2201cb0ef41Sopenharmony_ci        elif FLAKY in output.test.outcomes and self.flaky_tests_mode == KEEP_RETRYING:
2211cb0ef41Sopenharmony_ci          for _ in range(99):
2221cb0ef41Sopenharmony_ci            if not case.Run().UnexpectedOutput():
2231cb0ef41Sopenharmony_ci              self.flaky_failed.append(output)
2241cb0ef41Sopenharmony_ci              break
2251cb0ef41Sopenharmony_ci          else:
2261cb0ef41Sopenharmony_ci            # If after 100 tries, the test is not passing, it's not flaky.
2271cb0ef41Sopenharmony_ci            self.failed.append(output)
2281cb0ef41Sopenharmony_ci        else:
2291cb0ef41Sopenharmony_ci          self.failed.append(output)
2301cb0ef41Sopenharmony_ci          if output.HasCrashed():
2311cb0ef41Sopenharmony_ci            self.crashed += 1
2321cb0ef41Sopenharmony_ci          if self.measure_flakiness:
2331cb0ef41Sopenharmony_ci            outputs = [case.Run() for _ in range(self.measure_flakiness)]
2341cb0ef41Sopenharmony_ci            # +1s are there because the test already failed once at this point.
2351cb0ef41Sopenharmony_ci            print(" failed %d out of %d" % (len([i for i in outputs if i.UnexpectedOutput()]) + 1, self.measure_flakiness + 1))
2361cb0ef41Sopenharmony_ci      else:
2371cb0ef41Sopenharmony_ci        self.succeeded += 1
2381cb0ef41Sopenharmony_ci      self.remaining -= 1
2391cb0ef41Sopenharmony_ci      self.HasRun(output)
2401cb0ef41Sopenharmony_ci      self.lock.release()
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_cidef EscapeCommand(command):
2441cb0ef41Sopenharmony_ci  parts = []
2451cb0ef41Sopenharmony_ci  for part in command:
2461cb0ef41Sopenharmony_ci    if ' ' in part:
2471cb0ef41Sopenharmony_ci      # Escape spaces.  We may need to escape more characters for this
2481cb0ef41Sopenharmony_ci      # to work properly.
2491cb0ef41Sopenharmony_ci      parts.append('"%s"' % part)
2501cb0ef41Sopenharmony_ci    else:
2511cb0ef41Sopenharmony_ci      parts.append(part)
2521cb0ef41Sopenharmony_ci  return " ".join(parts)
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ciclass SimpleProgressIndicator(ProgressIndicator):
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  def Starting(self):
2581cb0ef41Sopenharmony_ci    print('Running %i tests' % len(self.cases))
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci  def Done(self):
2611cb0ef41Sopenharmony_ci    print()
2621cb0ef41Sopenharmony_ci    for failed in self.failed:
2631cb0ef41Sopenharmony_ci      self.PrintFailureHeader(failed.test)
2641cb0ef41Sopenharmony_ci      self.PrintFailureOutput(failed)
2651cb0ef41Sopenharmony_ci    if len(self.failed) == 0:
2661cb0ef41Sopenharmony_ci      print("===")
2671cb0ef41Sopenharmony_ci      print("=== All tests succeeded")
2681cb0ef41Sopenharmony_ci      print("===")
2691cb0ef41Sopenharmony_ci    else:
2701cb0ef41Sopenharmony_ci      print()
2711cb0ef41Sopenharmony_ci      print("===")
2721cb0ef41Sopenharmony_ci      print("=== %i tests failed" % len(self.failed))
2731cb0ef41Sopenharmony_ci      if self.crashed > 0:
2741cb0ef41Sopenharmony_ci        print("=== %i tests CRASHED" % self.crashed)
2751cb0ef41Sopenharmony_ci      print("===")
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ciclass VerboseProgressIndicator(SimpleProgressIndicator):
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci  def AboutToRun(self, case):
2811cb0ef41Sopenharmony_ci    print('Starting %s...' % case.GetLabel())
2821cb0ef41Sopenharmony_ci    sys.stdout.flush()
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  def HasRun(self, output):
2851cb0ef41Sopenharmony_ci    if output.UnexpectedOutput():
2861cb0ef41Sopenharmony_ci      if output.HasCrashed():
2871cb0ef41Sopenharmony_ci        outcome = 'CRASH'
2881cb0ef41Sopenharmony_ci      else:
2891cb0ef41Sopenharmony_ci        outcome = 'FAIL'
2901cb0ef41Sopenharmony_ci    else:
2911cb0ef41Sopenharmony_ci      outcome = 'pass'
2921cb0ef41Sopenharmony_ci    print('Done running %s: %s' % (output.test.GetLabel(), outcome))
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ciclass DotsProgressIndicator(SimpleProgressIndicator):
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci  def AboutToRun(self, case):
2981cb0ef41Sopenharmony_ci    pass
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  def HasRun(self, output):
3011cb0ef41Sopenharmony_ci    total = self.succeeded + len(self.failed)
3021cb0ef41Sopenharmony_ci    if (total > 1) and (total % 50 == 1):
3031cb0ef41Sopenharmony_ci      sys.stdout.write('\n')
3041cb0ef41Sopenharmony_ci    if output.UnexpectedOutput():
3051cb0ef41Sopenharmony_ci      if output.HasCrashed():
3061cb0ef41Sopenharmony_ci        sys.stdout.write('C')
3071cb0ef41Sopenharmony_ci        sys.stdout.flush()
3081cb0ef41Sopenharmony_ci      elif output.HasTimedOut():
3091cb0ef41Sopenharmony_ci        sys.stdout.write('T')
3101cb0ef41Sopenharmony_ci        sys.stdout.flush()
3111cb0ef41Sopenharmony_ci      else:
3121cb0ef41Sopenharmony_ci        sys.stdout.write('F')
3131cb0ef41Sopenharmony_ci        sys.stdout.flush()
3141cb0ef41Sopenharmony_ci    else:
3151cb0ef41Sopenharmony_ci      sys.stdout.write('.')
3161cb0ef41Sopenharmony_ci      sys.stdout.flush()
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ciclass ActionsAnnotationProgressIndicator(DotsProgressIndicator):
3191cb0ef41Sopenharmony_ci  def GetAnnotationInfo(self, test, output):
3201cb0ef41Sopenharmony_ci    traceback = output.stdout + output.stderr
3211cb0ef41Sopenharmony_ci    find_full_path = re.search(r' +at .*\(.*%s:([0-9]+):([0-9]+)' % test.file, traceback)
3221cb0ef41Sopenharmony_ci    col = line = 0
3231cb0ef41Sopenharmony_ci    if find_full_path:
3241cb0ef41Sopenharmony_ci        line, col = map(int, find_full_path.groups())
3251cb0ef41Sopenharmony_ci    root_path = abspath(join(dirname(__file__), '../')) + os.sep
3261cb0ef41Sopenharmony_ci    filename = test.file.replace(root_path, "")
3271cb0ef41Sopenharmony_ci    return filename, line, col
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  def PrintFailureOutput(self, failure):
3301cb0ef41Sopenharmony_ci    output = self.GetFailureOutput(failure)
3311cb0ef41Sopenharmony_ci    filename, line, column = self.GetAnnotationInfo(failure.test, failure.output)
3321cb0ef41Sopenharmony_ci    print("::error file=%s,line=%d,col=%d::%s" % (filename, line, column, output.replace('\n', '%0A')))
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ciclass TapProgressIndicator(SimpleProgressIndicator):
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  def _printDiagnostic(self):
3371cb0ef41Sopenharmony_ci    logger.info('  severity: %s', self.severity)
3381cb0ef41Sopenharmony_ci    self.exitcode and logger.info('  exitcode: %s', self.exitcode)
3391cb0ef41Sopenharmony_ci    logger.info('  stack: |-')
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci    for l in self.traceback.splitlines():
3421cb0ef41Sopenharmony_ci      logger.info('    ' + l)
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci  def Starting(self):
3451cb0ef41Sopenharmony_ci    logger.info('TAP version 13')
3461cb0ef41Sopenharmony_ci    logger.info('1..%i' % len(self.cases))
3471cb0ef41Sopenharmony_ci    self._done = 0
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci  def AboutToRun(self, case):
3501cb0ef41Sopenharmony_ci    pass
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci  def HasRun(self, output):
3531cb0ef41Sopenharmony_ci    self._done += 1
3541cb0ef41Sopenharmony_ci    self.traceback = ''
3551cb0ef41Sopenharmony_ci    self.severity = 'ok'
3561cb0ef41Sopenharmony_ci    self.exitcode = ''
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci    # Print test name as (for example) "parallel/test-assert".  Tests that are
3591cb0ef41Sopenharmony_ci    # scraped from the addons documentation are all named test.js, making it
3601cb0ef41Sopenharmony_ci    # hard to decipher what test is running when only the filename is printed.
3611cb0ef41Sopenharmony_ci    prefix = abspath(join(dirname(__file__), '../test')) + os.sep
3621cb0ef41Sopenharmony_ci    command = output.command[-1]
3631cb0ef41Sopenharmony_ci    command = NormalizePath(command, prefix)
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci    if output.UnexpectedOutput():
3661cb0ef41Sopenharmony_ci      status_line = 'not ok %i %s' % (self._done, command)
3671cb0ef41Sopenharmony_ci      self.severity = 'fail'
3681cb0ef41Sopenharmony_ci      self.exitcode = output.output.exit_code
3691cb0ef41Sopenharmony_ci      self.traceback = output.output.stdout + output.output.stderr
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci      if FLAKY in output.test.outcomes and self.flaky_tests_mode == DONTCARE:
3721cb0ef41Sopenharmony_ci        status_line = status_line + ' # TODO : Fix flaky test'
3731cb0ef41Sopenharmony_ci        self.severity = 'flaky'
3741cb0ef41Sopenharmony_ci
3751cb0ef41Sopenharmony_ci      logger.info(status_line)
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci      if output.HasCrashed():
3781cb0ef41Sopenharmony_ci        self.severity = 'crashed'
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci      elif output.HasTimedOut():
3811cb0ef41Sopenharmony_ci        self.severity = 'fail'
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci    else:
3841cb0ef41Sopenharmony_ci      skip = skip_regex.search(output.output.stdout)
3851cb0ef41Sopenharmony_ci      if skip:
3861cb0ef41Sopenharmony_ci        logger.info(
3871cb0ef41Sopenharmony_ci          'ok %i %s # skip %s' % (self._done, command, skip.group(1)))
3881cb0ef41Sopenharmony_ci      else:
3891cb0ef41Sopenharmony_ci        status_line = 'ok %i %s' % (self._done, command)
3901cb0ef41Sopenharmony_ci        if FLAKY in output.test.outcomes:
3911cb0ef41Sopenharmony_ci          status_line = status_line + ' # TODO : Fix flaky test'
3921cb0ef41Sopenharmony_ci        logger.info(status_line)
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci      if output.diagnostic:
3951cb0ef41Sopenharmony_ci        self.severity = 'ok'
3961cb0ef41Sopenharmony_ci        if isinstance(output.diagnostic, list):
3971cb0ef41Sopenharmony_ci          self.traceback = '\n'.join(output.diagnostic)
3981cb0ef41Sopenharmony_ci        else:
3991cb0ef41Sopenharmony_ci          self.traceback = output.diagnostic
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci    duration = output.test.duration
4031cb0ef41Sopenharmony_ci    logger.info('  ---')
4041cb0ef41Sopenharmony_ci    logger.info('  duration_ms: %.5f' % (duration  / timedelta(milliseconds=1)))
4051cb0ef41Sopenharmony_ci    if self.severity != 'ok' or self.traceback != '':
4061cb0ef41Sopenharmony_ci      if output.HasTimedOut():
4071cb0ef41Sopenharmony_ci        self.traceback = 'timeout\n' + output.output.stdout + output.output.stderr
4081cb0ef41Sopenharmony_ci      self._printDiagnostic()
4091cb0ef41Sopenharmony_ci    logger.info('  ...')
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  def Done(self):
4121cb0ef41Sopenharmony_ci    pass
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ciclass DeoptsCheckProgressIndicator(SimpleProgressIndicator):
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci  def Starting(self):
4171cb0ef41Sopenharmony_ci    pass
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_ci  def AboutToRun(self, case):
4201cb0ef41Sopenharmony_ci    pass
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci  def HasRun(self, output):
4231cb0ef41Sopenharmony_ci    # Print test name as (for example) "parallel/test-assert".  Tests that are
4241cb0ef41Sopenharmony_ci    # scraped from the addons documentation are all named test.js, making it
4251cb0ef41Sopenharmony_ci    # hard to decipher what test is running when only the filename is printed.
4261cb0ef41Sopenharmony_ci    prefix = abspath(join(dirname(__file__), '../test')) + os.sep
4271cb0ef41Sopenharmony_ci    command = output.command[-1]
4281cb0ef41Sopenharmony_ci    command = NormalizePath(command, prefix)
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci    stdout = output.output.stdout.strip()
4311cb0ef41Sopenharmony_ci    printed_file = False
4321cb0ef41Sopenharmony_ci    for line in stdout.splitlines():
4331cb0ef41Sopenharmony_ci      if (
4341cb0ef41Sopenharmony_ci        (line.startswith("[aborted optimiz") or line.startswith("[disabled optimiz")) and
4351cb0ef41Sopenharmony_ci        ("because:" in line or "reason:" in line)
4361cb0ef41Sopenharmony_ci      ):
4371cb0ef41Sopenharmony_ci        if not printed_file:
4381cb0ef41Sopenharmony_ci          printed_file = True
4391cb0ef41Sopenharmony_ci          print('==== %s ====' % command)
4401cb0ef41Sopenharmony_ci          self.failed.append(output)
4411cb0ef41Sopenharmony_ci        print('  %s' % line)
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ci  def Done(self):
4441cb0ef41Sopenharmony_ci    pass
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ciclass CompactProgressIndicator(ProgressIndicator):
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  def __init__(self, cases, flaky_tests_mode, measure_flakiness, templates):
4501cb0ef41Sopenharmony_ci    super(CompactProgressIndicator, self).__init__(cases, flaky_tests_mode, measure_flakiness)
4511cb0ef41Sopenharmony_ci    self.templates = templates
4521cb0ef41Sopenharmony_ci    self.last_status_length = 0
4531cb0ef41Sopenharmony_ci    self.start_time = time.time()
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci  def Starting(self):
4561cb0ef41Sopenharmony_ci    pass
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci  def Done(self):
4591cb0ef41Sopenharmony_ci    self.PrintProgress('Done\n')
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci  def AboutToRun(self, case):
4621cb0ef41Sopenharmony_ci    self.PrintProgress(case.GetLabel())
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  def HasRun(self, output):
4651cb0ef41Sopenharmony_ci    if output.UnexpectedOutput():
4661cb0ef41Sopenharmony_ci      self.ClearLine(self.last_status_length)
4671cb0ef41Sopenharmony_ci      self.PrintFailureHeader(output.test)
4681cb0ef41Sopenharmony_ci      stdout = output.output.stdout.strip()
4691cb0ef41Sopenharmony_ci      if len(stdout):
4701cb0ef41Sopenharmony_ci        print(self.templates['stdout'] % stdout)
4711cb0ef41Sopenharmony_ci      stderr = output.output.stderr.strip()
4721cb0ef41Sopenharmony_ci      if len(stderr):
4731cb0ef41Sopenharmony_ci        print(self.templates['stderr'] % stderr)
4741cb0ef41Sopenharmony_ci      print("Command: %s" % EscapeCommand(output.command))
4751cb0ef41Sopenharmony_ci      if output.HasCrashed():
4761cb0ef41Sopenharmony_ci        print("--- %s ---" % PrintCrashed(output.output.exit_code))
4771cb0ef41Sopenharmony_ci      if output.HasTimedOut():
4781cb0ef41Sopenharmony_ci        print("--- TIMEOUT ---")
4791cb0ef41Sopenharmony_ci      print("\n") # Two blank lines between failures, for visual separation
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  def Truncate(self, str, length):
4821cb0ef41Sopenharmony_ci    if length and (len(str) > (length - 3)):
4831cb0ef41Sopenharmony_ci      return str[:(length-3)] + "..."
4841cb0ef41Sopenharmony_ci    else:
4851cb0ef41Sopenharmony_ci      return str
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci  def PrintProgress(self, name):
4881cb0ef41Sopenharmony_ci    self.ClearLine(self.last_status_length)
4891cb0ef41Sopenharmony_ci    elapsed = time.time() - self.start_time
4901cb0ef41Sopenharmony_ci    status = self.templates['status_line'] % {
4911cb0ef41Sopenharmony_ci      'passed': self.succeeded,
4921cb0ef41Sopenharmony_ci      'remaining': (((self.total - self.remaining) * 100) // self.total),
4931cb0ef41Sopenharmony_ci      'failed': len(self.failed),
4941cb0ef41Sopenharmony_ci      'test': name,
4951cb0ef41Sopenharmony_ci      'mins': int(elapsed) / 60,
4961cb0ef41Sopenharmony_ci      'secs': int(elapsed) % 60
4971cb0ef41Sopenharmony_ci    }
4981cb0ef41Sopenharmony_ci    status = self.Truncate(status, 78)
4991cb0ef41Sopenharmony_ci    self.last_status_length = len(status)
5001cb0ef41Sopenharmony_ci    print(status, end='')
5011cb0ef41Sopenharmony_ci    sys.stdout.flush()
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_ciclass ColorProgressIndicator(CompactProgressIndicator):
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci  def __init__(self, cases, flaky_tests_mode, measure_flakiness):
5071cb0ef41Sopenharmony_ci    templates = {
5081cb0ef41Sopenharmony_ci      'status_line': "[%(mins)02i:%(secs)02i|\033[34m%%%(remaining) 4d\033[0m|\033[32m+%(passed) 4d\033[0m|\033[31m-%(failed) 4d\033[0m]: %(test)s",
5091cb0ef41Sopenharmony_ci      'stdout': "\033[1m%s\033[0m",
5101cb0ef41Sopenharmony_ci      'stderr': "\033[31m%s\033[0m",
5111cb0ef41Sopenharmony_ci    }
5121cb0ef41Sopenharmony_ci    super(ColorProgressIndicator, self).__init__(cases, flaky_tests_mode, measure_flakiness, templates)
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ci  def ClearLine(self, last_line_length):
5151cb0ef41Sopenharmony_ci    print("\033[1K\r", end='')
5161cb0ef41Sopenharmony_ci
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ciclass MonochromeProgressIndicator(CompactProgressIndicator):
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci  def __init__(self, cases, flaky_tests_mode, measure_flakiness):
5211cb0ef41Sopenharmony_ci    templates = {
5221cb0ef41Sopenharmony_ci      'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%(failed) 4d]: %(test)s",
5231cb0ef41Sopenharmony_ci      'stdout': '%s',
5241cb0ef41Sopenharmony_ci      'stderr': '%s',
5251cb0ef41Sopenharmony_ci      'clear': lambda last_line_length: ("\r" + (" " * last_line_length) + "\r"),
5261cb0ef41Sopenharmony_ci      'max_length': 78
5271cb0ef41Sopenharmony_ci    }
5281cb0ef41Sopenharmony_ci    super(MonochromeProgressIndicator, self).__init__(cases, flaky_tests_mode, measure_flakiness, templates)
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci  def ClearLine(self, last_line_length):
5311cb0ef41Sopenharmony_ci    print(("\r" + (" " * last_line_length) + "\r"), end='')
5321cb0ef41Sopenharmony_ci
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ciPROGRESS_INDICATORS = {
5351cb0ef41Sopenharmony_ci  'verbose': VerboseProgressIndicator,
5361cb0ef41Sopenharmony_ci  'dots': DotsProgressIndicator,
5371cb0ef41Sopenharmony_ci  'actions': ActionsAnnotationProgressIndicator,
5381cb0ef41Sopenharmony_ci  'color': ColorProgressIndicator,
5391cb0ef41Sopenharmony_ci  'tap': TapProgressIndicator,
5401cb0ef41Sopenharmony_ci  'mono': MonochromeProgressIndicator,
5411cb0ef41Sopenharmony_ci  'deopts': DeoptsCheckProgressIndicator
5421cb0ef41Sopenharmony_ci}
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_ci# -------------------------
5461cb0ef41Sopenharmony_ci# --- F r a m e w o r k ---
5471cb0ef41Sopenharmony_ci# -------------------------
5481cb0ef41Sopenharmony_ci
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ciclass CommandOutput(object):
5511cb0ef41Sopenharmony_ci
5521cb0ef41Sopenharmony_ci  def __init__(self, exit_code, timed_out, stdout, stderr):
5531cb0ef41Sopenharmony_ci    self.exit_code = exit_code
5541cb0ef41Sopenharmony_ci    self.timed_out = timed_out
5551cb0ef41Sopenharmony_ci    self.stdout = stdout
5561cb0ef41Sopenharmony_ci    self.stderr = stderr
5571cb0ef41Sopenharmony_ci    self.failed = None
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ciclass TestCase(object):
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ci  def __init__(self, context, path, arch, mode):
5631cb0ef41Sopenharmony_ci    self.path = path
5641cb0ef41Sopenharmony_ci    self.context = context
5651cb0ef41Sopenharmony_ci    self.duration = None
5661cb0ef41Sopenharmony_ci    self.arch = arch
5671cb0ef41Sopenharmony_ci    self.mode = mode
5681cb0ef41Sopenharmony_ci    self.parallel = False
5691cb0ef41Sopenharmony_ci    self.disable_core_files = False
5701cb0ef41Sopenharmony_ci    self.serial_id = 0
5711cb0ef41Sopenharmony_ci    self.thread_id = 0
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci  def IsNegative(self):
5741cb0ef41Sopenharmony_ci    return self.context.expect_fail
5751cb0ef41Sopenharmony_ci
5761cb0ef41Sopenharmony_ci  def DidFail(self, output):
5771cb0ef41Sopenharmony_ci    if output.failed is None:
5781cb0ef41Sopenharmony_ci      output.failed = self.IsFailureOutput(output)
5791cb0ef41Sopenharmony_ci    return output.failed
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci  def IsFailureOutput(self, output):
5821cb0ef41Sopenharmony_ci    return output.exit_code != 0
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  def GetSource(self):
5851cb0ef41Sopenharmony_ci    return "(no source available)"
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ci  def RunCommand(self, command, env):
5881cb0ef41Sopenharmony_ci    full_command = self.context.processor(command)
5891cb0ef41Sopenharmony_ci    output = Execute(full_command,
5901cb0ef41Sopenharmony_ci                     self.context,
5911cb0ef41Sopenharmony_ci                     self.context.GetTimeout(self.mode, self.config.section),
5921cb0ef41Sopenharmony_ci                     env,
5931cb0ef41Sopenharmony_ci                     disable_core_files = self.disable_core_files)
5941cb0ef41Sopenharmony_ci    return TestOutput(self,
5951cb0ef41Sopenharmony_ci                      full_command,
5961cb0ef41Sopenharmony_ci                      output,
5971cb0ef41Sopenharmony_ci                      self.context.store_unexpected_output)
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_ci  def Run(self):
6001cb0ef41Sopenharmony_ci    try:
6011cb0ef41Sopenharmony_ci      result = self.RunCommand(self.GetCommand(), {
6021cb0ef41Sopenharmony_ci        "TEST_SERIAL_ID": "%d" % self.serial_id,
6031cb0ef41Sopenharmony_ci        "TEST_THREAD_ID": "%d" % self.thread_id,
6041cb0ef41Sopenharmony_ci        "TEST_PARALLEL" : "%d" % self.parallel
6051cb0ef41Sopenharmony_ci      })
6061cb0ef41Sopenharmony_ci    finally:
6071cb0ef41Sopenharmony_ci      # Tests can leave the tty in non-blocking mode. If the test runner
6081cb0ef41Sopenharmony_ci      # tries to print to stdout/stderr after that and the tty buffer is
6091cb0ef41Sopenharmony_ci      # full, it'll die with a EAGAIN OSError. Ergo, put the tty back in
6101cb0ef41Sopenharmony_ci      # blocking mode before proceeding.
6111cb0ef41Sopenharmony_ci      if sys.platform != 'win32':
6121cb0ef41Sopenharmony_ci        from fcntl import fcntl, F_GETFL, F_SETFL
6131cb0ef41Sopenharmony_ci        from os import O_NONBLOCK
6141cb0ef41Sopenharmony_ci        for fd in 0,1,2: fcntl(fd, F_SETFL, ~O_NONBLOCK & fcntl(fd, F_GETFL))
6151cb0ef41Sopenharmony_ci
6161cb0ef41Sopenharmony_ci    return result
6171cb0ef41Sopenharmony_ci
6181cb0ef41Sopenharmony_ci
6191cb0ef41Sopenharmony_ciclass TestOutput(object):
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_ci  def __init__(self, test, command, output, store_unexpected_output):
6221cb0ef41Sopenharmony_ci    self.test = test
6231cb0ef41Sopenharmony_ci    self.command = command
6241cb0ef41Sopenharmony_ci    self.output = output
6251cb0ef41Sopenharmony_ci    self.store_unexpected_output = store_unexpected_output
6261cb0ef41Sopenharmony_ci    self.diagnostic = []
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_ci  def UnexpectedOutput(self):
6291cb0ef41Sopenharmony_ci    if self.HasCrashed():
6301cb0ef41Sopenharmony_ci      outcome = CRASH
6311cb0ef41Sopenharmony_ci    elif self.HasTimedOut():
6321cb0ef41Sopenharmony_ci      outcome = TIMEOUT
6331cb0ef41Sopenharmony_ci    elif self.HasFailed():
6341cb0ef41Sopenharmony_ci      outcome = FAIL
6351cb0ef41Sopenharmony_ci    else:
6361cb0ef41Sopenharmony_ci      outcome = PASS
6371cb0ef41Sopenharmony_ci    return not outcome in self.test.outcomes
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci  def HasCrashed(self):
6401cb0ef41Sopenharmony_ci    if utils.IsWindows():
6411cb0ef41Sopenharmony_ci      return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.output.exit_code)
6421cb0ef41Sopenharmony_ci    else:
6431cb0ef41Sopenharmony_ci      # Timed out tests will have exit_code -signal.SIGTERM.
6441cb0ef41Sopenharmony_ci      if self.output.timed_out:
6451cb0ef41Sopenharmony_ci        return False
6461cb0ef41Sopenharmony_ci      return self.output.exit_code < 0
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_ci  def HasTimedOut(self):
6491cb0ef41Sopenharmony_ci    return self.output.timed_out
6501cb0ef41Sopenharmony_ci
6511cb0ef41Sopenharmony_ci  def HasFailed(self):
6521cb0ef41Sopenharmony_ci    execution_failed = self.test.DidFail(self.output)
6531cb0ef41Sopenharmony_ci    if self.test.IsNegative():
6541cb0ef41Sopenharmony_ci      return not execution_failed
6551cb0ef41Sopenharmony_ci    else:
6561cb0ef41Sopenharmony_ci      return execution_failed
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_cidef KillProcessWithID(pid, signal_to_send=signal.SIGTERM):
6601cb0ef41Sopenharmony_ci  if utils.IsWindows():
6611cb0ef41Sopenharmony_ci    os.popen('taskkill /T /F /PID %d' % pid)
6621cb0ef41Sopenharmony_ci  else:
6631cb0ef41Sopenharmony_ci    os.kill(pid, signal_to_send)
6641cb0ef41Sopenharmony_ci
6651cb0ef41Sopenharmony_ci
6661cb0ef41Sopenharmony_ciMAX_SLEEP_TIME = 0.1
6671cb0ef41Sopenharmony_ciINITIAL_SLEEP_TIME = 0.0001
6681cb0ef41Sopenharmony_ciSLEEP_TIME_FACTOR = 1.25
6691cb0ef41Sopenharmony_ci
6701cb0ef41Sopenharmony_ciSEM_INVALID_VALUE = -1
6711cb0ef41Sopenharmony_ciSEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h
6721cb0ef41Sopenharmony_ci
6731cb0ef41Sopenharmony_cidef Win32SetErrorMode(mode):
6741cb0ef41Sopenharmony_ci  prev_error_mode = SEM_INVALID_VALUE
6751cb0ef41Sopenharmony_ci  try:
6761cb0ef41Sopenharmony_ci    import ctypes
6771cb0ef41Sopenharmony_ci    prev_error_mode = ctypes.windll.kernel32.SetErrorMode(mode)
6781cb0ef41Sopenharmony_ci  except ImportError:
6791cb0ef41Sopenharmony_ci    pass
6801cb0ef41Sopenharmony_ci  return prev_error_mode
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ci
6831cb0ef41Sopenharmony_cidef KillTimedOutProcess(context, pid):
6841cb0ef41Sopenharmony_ci  signal_to_send = signal.SIGTERM
6851cb0ef41Sopenharmony_ci  if context.abort_on_timeout:
6861cb0ef41Sopenharmony_ci    # Using SIGABRT here allows the OS to generate a core dump that can be
6871cb0ef41Sopenharmony_ci    # looked at post-mortem, which helps for investigating failures that are
6881cb0ef41Sopenharmony_ci    # difficult to reproduce.
6891cb0ef41Sopenharmony_ci    signal_to_send = signal.SIGABRT
6901cb0ef41Sopenharmony_ci  KillProcessWithID(pid, signal_to_send)
6911cb0ef41Sopenharmony_ci
6921cb0ef41Sopenharmony_ci
6931cb0ef41Sopenharmony_cidef RunProcess(context, timeout, args, **rest):
6941cb0ef41Sopenharmony_ci  if context.verbose: print("#", " ".join(args))
6951cb0ef41Sopenharmony_ci  popen_args = args
6961cb0ef41Sopenharmony_ci  prev_error_mode = SEM_INVALID_VALUE
6971cb0ef41Sopenharmony_ci  if utils.IsWindows():
6981cb0ef41Sopenharmony_ci    if context.suppress_dialogs:
6991cb0ef41Sopenharmony_ci      # Try to change the error mode to avoid dialogs on fatal errors. Don't
7001cb0ef41Sopenharmony_ci      # touch any existing error mode flags by merging the existing error mode.
7011cb0ef41Sopenharmony_ci      # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
7021cb0ef41Sopenharmony_ci      error_mode = SEM_NOGPFAULTERRORBOX
7031cb0ef41Sopenharmony_ci      prev_error_mode = Win32SetErrorMode(error_mode)
7041cb0ef41Sopenharmony_ci      Win32SetErrorMode(error_mode | prev_error_mode)
7051cb0ef41Sopenharmony_ci
7061cb0ef41Sopenharmony_ci  process = subprocess.Popen(
7071cb0ef41Sopenharmony_ci    args = popen_args,
7081cb0ef41Sopenharmony_ci    **rest
7091cb0ef41Sopenharmony_ci  )
7101cb0ef41Sopenharmony_ci  if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
7111cb0ef41Sopenharmony_ci    Win32SetErrorMode(prev_error_mode)
7121cb0ef41Sopenharmony_ci  # Compute the end time - if the process crosses this limit we
7131cb0ef41Sopenharmony_ci  # consider it timed out.
7141cb0ef41Sopenharmony_ci  if timeout is None: end_time = None
7151cb0ef41Sopenharmony_ci  else: end_time = time.time() + timeout
7161cb0ef41Sopenharmony_ci  timed_out = False
7171cb0ef41Sopenharmony_ci  # Repeatedly check the exit code from the process in a
7181cb0ef41Sopenharmony_ci  # loop and keep track of whether or not it times out.
7191cb0ef41Sopenharmony_ci  exit_code = None
7201cb0ef41Sopenharmony_ci  sleep_time = INITIAL_SLEEP_TIME
7211cb0ef41Sopenharmony_ci
7221cb0ef41Sopenharmony_ci  while exit_code is None:
7231cb0ef41Sopenharmony_ci    if (not end_time is None) and (time.time() >= end_time):
7241cb0ef41Sopenharmony_ci      # Kill the process and wait for it to exit.
7251cb0ef41Sopenharmony_ci      KillTimedOutProcess(context, process.pid)
7261cb0ef41Sopenharmony_ci      exit_code = process.wait()
7271cb0ef41Sopenharmony_ci      timed_out = True
7281cb0ef41Sopenharmony_ci    else:
7291cb0ef41Sopenharmony_ci      exit_code = process.poll()
7301cb0ef41Sopenharmony_ci      time.sleep(sleep_time)
7311cb0ef41Sopenharmony_ci      sleep_time = sleep_time * SLEEP_TIME_FACTOR
7321cb0ef41Sopenharmony_ci      if sleep_time > MAX_SLEEP_TIME:
7331cb0ef41Sopenharmony_ci        sleep_time = MAX_SLEEP_TIME
7341cb0ef41Sopenharmony_ci  return (process, exit_code, timed_out)
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_cidef PrintError(str):
7381cb0ef41Sopenharmony_ci  sys.stderr.write(str)
7391cb0ef41Sopenharmony_ci  sys.stderr.write('\n')
7401cb0ef41Sopenharmony_ci
7411cb0ef41Sopenharmony_ci
7421cb0ef41Sopenharmony_cidef CheckedUnlink(name):
7431cb0ef41Sopenharmony_ci  while True:
7441cb0ef41Sopenharmony_ci    try:
7451cb0ef41Sopenharmony_ci      os.unlink(name)
7461cb0ef41Sopenharmony_ci    except OSError as e:
7471cb0ef41Sopenharmony_ci      # On Windows unlink() fails if another process (typically a virus scanner
7481cb0ef41Sopenharmony_ci      # or the indexing service) has the file open. Those processes keep a
7491cb0ef41Sopenharmony_ci      # file open for a short time only, so yield and try again; it'll succeed.
7501cb0ef41Sopenharmony_ci      if sys.platform == 'win32' and e.errno == errno.EACCES:
7511cb0ef41Sopenharmony_ci        time.sleep(0)
7521cb0ef41Sopenharmony_ci        continue
7531cb0ef41Sopenharmony_ci      PrintError("os.unlink() " + str(e))
7541cb0ef41Sopenharmony_ci    break
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_cidef Execute(args, context, timeout=None, env=None, disable_core_files=False, stdin=None):
7571cb0ef41Sopenharmony_ci  (fd_out, outname) = tempfile.mkstemp()
7581cb0ef41Sopenharmony_ci  (fd_err, errname) = tempfile.mkstemp()
7591cb0ef41Sopenharmony_ci
7601cb0ef41Sopenharmony_ci  if env is None:
7611cb0ef41Sopenharmony_ci    env = {}
7621cb0ef41Sopenharmony_ci  env_copy = os.environ.copy()
7631cb0ef41Sopenharmony_ci
7641cb0ef41Sopenharmony_ci  # Remove NODE_PATH
7651cb0ef41Sopenharmony_ci  if "NODE_PATH" in env_copy:
7661cb0ef41Sopenharmony_ci    del env_copy["NODE_PATH"]
7671cb0ef41Sopenharmony_ci
7681cb0ef41Sopenharmony_ci  # Remove NODE_REPL_EXTERNAL_MODULE
7691cb0ef41Sopenharmony_ci  if "NODE_REPL_EXTERNAL_MODULE" in env_copy:
7701cb0ef41Sopenharmony_ci    del env_copy["NODE_REPL_EXTERNAL_MODULE"]
7711cb0ef41Sopenharmony_ci
7721cb0ef41Sopenharmony_ci  # Extend environment
7731cb0ef41Sopenharmony_ci  for key, value in env.items():
7741cb0ef41Sopenharmony_ci    env_copy[key] = value
7751cb0ef41Sopenharmony_ci
7761cb0ef41Sopenharmony_ci  preexec_fn = None
7771cb0ef41Sopenharmony_ci
7781cb0ef41Sopenharmony_ci  if disable_core_files and not utils.IsWindows():
7791cb0ef41Sopenharmony_ci    def disableCoreFiles():
7801cb0ef41Sopenharmony_ci      import resource
7811cb0ef41Sopenharmony_ci      resource.setrlimit(resource.RLIMIT_CORE, (0,0))
7821cb0ef41Sopenharmony_ci    preexec_fn = disableCoreFiles
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci  (process, exit_code, timed_out) = RunProcess(
7851cb0ef41Sopenharmony_ci    context,
7861cb0ef41Sopenharmony_ci    timeout,
7871cb0ef41Sopenharmony_ci    args = args,
7881cb0ef41Sopenharmony_ci    stdin = stdin,
7891cb0ef41Sopenharmony_ci    stdout = fd_out,
7901cb0ef41Sopenharmony_ci    stderr = fd_err,
7911cb0ef41Sopenharmony_ci    env = env_copy,
7921cb0ef41Sopenharmony_ci    preexec_fn = preexec_fn
7931cb0ef41Sopenharmony_ci  )
7941cb0ef41Sopenharmony_ci  os.close(fd_out)
7951cb0ef41Sopenharmony_ci  os.close(fd_err)
7961cb0ef41Sopenharmony_ci  output = open(outname, encoding='utf8').read()
7971cb0ef41Sopenharmony_ci  errors = open(errname, encoding='utf8').read()
7981cb0ef41Sopenharmony_ci  CheckedUnlink(outname)
7991cb0ef41Sopenharmony_ci  CheckedUnlink(errname)
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_ci  return CommandOutput(exit_code, timed_out, output, errors)
8021cb0ef41Sopenharmony_ci
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_cidef CarCdr(path):
8051cb0ef41Sopenharmony_ci  if len(path) == 0:
8061cb0ef41Sopenharmony_ci    return (None, [ ])
8071cb0ef41Sopenharmony_ci  else:
8081cb0ef41Sopenharmony_ci    return (path[0], path[1:])
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ci
8111cb0ef41Sopenharmony_ciclass TestConfiguration(object):
8121cb0ef41Sopenharmony_ci  def __init__(self, context, root, section):
8131cb0ef41Sopenharmony_ci    self.context = context
8141cb0ef41Sopenharmony_ci    self.root = root
8151cb0ef41Sopenharmony_ci    self.section = section
8161cb0ef41Sopenharmony_ci
8171cb0ef41Sopenharmony_ci  def Contains(self, path, file):
8181cb0ef41Sopenharmony_ci    if len(path) > len(file):
8191cb0ef41Sopenharmony_ci      return False
8201cb0ef41Sopenharmony_ci    for i in range(len(path)):
8211cb0ef41Sopenharmony_ci      if not path[i].match(NormalizePath(file[i])):
8221cb0ef41Sopenharmony_ci        return False
8231cb0ef41Sopenharmony_ci    return True
8241cb0ef41Sopenharmony_ci
8251cb0ef41Sopenharmony_ci  def GetTestStatus(self, sections, defs):
8261cb0ef41Sopenharmony_ci    status_file = join(self.root, '%s.status' % self.section)
8271cb0ef41Sopenharmony_ci    if exists(status_file):
8281cb0ef41Sopenharmony_ci      ReadConfigurationInto(status_file, sections, defs)
8291cb0ef41Sopenharmony_ci
8301cb0ef41Sopenharmony_ci
8311cb0ef41Sopenharmony_ciclass TestSuite(object):
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_ci  def __init__(self, name):
8341cb0ef41Sopenharmony_ci    self.name = name
8351cb0ef41Sopenharmony_ci
8361cb0ef41Sopenharmony_ci  def GetName(self):
8371cb0ef41Sopenharmony_ci    return self.name
8381cb0ef41Sopenharmony_ci
8391cb0ef41Sopenharmony_ci
8401cb0ef41Sopenharmony_ciclass TestRepository(TestSuite):
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci  def __init__(self, path):
8431cb0ef41Sopenharmony_ci    normalized_path = abspath(path)
8441cb0ef41Sopenharmony_ci    super(TestRepository, self).__init__(basename(normalized_path))
8451cb0ef41Sopenharmony_ci    self.path = normalized_path
8461cb0ef41Sopenharmony_ci    self.is_loaded = False
8471cb0ef41Sopenharmony_ci    self.config = None
8481cb0ef41Sopenharmony_ci
8491cb0ef41Sopenharmony_ci  def GetConfiguration(self, context):
8501cb0ef41Sopenharmony_ci    if self.is_loaded:
8511cb0ef41Sopenharmony_ci      return self.config
8521cb0ef41Sopenharmony_ci    self.is_loaded = True
8531cb0ef41Sopenharmony_ci
8541cb0ef41Sopenharmony_ci    module = get_module('testcfg', self.path)
8551cb0ef41Sopenharmony_ci    self.config = module.GetConfiguration(context, self.path)
8561cb0ef41Sopenharmony_ci    if hasattr(self.config, 'additional_flags'):
8571cb0ef41Sopenharmony_ci      self.config.additional_flags += context.node_args
8581cb0ef41Sopenharmony_ci    else:
8591cb0ef41Sopenharmony_ci      self.config.additional_flags = context.node_args
8601cb0ef41Sopenharmony_ci    return self.config
8611cb0ef41Sopenharmony_ci
8621cb0ef41Sopenharmony_ci  def GetBuildRequirements(self, path, context):
8631cb0ef41Sopenharmony_ci    return self.GetConfiguration(context).GetBuildRequirements()
8641cb0ef41Sopenharmony_ci
8651cb0ef41Sopenharmony_ci  def AddTestsToList(self, result, current_path, path, context, arch, mode):
8661cb0ef41Sopenharmony_ci    tests = self.GetConfiguration(context).ListTests(current_path, path,
8671cb0ef41Sopenharmony_ci                                                     arch, mode)
8681cb0ef41Sopenharmony_ci    result += tests
8691cb0ef41Sopenharmony_ci    for i in range(1, context.repeat):
8701cb0ef41Sopenharmony_ci      result += copy.deepcopy(tests)
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ci  def GetTestStatus(self, context, sections, defs):
8731cb0ef41Sopenharmony_ci    self.GetConfiguration(context).GetTestStatus(sections, defs)
8741cb0ef41Sopenharmony_ci
8751cb0ef41Sopenharmony_ci
8761cb0ef41Sopenharmony_ciclass LiteralTestSuite(TestSuite):
8771cb0ef41Sopenharmony_ci  def __init__(self, tests_repos, test_root):
8781cb0ef41Sopenharmony_ci    super(LiteralTestSuite, self).__init__('root')
8791cb0ef41Sopenharmony_ci    self.tests_repos = tests_repos
8801cb0ef41Sopenharmony_ci    self.test_root = test_root
8811cb0ef41Sopenharmony_ci
8821cb0ef41Sopenharmony_ci  def GetBuildRequirements(self, path, context):
8831cb0ef41Sopenharmony_ci    (name, rest) = CarCdr(path)
8841cb0ef41Sopenharmony_ci    result = [ ]
8851cb0ef41Sopenharmony_ci    for test in self.tests_repos:
8861cb0ef41Sopenharmony_ci      if not name or name.match(test.GetName()):
8871cb0ef41Sopenharmony_ci        result += test.GetBuildRequirements(rest, context)
8881cb0ef41Sopenharmony_ci    return result
8891cb0ef41Sopenharmony_ci
8901cb0ef41Sopenharmony_ci  def ListTests(self, current_path, path, context, arch, mode):
8911cb0ef41Sopenharmony_ci    (name, rest) = CarCdr(path)
8921cb0ef41Sopenharmony_ci    result = [ ]
8931cb0ef41Sopenharmony_ci    for test in self.tests_repos:
8941cb0ef41Sopenharmony_ci      test_name = test.GetName()
8951cb0ef41Sopenharmony_ci      if not name or name.match(test_name):
8961cb0ef41Sopenharmony_ci        full_path = current_path + [test_name]
8971cb0ef41Sopenharmony_ci        test.AddTestsToList(result, full_path, path, context, arch, mode)
8981cb0ef41Sopenharmony_ci    result.sort(key=lambda x: x.GetName())
8991cb0ef41Sopenharmony_ci    return result
9001cb0ef41Sopenharmony_ci
9011cb0ef41Sopenharmony_ci  def GetTestStatus(self, context, sections, defs):
9021cb0ef41Sopenharmony_ci    # Just read the test configuration from root_path/root.status.
9031cb0ef41Sopenharmony_ci    root = TestConfiguration(context, self.test_root, 'root')
9041cb0ef41Sopenharmony_ci    root.GetTestStatus(sections, defs)
9051cb0ef41Sopenharmony_ci    for tests_repos in self.tests_repos:
9061cb0ef41Sopenharmony_ci      tests_repos.GetTestStatus(context, sections, defs)
9071cb0ef41Sopenharmony_ci
9081cb0ef41Sopenharmony_ci
9091cb0ef41Sopenharmony_ciTIMEOUT_SCALEFACTOR = {
9101cb0ef41Sopenharmony_ci    'arm'       : { 'debug' :  8, 'release' : 3 }, # The ARM buildbots are slow.
9111cb0ef41Sopenharmony_ci    'riscv64'   : { 'debug' :  8, 'release' : 3 }, # The riscv devices are slow.
9121cb0ef41Sopenharmony_ci    'ia32'      : { 'debug' :  4, 'release' : 1 },
9131cb0ef41Sopenharmony_ci    'ppc'       : { 'debug' :  4, 'release' : 1 },
9141cb0ef41Sopenharmony_ci    's390'      : { 'debug' :  4, 'release' : 1 } }
9151cb0ef41Sopenharmony_ci
9161cb0ef41Sopenharmony_ci
9171cb0ef41Sopenharmony_ciclass Context(object):
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci  def __init__(self, workspace, verbose, vm, args, expect_fail,
9201cb0ef41Sopenharmony_ci               timeout, processor, suppress_dialogs,
9211cb0ef41Sopenharmony_ci               store_unexpected_output, repeat, abort_on_timeout):
9221cb0ef41Sopenharmony_ci    self.workspace = workspace
9231cb0ef41Sopenharmony_ci    self.verbose = verbose
9241cb0ef41Sopenharmony_ci    self.vm = vm
9251cb0ef41Sopenharmony_ci    self.node_args = args
9261cb0ef41Sopenharmony_ci    self.expect_fail = expect_fail
9271cb0ef41Sopenharmony_ci    self.timeout = timeout
9281cb0ef41Sopenharmony_ci    self.processor = processor
9291cb0ef41Sopenharmony_ci    self.suppress_dialogs = suppress_dialogs
9301cb0ef41Sopenharmony_ci    self.store_unexpected_output = store_unexpected_output
9311cb0ef41Sopenharmony_ci    self.repeat = repeat
9321cb0ef41Sopenharmony_ci    self.abort_on_timeout = abort_on_timeout
9331cb0ef41Sopenharmony_ci    self.v8_enable_inspector = True
9341cb0ef41Sopenharmony_ci    self.node_has_crypto = True
9351cb0ef41Sopenharmony_ci
9361cb0ef41Sopenharmony_ci  def GetVm(self, arch, mode):
9371cb0ef41Sopenharmony_ci    if self.vm is not None:
9381cb0ef41Sopenharmony_ci      return self.vm
9391cb0ef41Sopenharmony_ci    if arch == 'none':
9401cb0ef41Sopenharmony_ci      name = 'out/Debug/node' if mode == 'debug' else 'out/Release/node'
9411cb0ef41Sopenharmony_ci    else:
9421cb0ef41Sopenharmony_ci      name = 'out/%s.%s/node' % (arch, mode)
9431cb0ef41Sopenharmony_ci
9441cb0ef41Sopenharmony_ci    # Currently GYP does not support output_dir for MSVS.
9451cb0ef41Sopenharmony_ci    # http://code.google.com/p/gyp/issues/detail?id=40
9461cb0ef41Sopenharmony_ci    # It will put the builds into Release/node.exe or Debug/node.exe
9471cb0ef41Sopenharmony_ci    if utils.IsWindows():
9481cb0ef41Sopenharmony_ci      if not exists(name + '.exe'):
9491cb0ef41Sopenharmony_ci        name = name.replace('out/', '')
9501cb0ef41Sopenharmony_ci      name = os.path.abspath(name + '.exe')
9511cb0ef41Sopenharmony_ci
9521cb0ef41Sopenharmony_ci    if not exists(name):
9531cb0ef41Sopenharmony_ci      raise ValueError('Could not find executable. Should be ' + name)
9541cb0ef41Sopenharmony_ci
9551cb0ef41Sopenharmony_ci    return name
9561cb0ef41Sopenharmony_ci
9571cb0ef41Sopenharmony_ci  def GetTimeout(self, mode, section=''):
9581cb0ef41Sopenharmony_ci    timeout = self.timeout * TIMEOUT_SCALEFACTOR[ARCH_GUESS or 'ia32'][mode]
9591cb0ef41Sopenharmony_ci    if section == 'pummel' or section == 'benchmark':
9601cb0ef41Sopenharmony_ci      timeout = timeout * 6
9611cb0ef41Sopenharmony_ci    # We run all WPT from one subset in the same process using workers.
9621cb0ef41Sopenharmony_ci    # As the number of the tests grow, it can take longer to run some of the
9631cb0ef41Sopenharmony_ci    # subsets, but it's still overall faster than running them in different
9641cb0ef41Sopenharmony_ci    # processes.
9651cb0ef41Sopenharmony_ci    elif section == 'wpt':
9661cb0ef41Sopenharmony_ci      timeout = timeout * 12
9671cb0ef41Sopenharmony_ci    return timeout
9681cb0ef41Sopenharmony_ci
9691cb0ef41Sopenharmony_cidef RunTestCases(cases_to_run, progress, tasks, flaky_tests_mode, measure_flakiness):
9701cb0ef41Sopenharmony_ci  progress = PROGRESS_INDICATORS[progress](cases_to_run, flaky_tests_mode, measure_flakiness)
9711cb0ef41Sopenharmony_ci  return progress.Run(tasks)
9721cb0ef41Sopenharmony_ci
9731cb0ef41Sopenharmony_ci# -------------------------------------------
9741cb0ef41Sopenharmony_ci# --- T e s t   C o n f i g u r a t i o n ---
9751cb0ef41Sopenharmony_ci# -------------------------------------------
9761cb0ef41Sopenharmony_ci
9771cb0ef41Sopenharmony_ci
9781cb0ef41Sopenharmony_ciRUN = 'run'
9791cb0ef41Sopenharmony_ciSKIP = 'skip'
9801cb0ef41Sopenharmony_ciFAIL = 'fail'
9811cb0ef41Sopenharmony_ciPASS = 'pass'
9821cb0ef41Sopenharmony_ciOKAY = 'okay'
9831cb0ef41Sopenharmony_ciTIMEOUT = 'timeout'
9841cb0ef41Sopenharmony_ciCRASH = 'crash'
9851cb0ef41Sopenharmony_ciSLOW = 'slow'
9861cb0ef41Sopenharmony_ciFLAKY = 'flaky'
9871cb0ef41Sopenharmony_ciDONTCARE = 'dontcare'
9881cb0ef41Sopenharmony_ciKEEP_RETRYING = 'keep_retrying'
9891cb0ef41Sopenharmony_ci
9901cb0ef41Sopenharmony_ciclass Expression(object):
9911cb0ef41Sopenharmony_ci  pass
9921cb0ef41Sopenharmony_ci
9931cb0ef41Sopenharmony_ci
9941cb0ef41Sopenharmony_ciclass Constant(Expression):
9951cb0ef41Sopenharmony_ci
9961cb0ef41Sopenharmony_ci  def __init__(self, value):
9971cb0ef41Sopenharmony_ci    self.value = value
9981cb0ef41Sopenharmony_ci
9991cb0ef41Sopenharmony_ci  def Evaluate(self, env, defs):
10001cb0ef41Sopenharmony_ci    return self.value
10011cb0ef41Sopenharmony_ci
10021cb0ef41Sopenharmony_ci
10031cb0ef41Sopenharmony_ciclass Variable(Expression):
10041cb0ef41Sopenharmony_ci
10051cb0ef41Sopenharmony_ci  def __init__(self, name):
10061cb0ef41Sopenharmony_ci    self.name = name
10071cb0ef41Sopenharmony_ci
10081cb0ef41Sopenharmony_ci  def GetOutcomes(self, env, defs):
10091cb0ef41Sopenharmony_ci    if self.name in env: return set([env[self.name]])
10101cb0ef41Sopenharmony_ci    else: return set()
10111cb0ef41Sopenharmony_ci
10121cb0ef41Sopenharmony_ci
10131cb0ef41Sopenharmony_ciclass Outcome(Expression):
10141cb0ef41Sopenharmony_ci
10151cb0ef41Sopenharmony_ci  def __init__(self, name):
10161cb0ef41Sopenharmony_ci    self.name = name
10171cb0ef41Sopenharmony_ci
10181cb0ef41Sopenharmony_ci  def GetOutcomes(self, env, defs):
10191cb0ef41Sopenharmony_ci    if self.name in defs:
10201cb0ef41Sopenharmony_ci      return defs[self.name].GetOutcomes(env, defs)
10211cb0ef41Sopenharmony_ci    else:
10221cb0ef41Sopenharmony_ci      return set([self.name])
10231cb0ef41Sopenharmony_ci
10241cb0ef41Sopenharmony_ci
10251cb0ef41Sopenharmony_ciclass Operation(Expression):
10261cb0ef41Sopenharmony_ci
10271cb0ef41Sopenharmony_ci  def __init__(self, left, op, right):
10281cb0ef41Sopenharmony_ci    self.left = left
10291cb0ef41Sopenharmony_ci    self.op = op
10301cb0ef41Sopenharmony_ci    self.right = right
10311cb0ef41Sopenharmony_ci
10321cb0ef41Sopenharmony_ci  def Evaluate(self, env, defs):
10331cb0ef41Sopenharmony_ci    if self.op == '||' or self.op == ',':
10341cb0ef41Sopenharmony_ci      return self.left.Evaluate(env, defs) or self.right.Evaluate(env, defs)
10351cb0ef41Sopenharmony_ci    elif self.op == 'if':
10361cb0ef41Sopenharmony_ci      return False
10371cb0ef41Sopenharmony_ci    elif self.op == '==':
10381cb0ef41Sopenharmony_ci      inter = self.left.GetOutcomes(env, defs) & self.right.GetOutcomes(env, defs)
10391cb0ef41Sopenharmony_ci      return bool(inter)
10401cb0ef41Sopenharmony_ci    else:
10411cb0ef41Sopenharmony_ci      assert self.op == '&&'
10421cb0ef41Sopenharmony_ci      return self.left.Evaluate(env, defs) and self.right.Evaluate(env, defs)
10431cb0ef41Sopenharmony_ci
10441cb0ef41Sopenharmony_ci  def GetOutcomes(self, env, defs):
10451cb0ef41Sopenharmony_ci    if self.op == '||' or self.op == ',':
10461cb0ef41Sopenharmony_ci      return self.left.GetOutcomes(env, defs) | self.right.GetOutcomes(env, defs)
10471cb0ef41Sopenharmony_ci    elif self.op == 'if':
10481cb0ef41Sopenharmony_ci      if self.right.Evaluate(env, defs):
10491cb0ef41Sopenharmony_ci        return self.left.GetOutcomes(env, defs)
10501cb0ef41Sopenharmony_ci      else:
10511cb0ef41Sopenharmony_ci        return set()
10521cb0ef41Sopenharmony_ci    else:
10531cb0ef41Sopenharmony_ci      assert self.op == '&&'
10541cb0ef41Sopenharmony_ci      return self.left.GetOutcomes(env, defs) & self.right.GetOutcomes(env, defs)
10551cb0ef41Sopenharmony_ci
10561cb0ef41Sopenharmony_ci
10571cb0ef41Sopenharmony_cidef IsAlpha(str):
10581cb0ef41Sopenharmony_ci  for char in str:
10591cb0ef41Sopenharmony_ci    if not (char.isalpha() or char.isdigit() or char == '_'):
10601cb0ef41Sopenharmony_ci      return False
10611cb0ef41Sopenharmony_ci  return True
10621cb0ef41Sopenharmony_ci
10631cb0ef41Sopenharmony_ci
10641cb0ef41Sopenharmony_ciclass Tokenizer(object):
10651cb0ef41Sopenharmony_ci  """A simple string tokenizer that chops expressions into variables,
10661cb0ef41Sopenharmony_ci  parens and operators"""
10671cb0ef41Sopenharmony_ci
10681cb0ef41Sopenharmony_ci  def __init__(self, expr):
10691cb0ef41Sopenharmony_ci    self.index = 0
10701cb0ef41Sopenharmony_ci    self.expr = expr
10711cb0ef41Sopenharmony_ci    self.length = len(expr)
10721cb0ef41Sopenharmony_ci    self.tokens = None
10731cb0ef41Sopenharmony_ci
10741cb0ef41Sopenharmony_ci  def Current(self, length = 1):
10751cb0ef41Sopenharmony_ci    if not self.HasMore(length): return ""
10761cb0ef41Sopenharmony_ci    return self.expr[self.index:self.index+length]
10771cb0ef41Sopenharmony_ci
10781cb0ef41Sopenharmony_ci  def HasMore(self, length = 1):
10791cb0ef41Sopenharmony_ci    return self.index < self.length + (length - 1)
10801cb0ef41Sopenharmony_ci
10811cb0ef41Sopenharmony_ci  def Advance(self, count = 1):
10821cb0ef41Sopenharmony_ci    self.index = self.index + count
10831cb0ef41Sopenharmony_ci
10841cb0ef41Sopenharmony_ci  def AddToken(self, token):
10851cb0ef41Sopenharmony_ci    self.tokens.append(token)
10861cb0ef41Sopenharmony_ci
10871cb0ef41Sopenharmony_ci  def SkipSpaces(self):
10881cb0ef41Sopenharmony_ci    while self.HasMore() and self.Current().isspace():
10891cb0ef41Sopenharmony_ci      self.Advance()
10901cb0ef41Sopenharmony_ci
10911cb0ef41Sopenharmony_ci  def Tokenize(self):
10921cb0ef41Sopenharmony_ci    self.tokens = [ ]
10931cb0ef41Sopenharmony_ci    while self.HasMore():
10941cb0ef41Sopenharmony_ci      self.SkipSpaces()
10951cb0ef41Sopenharmony_ci      if not self.HasMore():
10961cb0ef41Sopenharmony_ci        return None
10971cb0ef41Sopenharmony_ci      if self.Current() == '(':
10981cb0ef41Sopenharmony_ci        self.AddToken('(')
10991cb0ef41Sopenharmony_ci        self.Advance()
11001cb0ef41Sopenharmony_ci      elif self.Current() == ')':
11011cb0ef41Sopenharmony_ci        self.AddToken(')')
11021cb0ef41Sopenharmony_ci        self.Advance()
11031cb0ef41Sopenharmony_ci      elif self.Current() == '$':
11041cb0ef41Sopenharmony_ci        self.AddToken('$')
11051cb0ef41Sopenharmony_ci        self.Advance()
11061cb0ef41Sopenharmony_ci      elif self.Current() == ',':
11071cb0ef41Sopenharmony_ci        self.AddToken(',')
11081cb0ef41Sopenharmony_ci        self.Advance()
11091cb0ef41Sopenharmony_ci      elif IsAlpha(self.Current()):
11101cb0ef41Sopenharmony_ci        buf = ""
11111cb0ef41Sopenharmony_ci        while self.HasMore() and IsAlpha(self.Current()):
11121cb0ef41Sopenharmony_ci          buf += self.Current()
11131cb0ef41Sopenharmony_ci          self.Advance()
11141cb0ef41Sopenharmony_ci        self.AddToken(buf)
11151cb0ef41Sopenharmony_ci      elif self.Current(2) == '&&':
11161cb0ef41Sopenharmony_ci        self.AddToken('&&')
11171cb0ef41Sopenharmony_ci        self.Advance(2)
11181cb0ef41Sopenharmony_ci      elif self.Current(2) == '||':
11191cb0ef41Sopenharmony_ci        self.AddToken('||')
11201cb0ef41Sopenharmony_ci        self.Advance(2)
11211cb0ef41Sopenharmony_ci      elif self.Current(2) == '==':
11221cb0ef41Sopenharmony_ci        self.AddToken('==')
11231cb0ef41Sopenharmony_ci        self.Advance(2)
11241cb0ef41Sopenharmony_ci      else:
11251cb0ef41Sopenharmony_ci        return None
11261cb0ef41Sopenharmony_ci    return self.tokens
11271cb0ef41Sopenharmony_ci
11281cb0ef41Sopenharmony_ci
11291cb0ef41Sopenharmony_ciclass Scanner(object):
11301cb0ef41Sopenharmony_ci  """A simple scanner that can serve out tokens from a given list"""
11311cb0ef41Sopenharmony_ci
11321cb0ef41Sopenharmony_ci  def __init__(self, tokens):
11331cb0ef41Sopenharmony_ci    self.tokens = tokens
11341cb0ef41Sopenharmony_ci    self.length = len(tokens)
11351cb0ef41Sopenharmony_ci    self.index = 0
11361cb0ef41Sopenharmony_ci
11371cb0ef41Sopenharmony_ci  def HasMore(self):
11381cb0ef41Sopenharmony_ci    return self.index < self.length
11391cb0ef41Sopenharmony_ci
11401cb0ef41Sopenharmony_ci  def Current(self):
11411cb0ef41Sopenharmony_ci    return self.tokens[self.index]
11421cb0ef41Sopenharmony_ci
11431cb0ef41Sopenharmony_ci  def Advance(self):
11441cb0ef41Sopenharmony_ci    self.index = self.index + 1
11451cb0ef41Sopenharmony_ci
11461cb0ef41Sopenharmony_ci
11471cb0ef41Sopenharmony_cidef ParseAtomicExpression(scan):
11481cb0ef41Sopenharmony_ci  if scan.Current() == "true":
11491cb0ef41Sopenharmony_ci    scan.Advance()
11501cb0ef41Sopenharmony_ci    return Constant(True)
11511cb0ef41Sopenharmony_ci  elif scan.Current() == "false":
11521cb0ef41Sopenharmony_ci    scan.Advance()
11531cb0ef41Sopenharmony_ci    return Constant(False)
11541cb0ef41Sopenharmony_ci  elif IsAlpha(scan.Current()):
11551cb0ef41Sopenharmony_ci    name = scan.Current()
11561cb0ef41Sopenharmony_ci    scan.Advance()
11571cb0ef41Sopenharmony_ci    return Outcome(name.lower())
11581cb0ef41Sopenharmony_ci  elif scan.Current() == '$':
11591cb0ef41Sopenharmony_ci    scan.Advance()
11601cb0ef41Sopenharmony_ci    if not IsAlpha(scan.Current()):
11611cb0ef41Sopenharmony_ci      return None
11621cb0ef41Sopenharmony_ci    name = scan.Current()
11631cb0ef41Sopenharmony_ci    scan.Advance()
11641cb0ef41Sopenharmony_ci    return Variable(name.lower())
11651cb0ef41Sopenharmony_ci  elif scan.Current() == '(':
11661cb0ef41Sopenharmony_ci    scan.Advance()
11671cb0ef41Sopenharmony_ci    result = ParseLogicalExpression(scan)
11681cb0ef41Sopenharmony_ci    if (not result) or (scan.Current() != ')'):
11691cb0ef41Sopenharmony_ci      return None
11701cb0ef41Sopenharmony_ci    scan.Advance()
11711cb0ef41Sopenharmony_ci    return result
11721cb0ef41Sopenharmony_ci  else:
11731cb0ef41Sopenharmony_ci    return None
11741cb0ef41Sopenharmony_ci
11751cb0ef41Sopenharmony_ci
11761cb0ef41Sopenharmony_ciBINARIES = ['==']
11771cb0ef41Sopenharmony_cidef ParseOperatorExpression(scan):
11781cb0ef41Sopenharmony_ci  left = ParseAtomicExpression(scan)
11791cb0ef41Sopenharmony_ci  if not left: return None
11801cb0ef41Sopenharmony_ci  while scan.HasMore() and (scan.Current() in BINARIES):
11811cb0ef41Sopenharmony_ci    op = scan.Current()
11821cb0ef41Sopenharmony_ci    scan.Advance()
11831cb0ef41Sopenharmony_ci    right = ParseOperatorExpression(scan)
11841cb0ef41Sopenharmony_ci    if not right:
11851cb0ef41Sopenharmony_ci      return None
11861cb0ef41Sopenharmony_ci    left = Operation(left, op, right)
11871cb0ef41Sopenharmony_ci  return left
11881cb0ef41Sopenharmony_ci
11891cb0ef41Sopenharmony_ci
11901cb0ef41Sopenharmony_cidef ParseConditionalExpression(scan):
11911cb0ef41Sopenharmony_ci  left = ParseOperatorExpression(scan)
11921cb0ef41Sopenharmony_ci  if not left: return None
11931cb0ef41Sopenharmony_ci  while scan.HasMore() and (scan.Current() == 'if'):
11941cb0ef41Sopenharmony_ci    scan.Advance()
11951cb0ef41Sopenharmony_ci    right = ParseOperatorExpression(scan)
11961cb0ef41Sopenharmony_ci    if not right:
11971cb0ef41Sopenharmony_ci      return None
11981cb0ef41Sopenharmony_ci    left=  Operation(left, 'if', right)
11991cb0ef41Sopenharmony_ci  return left
12001cb0ef41Sopenharmony_ci
12011cb0ef41Sopenharmony_ci
12021cb0ef41Sopenharmony_ciLOGICALS = ["&&", "||", ","]
12031cb0ef41Sopenharmony_cidef ParseLogicalExpression(scan):
12041cb0ef41Sopenharmony_ci  left = ParseConditionalExpression(scan)
12051cb0ef41Sopenharmony_ci  if not left: return None
12061cb0ef41Sopenharmony_ci  while scan.HasMore() and (scan.Current() in LOGICALS):
12071cb0ef41Sopenharmony_ci    op = scan.Current()
12081cb0ef41Sopenharmony_ci    scan.Advance()
12091cb0ef41Sopenharmony_ci    right = ParseConditionalExpression(scan)
12101cb0ef41Sopenharmony_ci    if not right:
12111cb0ef41Sopenharmony_ci      return None
12121cb0ef41Sopenharmony_ci    left = Operation(left, op, right)
12131cb0ef41Sopenharmony_ci  return left
12141cb0ef41Sopenharmony_ci
12151cb0ef41Sopenharmony_ci
12161cb0ef41Sopenharmony_cidef ParseCondition(expr):
12171cb0ef41Sopenharmony_ci  """Parses a logical expression into an Expression object"""
12181cb0ef41Sopenharmony_ci  tokens = Tokenizer(expr).Tokenize()
12191cb0ef41Sopenharmony_ci  if not tokens:
12201cb0ef41Sopenharmony_ci    print("Malformed expression: '%s'" % expr)
12211cb0ef41Sopenharmony_ci    return None
12221cb0ef41Sopenharmony_ci  scan = Scanner(tokens)
12231cb0ef41Sopenharmony_ci  ast = ParseLogicalExpression(scan)
12241cb0ef41Sopenharmony_ci  if not ast:
12251cb0ef41Sopenharmony_ci    print("Malformed expression: '%s'" % expr)
12261cb0ef41Sopenharmony_ci    return None
12271cb0ef41Sopenharmony_ci  if scan.HasMore():
12281cb0ef41Sopenharmony_ci    print("Malformed expression: '%s'" % expr)
12291cb0ef41Sopenharmony_ci    return None
12301cb0ef41Sopenharmony_ci  return ast
12311cb0ef41Sopenharmony_ci
12321cb0ef41Sopenharmony_ci
12331cb0ef41Sopenharmony_ciclass Configuration(object):
12341cb0ef41Sopenharmony_ci  """The parsed contents of a configuration file"""
12351cb0ef41Sopenharmony_ci
12361cb0ef41Sopenharmony_ci  def __init__(self, sections, defs):
12371cb0ef41Sopenharmony_ci    self.sections = sections
12381cb0ef41Sopenharmony_ci    self.defs = defs
12391cb0ef41Sopenharmony_ci
12401cb0ef41Sopenharmony_ci  def ClassifyTests(self, cases, env):
12411cb0ef41Sopenharmony_ci    sections = [ s for s in self.sections if s.condition.Evaluate(env, self.defs) ]
12421cb0ef41Sopenharmony_ci    all_rules = reduce(list.__add__, [s.rules for s in sections], [])
12431cb0ef41Sopenharmony_ci    unused_rules = set(all_rules)
12441cb0ef41Sopenharmony_ci    result = []
12451cb0ef41Sopenharmony_ci    for case in cases:
12461cb0ef41Sopenharmony_ci      matches = [ r for r in all_rules if r.Contains(case.path) ]
12471cb0ef41Sopenharmony_ci      outcomes_list = [ r.GetOutcomes(env, self.defs) for r in matches ]
12481cb0ef41Sopenharmony_ci      outcomes = reduce(set.union, outcomes_list, set())
12491cb0ef41Sopenharmony_ci      unused_rules.difference_update(matches)
12501cb0ef41Sopenharmony_ci      case.outcomes = set(outcomes) or set([PASS])
12511cb0ef41Sopenharmony_ci      # slow tests may also just pass.
12521cb0ef41Sopenharmony_ci      if SLOW in case.outcomes:
12531cb0ef41Sopenharmony_ci        case.outcomes.add(PASS)
12541cb0ef41Sopenharmony_ci      result.append(case)
12551cb0ef41Sopenharmony_ci    return result, unused_rules
12561cb0ef41Sopenharmony_ci
12571cb0ef41Sopenharmony_ci
12581cb0ef41Sopenharmony_ciclass Section(object):
12591cb0ef41Sopenharmony_ci  """A section of the configuration file.  Sections are enabled or
12601cb0ef41Sopenharmony_ci  disabled prior to running the tests, based on their conditions"""
12611cb0ef41Sopenharmony_ci
12621cb0ef41Sopenharmony_ci  def __init__(self, condition):
12631cb0ef41Sopenharmony_ci    self.condition = condition
12641cb0ef41Sopenharmony_ci    self.rules = [ ]
12651cb0ef41Sopenharmony_ci
12661cb0ef41Sopenharmony_ci  def AddRule(self, rule):
12671cb0ef41Sopenharmony_ci    self.rules.append(rule)
12681cb0ef41Sopenharmony_ci
12691cb0ef41Sopenharmony_ci
12701cb0ef41Sopenharmony_ciclass Rule(object):
12711cb0ef41Sopenharmony_ci  """A single rule that specifies the expected outcome for a single
12721cb0ef41Sopenharmony_ci  test."""
12731cb0ef41Sopenharmony_ci
12741cb0ef41Sopenharmony_ci  def __init__(self, raw_path, path, value):
12751cb0ef41Sopenharmony_ci    self.raw_path = raw_path
12761cb0ef41Sopenharmony_ci    self.path = path
12771cb0ef41Sopenharmony_ci    self.value = value
12781cb0ef41Sopenharmony_ci
12791cb0ef41Sopenharmony_ci  def GetOutcomes(self, env, defs):
12801cb0ef41Sopenharmony_ci    return self.value.GetOutcomes(env, defs)
12811cb0ef41Sopenharmony_ci
12821cb0ef41Sopenharmony_ci  def Contains(self, path):
12831cb0ef41Sopenharmony_ci    if len(self.path) > len(path):
12841cb0ef41Sopenharmony_ci      return False
12851cb0ef41Sopenharmony_ci    for i in range(len(self.path)):
12861cb0ef41Sopenharmony_ci      if not self.path[i].match(path[i]):
12871cb0ef41Sopenharmony_ci        return False
12881cb0ef41Sopenharmony_ci    return True
12891cb0ef41Sopenharmony_ci
12901cb0ef41Sopenharmony_ci
12911cb0ef41Sopenharmony_ciHEADER_PATTERN = re.compile(r'\[([^]]+)\]')
12921cb0ef41Sopenharmony_ciRULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
12931cb0ef41Sopenharmony_ciDEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
12941cb0ef41Sopenharmony_ciPREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w_.\-/]+)$')
12951cb0ef41Sopenharmony_ci
12961cb0ef41Sopenharmony_ci
12971cb0ef41Sopenharmony_cidef ReadConfigurationInto(path, sections, defs):
12981cb0ef41Sopenharmony_ci  current_section = Section(Constant(True))
12991cb0ef41Sopenharmony_ci  sections.append(current_section)
13001cb0ef41Sopenharmony_ci  prefix = []
13011cb0ef41Sopenharmony_ci  for line in utils.ReadLinesFrom(path):
13021cb0ef41Sopenharmony_ci    header_match = HEADER_PATTERN.match(line)
13031cb0ef41Sopenharmony_ci    if header_match:
13041cb0ef41Sopenharmony_ci      condition_str = header_match.group(1).strip()
13051cb0ef41Sopenharmony_ci      condition = ParseCondition(condition_str)
13061cb0ef41Sopenharmony_ci      new_section = Section(condition)
13071cb0ef41Sopenharmony_ci      sections.append(new_section)
13081cb0ef41Sopenharmony_ci      current_section = new_section
13091cb0ef41Sopenharmony_ci      continue
13101cb0ef41Sopenharmony_ci    rule_match = RULE_PATTERN.match(line)
13111cb0ef41Sopenharmony_ci    if rule_match:
13121cb0ef41Sopenharmony_ci      path = prefix + SplitPath(rule_match.group(1).strip())
13131cb0ef41Sopenharmony_ci      value_str = rule_match.group(2).strip()
13141cb0ef41Sopenharmony_ci      value = ParseCondition(value_str)
13151cb0ef41Sopenharmony_ci      if not value:
13161cb0ef41Sopenharmony_ci        return False
13171cb0ef41Sopenharmony_ci      current_section.AddRule(Rule(rule_match.group(1), path, value))
13181cb0ef41Sopenharmony_ci      continue
13191cb0ef41Sopenharmony_ci    def_match = DEF_PATTERN.match(line)
13201cb0ef41Sopenharmony_ci    if def_match:
13211cb0ef41Sopenharmony_ci      name = def_match.group(1).lower()
13221cb0ef41Sopenharmony_ci      value = ParseCondition(def_match.group(2).strip())
13231cb0ef41Sopenharmony_ci      if not value:
13241cb0ef41Sopenharmony_ci        return False
13251cb0ef41Sopenharmony_ci      defs[name] = value
13261cb0ef41Sopenharmony_ci      continue
13271cb0ef41Sopenharmony_ci    prefix_match = PREFIX_PATTERN.match(line)
13281cb0ef41Sopenharmony_ci    if prefix_match:
13291cb0ef41Sopenharmony_ci      prefix = SplitPath(prefix_match.group(1).strip())
13301cb0ef41Sopenharmony_ci      continue
13311cb0ef41Sopenharmony_ci    raise Exception("Malformed line: '%s'." % line)
13321cb0ef41Sopenharmony_ci
13331cb0ef41Sopenharmony_ci
13341cb0ef41Sopenharmony_ci# ---------------
13351cb0ef41Sopenharmony_ci# --- M a i n ---
13361cb0ef41Sopenharmony_ci# ---------------
13371cb0ef41Sopenharmony_ci
13381cb0ef41Sopenharmony_ci
13391cb0ef41Sopenharmony_ciARCH_GUESS = utils.GuessArchitecture()
13401cb0ef41Sopenharmony_ci
13411cb0ef41Sopenharmony_ci
13421cb0ef41Sopenharmony_cidef BuildOptions():
13431cb0ef41Sopenharmony_ci  result = optparse.OptionParser()
13441cb0ef41Sopenharmony_ci  result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)",
13451cb0ef41Sopenharmony_ci      default='release')
13461cb0ef41Sopenharmony_ci  result.add_option("-v", "--verbose", help="Verbose output",
13471cb0ef41Sopenharmony_ci      default=False, action="store_true")
13481cb0ef41Sopenharmony_ci  result.add_option('--logfile', dest='logfile',
13491cb0ef41Sopenharmony_ci      help='write test output to file. NOTE: this only applies the tap progress indicator')
13501cb0ef41Sopenharmony_ci  result.add_option("-p", "--progress",
13511cb0ef41Sopenharmony_ci      help="The style of progress indicator (%s)" % ", ".join(PROGRESS_INDICATORS.keys()),
13521cb0ef41Sopenharmony_ci      choices=list(PROGRESS_INDICATORS.keys()), default="mono")
13531cb0ef41Sopenharmony_ci  result.add_option("--report", help="Print a summary of the tests to be run",
13541cb0ef41Sopenharmony_ci      default=False, action="store_true")
13551cb0ef41Sopenharmony_ci  result.add_option("-s", "--suite", help="A test suite",
13561cb0ef41Sopenharmony_ci      default=[], action="append")
13571cb0ef41Sopenharmony_ci  result.add_option("-t", "--timeout", help="Timeout in seconds",
13581cb0ef41Sopenharmony_ci      default=120, type="int")
13591cb0ef41Sopenharmony_ci  result.add_option("--arch", help='The architecture to run tests for',
13601cb0ef41Sopenharmony_ci      default='none')
13611cb0ef41Sopenharmony_ci  result.add_option("--snapshot", help="Run the tests with snapshot turned on",
13621cb0ef41Sopenharmony_ci      default=False, action="store_true")
13631cb0ef41Sopenharmony_ci  result.add_option("--special-command", default=None)
13641cb0ef41Sopenharmony_ci  result.add_option("--node-args", dest="node_args", help="Args to pass through to Node",
13651cb0ef41Sopenharmony_ci      default=[], action="append")
13661cb0ef41Sopenharmony_ci  result.add_option("--expect-fail", dest="expect_fail",
13671cb0ef41Sopenharmony_ci      help="Expect test cases to fail", default=False, action="store_true")
13681cb0ef41Sopenharmony_ci  result.add_option("--valgrind", help="Run tests through valgrind",
13691cb0ef41Sopenharmony_ci      default=False, action="store_true")
13701cb0ef41Sopenharmony_ci  result.add_option("--worker", help="Run parallel tests inside a worker context",
13711cb0ef41Sopenharmony_ci      default=False, action="store_true")
13721cb0ef41Sopenharmony_ci  result.add_option("--check-deopts", help="Check tests for permanent deoptimizations",
13731cb0ef41Sopenharmony_ci      default=False, action="store_true")
13741cb0ef41Sopenharmony_ci  result.add_option("--cat", help="Print the source of the tests",
13751cb0ef41Sopenharmony_ci      default=False, action="store_true")
13761cb0ef41Sopenharmony_ci  result.add_option("--flaky-tests",
13771cb0ef41Sopenharmony_ci      help="Regard tests marked as flaky (run|skip|dontcare|keep_retrying)",
13781cb0ef41Sopenharmony_ci      default="run")
13791cb0ef41Sopenharmony_ci  result.add_option("--measure-flakiness",
13801cb0ef41Sopenharmony_ci      help="When a test fails, re-run it x number of times",
13811cb0ef41Sopenharmony_ci      default=0, type="int")
13821cb0ef41Sopenharmony_ci  result.add_option("--skip-tests",
13831cb0ef41Sopenharmony_ci      help="Tests that should not be executed (comma-separated)",
13841cb0ef41Sopenharmony_ci      default="")
13851cb0ef41Sopenharmony_ci  result.add_option("--warn-unused", help="Report unused rules",
13861cb0ef41Sopenharmony_ci      default=False, action="store_true")
13871cb0ef41Sopenharmony_ci  result.add_option("-j", help="The number of parallel tasks to run, 0=use number of cores",
13881cb0ef41Sopenharmony_ci      default=0, type="int")
13891cb0ef41Sopenharmony_ci  result.add_option("-J", help="For legacy compatibility, has no effect",
13901cb0ef41Sopenharmony_ci      default=False, action="store_true")
13911cb0ef41Sopenharmony_ci  result.add_option("--time", help="Print timing information after running",
13921cb0ef41Sopenharmony_ci      default=False, action="store_true")
13931cb0ef41Sopenharmony_ci  result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests",
13941cb0ef41Sopenharmony_ci        dest="suppress_dialogs", default=True, action="store_true")
13951cb0ef41Sopenharmony_ci  result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
13961cb0ef41Sopenharmony_ci        dest="suppress_dialogs", action="store_false")
13971cb0ef41Sopenharmony_ci  result.add_option("--shell", help="Path to node executable", default=None)
13981cb0ef41Sopenharmony_ci  result.add_option("--store-unexpected-output",
13991cb0ef41Sopenharmony_ci      help="Store the temporary JS files from tests that fails",
14001cb0ef41Sopenharmony_ci      dest="store_unexpected_output", default=True, action="store_true")
14011cb0ef41Sopenharmony_ci  result.add_option("--no-store-unexpected-output",
14021cb0ef41Sopenharmony_ci      help="Deletes the temporary JS files from tests that fails",
14031cb0ef41Sopenharmony_ci      dest="store_unexpected_output", action="store_false")
14041cb0ef41Sopenharmony_ci  result.add_option("-r", "--run",
14051cb0ef41Sopenharmony_ci      help="Divide the tests in m groups (interleaved) and run tests from group n (--run=n,m with n < m)",
14061cb0ef41Sopenharmony_ci      default="")
14071cb0ef41Sopenharmony_ci  result.add_option('--temp-dir',
14081cb0ef41Sopenharmony_ci      help='Optional path to change directory used for tests', default=False)
14091cb0ef41Sopenharmony_ci  result.add_option('--test-root',
14101cb0ef41Sopenharmony_ci      help='Optional path to change test directory', dest='test_root', default=None)
14111cb0ef41Sopenharmony_ci  result.add_option('--repeat',
14121cb0ef41Sopenharmony_ci      help='Number of times to repeat given tests',
14131cb0ef41Sopenharmony_ci      default=1, type="int")
14141cb0ef41Sopenharmony_ci  result.add_option('--abort-on-timeout',
14151cb0ef41Sopenharmony_ci      help='Send SIGABRT instead of SIGTERM to kill processes that time out',
14161cb0ef41Sopenharmony_ci      default=False, action="store_true", dest="abort_on_timeout")
14171cb0ef41Sopenharmony_ci  result.add_option("--type",
14181cb0ef41Sopenharmony_ci      help="Type of build (simple, fips, coverage)",
14191cb0ef41Sopenharmony_ci      default=None)
14201cb0ef41Sopenharmony_ci  return result
14211cb0ef41Sopenharmony_ci
14221cb0ef41Sopenharmony_ci
14231cb0ef41Sopenharmony_cidef ProcessOptions(options):
14241cb0ef41Sopenharmony_ci  global VERBOSE
14251cb0ef41Sopenharmony_ci  VERBOSE = options.verbose
14261cb0ef41Sopenharmony_ci  options.arch = options.arch.split(',')
14271cb0ef41Sopenharmony_ci  options.mode = options.mode.split(',')
14281cb0ef41Sopenharmony_ci  options.run = options.run.split(',')
14291cb0ef41Sopenharmony_ci  # Split at commas and filter out all the empty strings.
14301cb0ef41Sopenharmony_ci  options.skip_tests = [test for test in options.skip_tests.split(',') if test]
14311cb0ef41Sopenharmony_ci  if options.run == [""]:
14321cb0ef41Sopenharmony_ci    options.run = None
14331cb0ef41Sopenharmony_ci  elif len(options.run) != 2:
14341cb0ef41Sopenharmony_ci    print("The run argument must be two comma-separated integers.")
14351cb0ef41Sopenharmony_ci    return False
14361cb0ef41Sopenharmony_ci  else:
14371cb0ef41Sopenharmony_ci    try:
14381cb0ef41Sopenharmony_ci      options.run = [int(level) for level in options.run]
14391cb0ef41Sopenharmony_ci    except ValueError:
14401cb0ef41Sopenharmony_ci      print("Could not parse the integers from the run argument.")
14411cb0ef41Sopenharmony_ci      return False
14421cb0ef41Sopenharmony_ci    if options.run[0] < 0 or options.run[1] < 0:
14431cb0ef41Sopenharmony_ci      print("The run argument cannot have negative integers.")
14441cb0ef41Sopenharmony_ci      return False
14451cb0ef41Sopenharmony_ci    if options.run[0] >= options.run[1]:
14461cb0ef41Sopenharmony_ci      print("The test group to run (n) must be smaller than number of groups (m).")
14471cb0ef41Sopenharmony_ci      return False
14481cb0ef41Sopenharmony_ci  if options.j == 0:
14491cb0ef41Sopenharmony_ci    # inherit JOBS from environment if provided. some virtualised systems
14501cb0ef41Sopenharmony_ci    # tends to exaggerate the number of available cpus/cores.
14511cb0ef41Sopenharmony_ci    cores = os.environ.get('JOBS')
14521cb0ef41Sopenharmony_ci    options.j = int(cores) if cores is not None else multiprocessing.cpu_count()
14531cb0ef41Sopenharmony_ci  elif options.J:
14541cb0ef41Sopenharmony_ci    # If someone uses -j and legacy -J, let them know that we will be respecting
14551cb0ef41Sopenharmony_ci    # -j and ignoring -J, which is the opposite of what we used to do before -J
14561cb0ef41Sopenharmony_ci    # became a legacy no-op.
14571cb0ef41Sopenharmony_ci    print('Warning: Legacy -J option is ignored. Using the -j option.')
14581cb0ef41Sopenharmony_ci  if options.flaky_tests not in [RUN, SKIP, DONTCARE, KEEP_RETRYING]:
14591cb0ef41Sopenharmony_ci    print("Unknown flaky-tests mode %s" % options.flaky_tests)
14601cb0ef41Sopenharmony_ci    return False
14611cb0ef41Sopenharmony_ci  return True
14621cb0ef41Sopenharmony_ci
14631cb0ef41Sopenharmony_ci
14641cb0ef41Sopenharmony_ciREPORT_TEMPLATE = """\
14651cb0ef41Sopenharmony_ciTotal: %(total)i tests
14661cb0ef41Sopenharmony_ci * %(skipped)4d tests will be skipped
14671cb0ef41Sopenharmony_ci * %(pass)4d tests are expected to pass
14681cb0ef41Sopenharmony_ci * %(fail_ok)4d tests are expected to fail that we won't fix
14691cb0ef41Sopenharmony_ci * %(fail)4d tests are expected to fail that we should fix\
14701cb0ef41Sopenharmony_ci"""
14711cb0ef41Sopenharmony_ci
14721cb0ef41Sopenharmony_ci
14731cb0ef41Sopenharmony_ciclass Pattern(object):
14741cb0ef41Sopenharmony_ci
14751cb0ef41Sopenharmony_ci  def __init__(self, pattern):
14761cb0ef41Sopenharmony_ci    self.pattern = pattern
14771cb0ef41Sopenharmony_ci    self.compiled = None
14781cb0ef41Sopenharmony_ci
14791cb0ef41Sopenharmony_ci  def match(self, str):
14801cb0ef41Sopenharmony_ci    if not self.compiled:
14811cb0ef41Sopenharmony_ci      pattern = "^" + self.pattern.replace('*', '.*') + "$"
14821cb0ef41Sopenharmony_ci      self.compiled = re.compile(pattern)
14831cb0ef41Sopenharmony_ci    return self.compiled.match(str)
14841cb0ef41Sopenharmony_ci
14851cb0ef41Sopenharmony_ci  def __str__(self):
14861cb0ef41Sopenharmony_ci    return self.pattern
14871cb0ef41Sopenharmony_ci
14881cb0ef41Sopenharmony_ci
14891cb0ef41Sopenharmony_cidef SplitPath(path_arg):
14901cb0ef41Sopenharmony_ci  stripped = [c.strip() for c in path_arg.split('/')]
14911cb0ef41Sopenharmony_ci  return [Pattern(s) for s in stripped if len(s) > 0]
14921cb0ef41Sopenharmony_ci
14931cb0ef41Sopenharmony_cidef NormalizePath(path, prefix='test/'):
14941cb0ef41Sopenharmony_ci  # strip the extra path information of the specified test
14951cb0ef41Sopenharmony_ci  prefix = prefix.replace('\\', '/')
14961cb0ef41Sopenharmony_ci  path = path.replace('\\', '/')
14971cb0ef41Sopenharmony_ci  if path.startswith(prefix):
14981cb0ef41Sopenharmony_ci    path = path[len(prefix):]
14991cb0ef41Sopenharmony_ci  if path.endswith('.js'):
15001cb0ef41Sopenharmony_ci    path = path[:-3]
15011cb0ef41Sopenharmony_ci  elif path.endswith('.mjs'):
15021cb0ef41Sopenharmony_ci    path = path[:-4]
15031cb0ef41Sopenharmony_ci  return path
15041cb0ef41Sopenharmony_ci
15051cb0ef41Sopenharmony_cidef GetSpecialCommandProcessor(value):
15061cb0ef41Sopenharmony_ci  if (not value) or (value.find('@') == -1):
15071cb0ef41Sopenharmony_ci    def ExpandCommand(args):
15081cb0ef41Sopenharmony_ci      return args
15091cb0ef41Sopenharmony_ci    return ExpandCommand
15101cb0ef41Sopenharmony_ci  else:
15111cb0ef41Sopenharmony_ci    prefix, _, suffix = value.partition('@')
15121cb0ef41Sopenharmony_ci    prefix = unquote(prefix).split()
15131cb0ef41Sopenharmony_ci    suffix = unquote(suffix).split()
15141cb0ef41Sopenharmony_ci    def ExpandCommand(args):
15151cb0ef41Sopenharmony_ci      return prefix + args + suffix
15161cb0ef41Sopenharmony_ci    return ExpandCommand
15171cb0ef41Sopenharmony_ci
15181cb0ef41Sopenharmony_cidef GetSuites(test_root):
15191cb0ef41Sopenharmony_ci  def IsSuite(path):
15201cb0ef41Sopenharmony_ci    return isdir(path) and exists(join(path, 'testcfg.py'))
15211cb0ef41Sopenharmony_ci  return [ f for f in os.listdir(test_root) if IsSuite(join(test_root, f)) ]
15221cb0ef41Sopenharmony_ci
15231cb0ef41Sopenharmony_ci
15241cb0ef41Sopenharmony_cidef FormatTime(d):
15251cb0ef41Sopenharmony_ci  millis = round(d * 1000) % 1000
15261cb0ef41Sopenharmony_ci  return time.strftime("%M:%S.", time.gmtime(d)) + ("%03i" % millis)
15271cb0ef41Sopenharmony_ci
15281cb0ef41Sopenharmony_ci
15291cb0ef41Sopenharmony_cidef FormatTimedelta(td):
15301cb0ef41Sopenharmony_ci  if hasattr(td, 'total_seconds'):
15311cb0ef41Sopenharmony_ci    d = td.total_seconds()
15321cb0ef41Sopenharmony_ci  else: # python2.6 compat
15331cb0ef41Sopenharmony_ci    d =  td.seconds + (td.microseconds / 10.0**6)
15341cb0ef41Sopenharmony_ci  return FormatTime(d)
15351cb0ef41Sopenharmony_ci
15361cb0ef41Sopenharmony_ci
15371cb0ef41Sopenharmony_cidef PrintCrashed(code):
15381cb0ef41Sopenharmony_ci  if utils.IsWindows():
15391cb0ef41Sopenharmony_ci    return "CRASHED"
15401cb0ef41Sopenharmony_ci  else:
15411cb0ef41Sopenharmony_ci    return "CRASHED (Signal: %d)" % -code
15421cb0ef41Sopenharmony_ci
15431cb0ef41Sopenharmony_ci
15441cb0ef41Sopenharmony_ci# these suites represent special cases that should not be run as part of the
15451cb0ef41Sopenharmony_ci# default JavaScript test-run, e.g., internet/ requires a network connection,
15461cb0ef41Sopenharmony_ci# addons/ requires compilation.
15471cb0ef41Sopenharmony_ciIGNORED_SUITES = [
15481cb0ef41Sopenharmony_ci  'addons',
15491cb0ef41Sopenharmony_ci  'benchmark',
15501cb0ef41Sopenharmony_ci  'doctool',
15511cb0ef41Sopenharmony_ci  'embedding',
15521cb0ef41Sopenharmony_ci  'internet',
15531cb0ef41Sopenharmony_ci  'js-native-api',
15541cb0ef41Sopenharmony_ci  'node-api',
15551cb0ef41Sopenharmony_ci  'pummel',
15561cb0ef41Sopenharmony_ci  'tick-processor',
15571cb0ef41Sopenharmony_ci  'v8-updates'
15581cb0ef41Sopenharmony_ci]
15591cb0ef41Sopenharmony_ci
15601cb0ef41Sopenharmony_ci
15611cb0ef41Sopenharmony_cidef ArgsToTestPaths(test_root, args, suites):
15621cb0ef41Sopenharmony_ci  if len(args) == 0 or 'default' in args:
15631cb0ef41Sopenharmony_ci    def_suites = [s for s in suites if s not in IGNORED_SUITES]
15641cb0ef41Sopenharmony_ci    args = [a for a in args if a != 'default'] + def_suites
15651cb0ef41Sopenharmony_ci  subsystem_regex = re.compile(r'^[a-zA-Z-]*$')
15661cb0ef41Sopenharmony_ci  check = lambda arg: subsystem_regex.match(arg) and (arg not in suites)
15671cb0ef41Sopenharmony_ci  mapped_args = ["*/test*-%s-*" % arg if check(arg) else arg for arg in args]
15681cb0ef41Sopenharmony_ci  paths = [SplitPath(NormalizePath(a)) for a in mapped_args]
15691cb0ef41Sopenharmony_ci  return paths
15701cb0ef41Sopenharmony_ci
15711cb0ef41Sopenharmony_ci
15721cb0ef41Sopenharmony_cidef get_env_type(vm, options_type, context):
15731cb0ef41Sopenharmony_ci  if options_type is not None:
15741cb0ef41Sopenharmony_ci    env_type = options_type
15751cb0ef41Sopenharmony_ci  else:
15761cb0ef41Sopenharmony_ci    # 'simple' is the default value for 'env_type'.
15771cb0ef41Sopenharmony_ci    env_type = 'simple'
15781cb0ef41Sopenharmony_ci    ssl_ver = Execute([vm, '-p', 'process.versions.openssl'], context).stdout
15791cb0ef41Sopenharmony_ci    if 'fips' in ssl_ver:
15801cb0ef41Sopenharmony_ci      env_type = 'fips'
15811cb0ef41Sopenharmony_ci  return env_type
15821cb0ef41Sopenharmony_ci
15831cb0ef41Sopenharmony_ci
15841cb0ef41Sopenharmony_cidef get_asan_state():
15851cb0ef41Sopenharmony_ci  return "on" if os.environ.get('ASAN') is not None else "off"
15861cb0ef41Sopenharmony_ci
15871cb0ef41Sopenharmony_ci
15881cb0ef41Sopenharmony_cidef Main():
15891cb0ef41Sopenharmony_ci  parser = BuildOptions()
15901cb0ef41Sopenharmony_ci  (options, args) = parser.parse_args()
15911cb0ef41Sopenharmony_ci  if not ProcessOptions(options):
15921cb0ef41Sopenharmony_ci    parser.print_help()
15931cb0ef41Sopenharmony_ci    return 1
15941cb0ef41Sopenharmony_ci
15951cb0ef41Sopenharmony_ci  stream = sys.stdout
15961cb0ef41Sopenharmony_ci  try:
15971cb0ef41Sopenharmony_ci    sys.stdout.reconfigure(encoding='utf8')
15981cb0ef41Sopenharmony_ci  except AttributeError:
15991cb0ef41Sopenharmony_ci    # Python < 3.7 does not have reconfigure
16001cb0ef41Sopenharmony_ci    stream = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
16011cb0ef41Sopenharmony_ci  ch = logging.StreamHandler(stream)
16021cb0ef41Sopenharmony_ci  logger.addHandler(ch)
16031cb0ef41Sopenharmony_ci  logger.setLevel(logging.INFO)
16041cb0ef41Sopenharmony_ci  if options.logfile:
16051cb0ef41Sopenharmony_ci    fh = logging.FileHandler(options.logfile, encoding='utf-8', mode='w')
16061cb0ef41Sopenharmony_ci    logger.addHandler(fh)
16071cb0ef41Sopenharmony_ci
16081cb0ef41Sopenharmony_ci  workspace = abspath(join(dirname(sys.argv[0]), '..'))
16091cb0ef41Sopenharmony_ci  test_root = join(workspace, 'test')
16101cb0ef41Sopenharmony_ci  if options.test_root is not None:
16111cb0ef41Sopenharmony_ci    test_root = options.test_root
16121cb0ef41Sopenharmony_ci  suites = GetSuites(test_root)
16131cb0ef41Sopenharmony_ci  repositories = [TestRepository(join(test_root, name)) for name in suites]
16141cb0ef41Sopenharmony_ci  repositories += [TestRepository(a) for a in options.suite]
16151cb0ef41Sopenharmony_ci
16161cb0ef41Sopenharmony_ci  root = LiteralTestSuite(repositories, test_root)
16171cb0ef41Sopenharmony_ci  paths = ArgsToTestPaths(test_root, args, suites)
16181cb0ef41Sopenharmony_ci
16191cb0ef41Sopenharmony_ci  # Check for --valgrind option. If enabled, we overwrite the special
16201cb0ef41Sopenharmony_ci  # command flag with a command that uses the run-valgrind.py script.
16211cb0ef41Sopenharmony_ci  if options.valgrind:
16221cb0ef41Sopenharmony_ci    run_valgrind = join(workspace, "tools", "run-valgrind.py")
16231cb0ef41Sopenharmony_ci    options.special_command = "python -u " + run_valgrind + " @"
16241cb0ef41Sopenharmony_ci
16251cb0ef41Sopenharmony_ci  if options.check_deopts:
16261cb0ef41Sopenharmony_ci    options.node_args.append("--trace-opt")
16271cb0ef41Sopenharmony_ci    options.node_args.append("--trace-file-names")
16281cb0ef41Sopenharmony_ci    # --always-opt is needed because many tests do not run long enough for the
16291cb0ef41Sopenharmony_ci    # optimizer to kick in, so this flag will force it to run.
16301cb0ef41Sopenharmony_ci    options.node_args.append("--always-opt")
16311cb0ef41Sopenharmony_ci    options.progress = "deopts"
16321cb0ef41Sopenharmony_ci
16331cb0ef41Sopenharmony_ci  if options.worker:
16341cb0ef41Sopenharmony_ci    run_worker = join(workspace, "tools", "run-worker.js")
16351cb0ef41Sopenharmony_ci    options.node_args.append(run_worker)
16361cb0ef41Sopenharmony_ci
16371cb0ef41Sopenharmony_ci  processor = GetSpecialCommandProcessor(options.special_command)
16381cb0ef41Sopenharmony_ci
16391cb0ef41Sopenharmony_ci  context = Context(workspace,
16401cb0ef41Sopenharmony_ci                    VERBOSE,
16411cb0ef41Sopenharmony_ci                    options.shell,
16421cb0ef41Sopenharmony_ci                    options.node_args,
16431cb0ef41Sopenharmony_ci                    options.expect_fail,
16441cb0ef41Sopenharmony_ci                    options.timeout,
16451cb0ef41Sopenharmony_ci                    processor,
16461cb0ef41Sopenharmony_ci                    options.suppress_dialogs,
16471cb0ef41Sopenharmony_ci                    options.store_unexpected_output,
16481cb0ef41Sopenharmony_ci                    options.repeat,
16491cb0ef41Sopenharmony_ci                    options.abort_on_timeout)
16501cb0ef41Sopenharmony_ci
16511cb0ef41Sopenharmony_ci  # Get status for tests
16521cb0ef41Sopenharmony_ci  sections = [ ]
16531cb0ef41Sopenharmony_ci  defs = { }
16541cb0ef41Sopenharmony_ci  root.GetTestStatus(context, sections, defs)
16551cb0ef41Sopenharmony_ci  config = Configuration(sections, defs)
16561cb0ef41Sopenharmony_ci
16571cb0ef41Sopenharmony_ci  # List the tests
16581cb0ef41Sopenharmony_ci  all_cases = [ ]
16591cb0ef41Sopenharmony_ci  all_unused = [ ]
16601cb0ef41Sopenharmony_ci  unclassified_tests = [ ]
16611cb0ef41Sopenharmony_ci  globally_unused_rules = None
16621cb0ef41Sopenharmony_ci  for path in paths:
16631cb0ef41Sopenharmony_ci    for arch in options.arch:
16641cb0ef41Sopenharmony_ci      for mode in options.mode:
16651cb0ef41Sopenharmony_ci        vm = context.GetVm(arch, mode)
16661cb0ef41Sopenharmony_ci        if not exists(vm):
16671cb0ef41Sopenharmony_ci          print("Can't find shell executable: '%s'" % vm)
16681cb0ef41Sopenharmony_ci          continue
16691cb0ef41Sopenharmony_ci        archEngineContext = Execute([vm, "-p", "process.arch"], context)
16701cb0ef41Sopenharmony_ci        vmArch = archEngineContext.stdout.rstrip()
16711cb0ef41Sopenharmony_ci        if archEngineContext.exit_code != 0 or vmArch == "undefined":
16721cb0ef41Sopenharmony_ci          print("Can't determine the arch of: '%s'" % vm)
16731cb0ef41Sopenharmony_ci          print(archEngineContext.stderr.rstrip())
16741cb0ef41Sopenharmony_ci          continue
16751cb0ef41Sopenharmony_ci        env = {
16761cb0ef41Sopenharmony_ci          'mode': mode,
16771cb0ef41Sopenharmony_ci          'system': utils.GuessOS(),
16781cb0ef41Sopenharmony_ci          'arch': vmArch,
16791cb0ef41Sopenharmony_ci          'type': get_env_type(vm, options.type, context),
16801cb0ef41Sopenharmony_ci          'asan': get_asan_state(),
16811cb0ef41Sopenharmony_ci        }
16821cb0ef41Sopenharmony_ci        test_list = root.ListTests([], path, context, arch, mode)
16831cb0ef41Sopenharmony_ci        unclassified_tests += test_list
16841cb0ef41Sopenharmony_ci        cases, unused_rules = config.ClassifyTests(test_list, env)
16851cb0ef41Sopenharmony_ci        if globally_unused_rules is None:
16861cb0ef41Sopenharmony_ci          globally_unused_rules = set(unused_rules)
16871cb0ef41Sopenharmony_ci        else:
16881cb0ef41Sopenharmony_ci          globally_unused_rules = (
16891cb0ef41Sopenharmony_ci              globally_unused_rules.intersection(unused_rules))
16901cb0ef41Sopenharmony_ci        all_cases += cases
16911cb0ef41Sopenharmony_ci        all_unused.append(unused_rules)
16921cb0ef41Sopenharmony_ci
16931cb0ef41Sopenharmony_ci  # We want to skip the inspector tests if node was built without the inspector.
16941cb0ef41Sopenharmony_ci  has_inspector = Execute([vm,
16951cb0ef41Sopenharmony_ci      '-p', 'process.features.inspector'], context)
16961cb0ef41Sopenharmony_ci  if has_inspector.stdout.rstrip() == 'false':
16971cb0ef41Sopenharmony_ci    context.v8_enable_inspector = False
16981cb0ef41Sopenharmony_ci
16991cb0ef41Sopenharmony_ci  has_crypto = Execute([vm,
17001cb0ef41Sopenharmony_ci      '-p', 'process.versions.openssl'], context)
17011cb0ef41Sopenharmony_ci  if has_crypto.stdout.rstrip() == 'undefined':
17021cb0ef41Sopenharmony_ci    context.node_has_crypto = False
17031cb0ef41Sopenharmony_ci
17041cb0ef41Sopenharmony_ci  if options.cat:
17051cb0ef41Sopenharmony_ci    visited = set()
17061cb0ef41Sopenharmony_ci    for test in unclassified_tests:
17071cb0ef41Sopenharmony_ci      key = tuple(test.path)
17081cb0ef41Sopenharmony_ci      if key in visited:
17091cb0ef41Sopenharmony_ci        continue
17101cb0ef41Sopenharmony_ci      visited.add(key)
17111cb0ef41Sopenharmony_ci      print("--- begin source: %s ---" % test.GetLabel())
17121cb0ef41Sopenharmony_ci      source = test.GetSource().strip()
17131cb0ef41Sopenharmony_ci      print(source)
17141cb0ef41Sopenharmony_ci      print("--- end source: %s ---" % test.GetLabel())
17151cb0ef41Sopenharmony_ci    return 0
17161cb0ef41Sopenharmony_ci
17171cb0ef41Sopenharmony_ci  if options.warn_unused:
17181cb0ef41Sopenharmony_ci    for rule in globally_unused_rules:
17191cb0ef41Sopenharmony_ci      print("Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path]))
17201cb0ef41Sopenharmony_ci
17211cb0ef41Sopenharmony_ci  tempdir = os.environ.get('NODE_TEST_DIR') or options.temp_dir
17221cb0ef41Sopenharmony_ci  if tempdir:
17231cb0ef41Sopenharmony_ci    os.environ['NODE_TEST_DIR'] = tempdir
17241cb0ef41Sopenharmony_ci    try:
17251cb0ef41Sopenharmony_ci      os.makedirs(tempdir)
17261cb0ef41Sopenharmony_ci    except OSError as exception:
17271cb0ef41Sopenharmony_ci      if exception.errno != errno.EEXIST:
17281cb0ef41Sopenharmony_ci        print("Could not create the temporary directory", options.temp_dir)
17291cb0ef41Sopenharmony_ci        sys.exit(1)
17301cb0ef41Sopenharmony_ci
17311cb0ef41Sopenharmony_ci  def should_keep(case):
17321cb0ef41Sopenharmony_ci    if any((s in case.file) for s in options.skip_tests):
17331cb0ef41Sopenharmony_ci      return False
17341cb0ef41Sopenharmony_ci    elif SKIP in case.outcomes:
17351cb0ef41Sopenharmony_ci      return False
17361cb0ef41Sopenharmony_ci    elif (options.flaky_tests == SKIP) and (set([SLOW, FLAKY]) & case.outcomes):
17371cb0ef41Sopenharmony_ci      return False
17381cb0ef41Sopenharmony_ci    else:
17391cb0ef41Sopenharmony_ci      return True
17401cb0ef41Sopenharmony_ci
17411cb0ef41Sopenharmony_ci  cases_to_run = [
17421cb0ef41Sopenharmony_ci    test_case for test_case in all_cases if should_keep(test_case)
17431cb0ef41Sopenharmony_ci  ]
17441cb0ef41Sopenharmony_ci
17451cb0ef41Sopenharmony_ci  if options.report:
17461cb0ef41Sopenharmony_ci    print(REPORT_TEMPLATE % {
17471cb0ef41Sopenharmony_ci      'total': len(all_cases),
17481cb0ef41Sopenharmony_ci      'skipped': len(all_cases) - len(cases_to_run),
17491cb0ef41Sopenharmony_ci      'pass': len([t for t in cases_to_run if PASS in t.outcomes]),
17501cb0ef41Sopenharmony_ci      'fail_ok': len([t for t in cases_to_run if t.outcomes == set([FAIL, OKAY])]),
17511cb0ef41Sopenharmony_ci      'fail': len([t for t in cases_to_run if t.outcomes == set([FAIL])])
17521cb0ef41Sopenharmony_ci    })
17531cb0ef41Sopenharmony_ci
17541cb0ef41Sopenharmony_ci  if options.run is not None:
17551cb0ef41Sopenharmony_ci    # Must ensure the list of tests is sorted before selecting, to avoid
17561cb0ef41Sopenharmony_ci    # silent errors if this file is changed to list the tests in a way that
17571cb0ef41Sopenharmony_ci    # can be different in different machines
17581cb0ef41Sopenharmony_ci    cases_to_run.sort(key=lambda c: (c.arch, c.mode, c.file))
17591cb0ef41Sopenharmony_ci    cases_to_run = [ cases_to_run[i] for i
17601cb0ef41Sopenharmony_ci                     in range(options.run[0],
17611cb0ef41Sopenharmony_ci                               len(cases_to_run),
17621cb0ef41Sopenharmony_ci                               options.run[1]) ]
17631cb0ef41Sopenharmony_ci  if len(cases_to_run) == 0:
17641cb0ef41Sopenharmony_ci    print("No tests to run.")
17651cb0ef41Sopenharmony_ci    return 1
17661cb0ef41Sopenharmony_ci  else:
17671cb0ef41Sopenharmony_ci    try:
17681cb0ef41Sopenharmony_ci      start = time.time()
17691cb0ef41Sopenharmony_ci      result = RunTestCases(cases_to_run, options.progress, options.j, options.flaky_tests, options.measure_flakiness)
17701cb0ef41Sopenharmony_ci      exitcode = 0 if result['allPassed'] else 1
17711cb0ef41Sopenharmony_ci      duration = time.time() - start
17721cb0ef41Sopenharmony_ci    except KeyboardInterrupt:
17731cb0ef41Sopenharmony_ci      print("Interrupted")
17741cb0ef41Sopenharmony_ci      return 1
17751cb0ef41Sopenharmony_ci
17761cb0ef41Sopenharmony_ci  if options.time:
17771cb0ef41Sopenharmony_ci    # Write the times to stderr to make it easy to separate from the
17781cb0ef41Sopenharmony_ci    # test output.
17791cb0ef41Sopenharmony_ci    print()
17801cb0ef41Sopenharmony_ci    sys.stderr.write("--- Total time: %s ---\n" % FormatTime(duration))
17811cb0ef41Sopenharmony_ci    timed_tests = [ t for t in cases_to_run if not t.duration is None ]
17821cb0ef41Sopenharmony_ci    timed_tests.sort(key=lambda x: x.duration)
17831cb0ef41Sopenharmony_ci    for i, entry in enumerate(timed_tests[:20], start=1):
17841cb0ef41Sopenharmony_ci      t = FormatTimedelta(entry.duration)
17851cb0ef41Sopenharmony_ci      sys.stderr.write("%4i (%s) %s\n" % (i, t, entry.GetLabel()))
17861cb0ef41Sopenharmony_ci
17871cb0ef41Sopenharmony_ci  if result['allPassed']:
17881cb0ef41Sopenharmony_ci    print("\nAll tests passed.")
17891cb0ef41Sopenharmony_ci  else:
17901cb0ef41Sopenharmony_ci    print("\nFailed tests:")
17911cb0ef41Sopenharmony_ci    for failure in result['failed']:
17921cb0ef41Sopenharmony_ci      print(EscapeCommand(failure.command))
17931cb0ef41Sopenharmony_ci
17941cb0ef41Sopenharmony_ci  return exitcode
17951cb0ef41Sopenharmony_ci
17961cb0ef41Sopenharmony_ci
17971cb0ef41Sopenharmony_ciif __name__ == '__main__':
17981cb0ef41Sopenharmony_ci  sys.exit(Main())
1799