11cb0ef41Sopenharmony_ci# Copyright 2018 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci# found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_cifrom collections import defaultdict
61cb0ef41Sopenharmony_ciimport time
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_cifrom . import base
91cb0ef41Sopenharmony_cifrom ..objects import testcase
101cb0ef41Sopenharmony_cifrom ..outproc import base as outproc
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciclass CombinerProc(base.TestProc):
131cb0ef41Sopenharmony_ci  def __init__(self, rng, min_group_size, max_group_size, count):
141cb0ef41Sopenharmony_ci    """
151cb0ef41Sopenharmony_ci    Args:
161cb0ef41Sopenharmony_ci      rng: random number generator
171cb0ef41Sopenharmony_ci      min_group_size: minimum number of tests to combine
181cb0ef41Sopenharmony_ci      max_group_size: maximum number of tests to combine
191cb0ef41Sopenharmony_ci      count: how many tests to generate. 0 means infinite running
201cb0ef41Sopenharmony_ci    """
211cb0ef41Sopenharmony_ci    super(CombinerProc, self).__init__()
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci    self._rng = rng
241cb0ef41Sopenharmony_ci    self._min_size = min_group_size
251cb0ef41Sopenharmony_ci    self._max_size = max_group_size
261cb0ef41Sopenharmony_ci    self._count = count
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci    # Index of the last generated test
291cb0ef41Sopenharmony_ci    self._current_num = 0
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    # {suite name: instance of TestGroups}
321cb0ef41Sopenharmony_ci    self._groups = defaultdict(TestGroups)
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    # {suite name: instance of TestCombiner}
351cb0ef41Sopenharmony_ci    self._combiners = {}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  def setup(self, requirement=base.DROP_RESULT):
381cb0ef41Sopenharmony_ci    # Combiner is not able to pass results (even as None) to the previous
391cb0ef41Sopenharmony_ci    # processor.
401cb0ef41Sopenharmony_ci    assert requirement == base.DROP_RESULT
411cb0ef41Sopenharmony_ci    self._next_proc.setup(base.DROP_RESULT)
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  def next_test(self, test):
441cb0ef41Sopenharmony_ci    group_key = self._get_group_key(test)
451cb0ef41Sopenharmony_ci    if not group_key:
461cb0ef41Sopenharmony_ci      # Test not suitable for combining
471cb0ef41Sopenharmony_ci      return False
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci    self._groups[test.suite.name].add_test(group_key, test)
501cb0ef41Sopenharmony_ci    return True
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  def _get_group_key(self, test):
531cb0ef41Sopenharmony_ci    combiner =  self._get_combiner(test.suite)
541cb0ef41Sopenharmony_ci    if not combiner:
551cb0ef41Sopenharmony_ci      print ('>>> Warning: There is no combiner for %s testsuite' %
561cb0ef41Sopenharmony_ci             test.suite.name)
571cb0ef41Sopenharmony_ci      return None
581cb0ef41Sopenharmony_ci    return combiner.get_group_key(test)
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  def result_for(self, test, result):
611cb0ef41Sopenharmony_ci    self._send_next_test()
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  def generate_initial_tests(self, num=1):
641cb0ef41Sopenharmony_ci    for _ in range(0, num):
651cb0ef41Sopenharmony_ci      self._send_next_test()
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  def _send_next_test(self):
681cb0ef41Sopenharmony_ci    if self.is_stopped:
691cb0ef41Sopenharmony_ci      return False
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    if self._count and self._current_num >= self._count:
721cb0ef41Sopenharmony_ci      return False
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    combined_test = self._create_new_test()
751cb0ef41Sopenharmony_ci    if not combined_test:
761cb0ef41Sopenharmony_ci      # Not enough tests
771cb0ef41Sopenharmony_ci      return False
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    return self._send_test(combined_test)
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  def _create_new_test(self):
821cb0ef41Sopenharmony_ci    suite, combiner = self._select_suite()
831cb0ef41Sopenharmony_ci    groups = self._groups[suite]
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    max_size = self._rng.randint(self._min_size, self._max_size)
861cb0ef41Sopenharmony_ci    sample = groups.sample(self._rng, max_size)
871cb0ef41Sopenharmony_ci    if not sample:
881cb0ef41Sopenharmony_ci      return None
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    self._current_num += 1
911cb0ef41Sopenharmony_ci    return combiner.combine('%s-%d' % (suite, self._current_num), sample)
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  def _select_suite(self):
941cb0ef41Sopenharmony_ci    """Returns pair (suite name, combiner)."""
951cb0ef41Sopenharmony_ci    selected = self._rng.randint(0, len(self._groups) - 1)
961cb0ef41Sopenharmony_ci    for n, suite in enumerate(self._groups):
971cb0ef41Sopenharmony_ci      if n == selected:
981cb0ef41Sopenharmony_ci        return suite, self._combiners[suite]
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  def _get_combiner(self, suite):
1011cb0ef41Sopenharmony_ci    combiner = self._combiners.get(suite.name)
1021cb0ef41Sopenharmony_ci    if not combiner:
1031cb0ef41Sopenharmony_ci      combiner = suite.get_test_combiner()
1041cb0ef41Sopenharmony_ci      self._combiners[suite.name] = combiner
1051cb0ef41Sopenharmony_ci    return combiner
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciclass TestGroups(object):
1091cb0ef41Sopenharmony_ci  def __init__(self):
1101cb0ef41Sopenharmony_ci    self._groups = defaultdict(list)
1111cb0ef41Sopenharmony_ci    self._keys = []
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  def add_test(self, key, test):
1141cb0ef41Sopenharmony_ci    self._groups[key].append(test)
1151cb0ef41Sopenharmony_ci    self._keys.append(key)
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  def sample(self, rng, max_size):
1181cb0ef41Sopenharmony_ci    # Not enough tests
1191cb0ef41Sopenharmony_ci    if not self._groups:
1201cb0ef41Sopenharmony_ci      return None
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci    group_key = rng.choice(self._keys)
1231cb0ef41Sopenharmony_ci    tests = self._groups[group_key]
1241cb0ef41Sopenharmony_ci    return [rng.choice(tests) for _ in range(0, max_size)]
125