You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							325 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							325 lines
						
					
					
						
							12 KiB
						
					
					
				
								#!/usr/bin/env python
							 | 
						|
								#
							 | 
						|
								# Copyright 2009 Google Inc. All Rights Reserved.
							 | 
						|
								#
							 | 
						|
								# Redistribution and use in source and binary forms, with or without
							 | 
						|
								# modification, are permitted provided that the following conditions are
							 | 
						|
								# met:
							 | 
						|
								#
							 | 
						|
								#     * Redistributions of source code must retain the above copyright
							 | 
						|
								# notice, this list of conditions and the following disclaimer.
							 | 
						|
								#     * Redistributions in binary form must reproduce the above
							 | 
						|
								# copyright notice, this list of conditions and the following disclaimer
							 | 
						|
								# in the documentation and/or other materials provided with the
							 | 
						|
								# distribution.
							 | 
						|
								#     * Neither the name of Google Inc. nor the names of its
							 | 
						|
								# contributors may be used to endorse or promote products derived from
							 | 
						|
								# this software without specific prior written permission.
							 | 
						|
								#
							 | 
						|
								# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
							 | 
						|
								# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
							 | 
						|
								# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
							 | 
						|
								# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
							 | 
						|
								# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
							 | 
						|
								# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
							 | 
						|
								# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
							 | 
						|
								# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
							 | 
						|
								# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
							 | 
						|
								# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
							 | 
						|
								# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
							 | 
						|
								
							 | 
						|
								"""Verifies that test shuffling works."""
							 | 
						|
								
							 | 
						|
								__author__ = 'wan@google.com (Zhanyong Wan)'
							 | 
						|
								
							 | 
						|
								import os
							 | 
						|
								import gtest_test_utils
							 | 
						|
								
							 | 
						|
								# Command to run the gtest_shuffle_test_ program.
							 | 
						|
								COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_')
							 | 
						|
								
							 | 
						|
								# The environment variables for test sharding.
							 | 
						|
								TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
							 | 
						|
								SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
							 | 
						|
								
							 | 
						|
								TEST_FILTER = 'A*.A:A*.B:C*'
							 | 
						|
								
							 | 
						|
								ALL_TESTS = []
							 | 
						|
								ACTIVE_TESTS = []
							 | 
						|
								FILTERED_TESTS = []
							 | 
						|
								SHARDED_TESTS = []
							 | 
						|
								
							 | 
						|
								SHUFFLED_ALL_TESTS = []
							 | 
						|
								SHUFFLED_ACTIVE_TESTS = []
							 | 
						|
								SHUFFLED_FILTERED_TESTS = []
							 | 
						|
								SHUFFLED_SHARDED_TESTS = []
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def AlsoRunDisabledTestsFlag():
							 | 
						|
								  return '--gtest_also_run_disabled_tests'
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def FilterFlag(test_filter):
							 | 
						|
								  return '--gtest_filter=%s' % (test_filter,)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def RepeatFlag(n):
							 | 
						|
								  return '--gtest_repeat=%s' % (n,)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def ShuffleFlag():
							 | 
						|
								  return '--gtest_shuffle'
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def RandomSeedFlag(n):
							 | 
						|
								  return '--gtest_random_seed=%s' % (n,)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def RunAndReturnOutput(extra_env, args):
							 | 
						|
								  """Runs the test program and returns its output."""
							 | 
						|
								
							 | 
						|
								  environ_copy = os.environ.copy()
							 | 
						|
								  environ_copy.update(extra_env)
							 | 
						|
								
							 | 
						|
								  return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def GetTestsForAllIterations(extra_env, args):
							 | 
						|
								  """Runs the test program and returns a list of test lists.
							 | 
						|
								
							 | 
						|
								  Args:
							 | 
						|
								    extra_env: a map from environment variables to their values
							 | 
						|
								    args: command line flags to pass to gtest_shuffle_test_
							 | 
						|
								
							 | 
						|
								  Returns:
							 | 
						|
								    A list where the i-th element is the list of tests run in the i-th
							 | 
						|
								    test iteration.
							 | 
						|
								  """
							 | 
						|
								
							 | 
						|
								  test_iterations = []
							 | 
						|
								  for line in RunAndReturnOutput(extra_env, args).split('\n'):
							 | 
						|
								    if line.startswith('----'):
							 | 
						|
								      tests = []
							 | 
						|
								      test_iterations.append(tests)
							 | 
						|
								    elif line.strip():
							 | 
						|
								      tests.append(line.strip())  # 'TestCaseName.TestName'
							 | 
						|
								
							 | 
						|
								  return test_iterations
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def GetTestCases(tests):
							 | 
						|
								  """Returns a list of test cases in the given full test names.
							 | 
						|
								
							 | 
						|
								  Args:
							 | 
						|
								    tests: a list of full test names
							 | 
						|
								
							 | 
						|
								  Returns:
							 | 
						|
								    A list of test cases from 'tests', in their original order.
							 | 
						|
								    Consecutive duplicates are removed.
							 | 
						|
								  """
							 | 
						|
								
							 | 
						|
								  test_cases = []
							 | 
						|
								  for test in tests:
							 | 
						|
								    test_case = test.split('.')[0]
							 | 
						|
								    if not test_case in test_cases:
							 | 
						|
								      test_cases.append(test_case)
							 | 
						|
								
							 | 
						|
								  return test_cases
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								def CalculateTestLists():
							 | 
						|
								  """Calculates the list of tests run under different flags."""
							 | 
						|
								
							 | 
						|
								  if not ALL_TESTS:
							 | 
						|
								    ALL_TESTS.extend(
							 | 
						|
								        GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0])
							 | 
						|
								
							 | 
						|
								  if not ACTIVE_TESTS:
							 | 
						|
								    ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0])
							 | 
						|
								
							 | 
						|
								  if not FILTERED_TESTS:
							 | 
						|
								    FILTERED_TESTS.extend(
							 | 
						|
								        GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0])
							 | 
						|
								
							 | 
						|
								  if not SHARDED_TESTS:
							 | 
						|
								    SHARDED_TESTS.extend(
							 | 
						|
								        GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
							 | 
						|
								                                  SHARD_INDEX_ENV_VAR: '1'},
							 | 
						|
								                                 [])[0])
							 | 
						|
								
							 | 
						|
								  if not SHUFFLED_ALL_TESTS:
							 | 
						|
								    SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations(
							 | 
						|
								        {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0])
							 | 
						|
								
							 | 
						|
								  if not SHUFFLED_ACTIVE_TESTS:
							 | 
						|
								    SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations(
							 | 
						|
								        {}, [ShuffleFlag(), RandomSeedFlag(1)])[0])
							 | 
						|
								
							 | 
						|
								  if not SHUFFLED_FILTERED_TESTS:
							 | 
						|
								    SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations(
							 | 
						|
								        {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0])
							 | 
						|
								
							 | 
						|
								  if not SHUFFLED_SHARDED_TESTS:
							 | 
						|
								    SHUFFLED_SHARDED_TESTS.extend(
							 | 
						|
								        GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
							 | 
						|
								                                  SHARD_INDEX_ENV_VAR: '1'},
							 | 
						|
								                                 [ShuffleFlag(), RandomSeedFlag(1)])[0])
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class GTestShuffleUnitTest(gtest_test_utils.TestCase):
							 | 
						|
								  """Tests test shuffling."""
							 | 
						|
								
							 | 
						|
								  def setUp(self):
							 | 
						|
								    CalculateTestLists()
							 | 
						|
								
							 | 
						|
								  def testShufflePreservesNumberOfTests(self):
							 | 
						|
								    self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS))
							 | 
						|
								    self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS))
							 | 
						|
								    self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS))
							 | 
						|
								    self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS))
							 | 
						|
								
							 | 
						|
								  def testShuffleChangesTestOrder(self):
							 | 
						|
								    self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
							 | 
						|
								    self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
							 | 
						|
								    self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
							 | 
						|
								                 SHUFFLED_FILTERED_TESTS)
							 | 
						|
								    self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
							 | 
						|
								                 SHUFFLED_SHARDED_TESTS)
							 | 
						|
								
							 | 
						|
								  def testShuffleChangesTestCaseOrder(self):
							 | 
						|
								    self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
							 | 
						|
								                 GetTestCases(SHUFFLED_ALL_TESTS))
							 | 
						|
								    self.assert_(
							 | 
						|
								        GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS),
							 | 
						|
								        GetTestCases(SHUFFLED_ACTIVE_TESTS))
							 | 
						|
								    self.assert_(
							 | 
						|
								        GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS),
							 | 
						|
								        GetTestCases(SHUFFLED_FILTERED_TESTS))
							 | 
						|
								    self.assert_(
							 | 
						|
								        GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS),
							 | 
						|
								        GetTestCases(SHUFFLED_SHARDED_TESTS))
							 | 
						|
								
							 | 
						|
								  def testShuffleDoesNotRepeatTest(self):
							 | 
						|
								    for test in SHUFFLED_ALL_TESTS:
							 | 
						|
								      self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test),
							 | 
						|
								                       '%s appears more than once' % (test,))
							 | 
						|
								    for test in SHUFFLED_ACTIVE_TESTS:
							 | 
						|
								      self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test),
							 | 
						|
								                       '%s appears more than once' % (test,))
							 | 
						|
								    for test in SHUFFLED_FILTERED_TESTS:
							 | 
						|
								      self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test),
							 | 
						|
								                       '%s appears more than once' % (test,))
							 | 
						|
								    for test in SHUFFLED_SHARDED_TESTS:
							 | 
						|
								      self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test),
							 | 
						|
								                       '%s appears more than once' % (test,))
							 | 
						|
								
							 | 
						|
								  def testShuffleDoesNotCreateNewTest(self):
							 | 
						|
								    for test in SHUFFLED_ALL_TESTS:
							 | 
						|
								      self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,))
							 | 
						|
								    for test in SHUFFLED_ACTIVE_TESTS:
							 | 
						|
								      self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,))
							 | 
						|
								    for test in SHUFFLED_FILTERED_TESTS:
							 | 
						|
								      self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,))
							 | 
						|
								    for test in SHUFFLED_SHARDED_TESTS:
							 | 
						|
								      self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,))
							 | 
						|
								
							 | 
						|
								  def testShuffleIncludesAllTests(self):
							 | 
						|
								    for test in ALL_TESTS:
							 | 
						|
								      self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,))
							 | 
						|
								    for test in ACTIVE_TESTS:
							 | 
						|
								      self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,))
							 | 
						|
								    for test in FILTERED_TESTS:
							 | 
						|
								      self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,))
							 | 
						|
								    for test in SHARDED_TESTS:
							 | 
						|
								      self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,))
							 | 
						|
								
							 | 
						|
								  def testShuffleLeavesDeathTestsAtFront(self):
							 | 
						|
								    non_death_test_found = False
							 | 
						|
								    for test in SHUFFLED_ACTIVE_TESTS:
							 | 
						|
								      if 'DeathTest.' in test:
							 | 
						|
								        self.assert_(not non_death_test_found,
							 | 
						|
								                     '%s appears after a non-death test' % (test,))
							 | 
						|
								      else:
							 | 
						|
								        non_death_test_found = True
							 | 
						|
								
							 | 
						|
								  def _VerifyTestCasesDoNotInterleave(self, tests):
							 | 
						|
								    test_cases = []
							 | 
						|
								    for test in tests:
							 | 
						|
								      [test_case, _] = test.split('.')
							 | 
						|
								      if test_cases and test_cases[-1] != test_case:
							 | 
						|
								        test_cases.append(test_case)
							 | 
						|
								        self.assertEqual(1, test_cases.count(test_case),
							 | 
						|
								                         'Test case %s is not grouped together in %s' %
							 | 
						|
								                         (test_case, tests))
							 | 
						|
								
							 | 
						|
								  def testShuffleDoesNotInterleaveTestCases(self):
							 | 
						|
								    self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS)
							 | 
						|
								    self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS)
							 | 
						|
								    self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS)
							 | 
						|
								    self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS)
							 | 
						|
								
							 | 
						|
								  def testShuffleRestoresOrderAfterEachIteration(self):
							 | 
						|
								    # Get the test lists in all 3 iterations, using random seed 1, 2,
							 | 
						|
								    # and 3 respectively.  Google Test picks a different seed in each
							 | 
						|
								    # iteration, and this test depends on the current implementation
							 | 
						|
								    # picking successive numbers.  This dependency is not ideal, but
							 | 
						|
								    # makes the test much easier to write.
							 | 
						|
								    [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
							 | 
						|
								        GetTestsForAllIterations(
							 | 
						|
								            {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
							 | 
						|
								
							 | 
						|
								    # Make sure running the tests with random seed 1 gets the same
							 | 
						|
								    # order as in iteration 1 above.
							 | 
						|
								    [tests_with_seed1] = GetTestsForAllIterations(
							 | 
						|
								        {}, [ShuffleFlag(), RandomSeedFlag(1)])
							 | 
						|
								    self.assertEqual(tests_in_iteration1, tests_with_seed1)
							 | 
						|
								
							 | 
						|
								    # Make sure running the tests with random seed 2 gets the same
							 | 
						|
								    # order as in iteration 2 above.  Success means that Google Test
							 | 
						|
								    # correctly restores the test order before re-shuffling at the
							 | 
						|
								    # beginning of iteration 2.
							 | 
						|
								    [tests_with_seed2] = GetTestsForAllIterations(
							 | 
						|
								        {}, [ShuffleFlag(), RandomSeedFlag(2)])
							 | 
						|
								    self.assertEqual(tests_in_iteration2, tests_with_seed2)
							 | 
						|
								
							 | 
						|
								    # Make sure running the tests with random seed 3 gets the same
							 | 
						|
								    # order as in iteration 3 above.  Success means that Google Test
							 | 
						|
								    # correctly restores the test order before re-shuffling at the
							 | 
						|
								    # beginning of iteration 3.
							 | 
						|
								    [tests_with_seed3] = GetTestsForAllIterations(
							 | 
						|
								        {}, [ShuffleFlag(), RandomSeedFlag(3)])
							 | 
						|
								    self.assertEqual(tests_in_iteration3, tests_with_seed3)
							 | 
						|
								
							 | 
						|
								  def testShuffleGeneratesNewOrderInEachIteration(self):
							 | 
						|
								    [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
							 | 
						|
								        GetTestsForAllIterations(
							 | 
						|
								            {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
							 | 
						|
								
							 | 
						|
								    self.assert_(tests_in_iteration1 != tests_in_iteration2,
							 | 
						|
								                 tests_in_iteration1)
							 | 
						|
								    self.assert_(tests_in_iteration1 != tests_in_iteration3,
							 | 
						|
								                 tests_in_iteration1)
							 | 
						|
								    self.assert_(tests_in_iteration2 != tests_in_iteration3,
							 | 
						|
								                 tests_in_iteration2)
							 | 
						|
								
							 | 
						|
								  def testShuffleShardedTestsPreservesPartition(self):
							 | 
						|
								    # If we run M tests on N shards, the same M tests should be run in
							 | 
						|
								    # total, regardless of the random seeds used by the shards.
							 | 
						|
								    [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
							 | 
						|
								                                         SHARD_INDEX_ENV_VAR: '0'},
							 | 
						|
								                                        [ShuffleFlag(), RandomSeedFlag(1)])
							 | 
						|
								    [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
							 | 
						|
								                                         SHARD_INDEX_ENV_VAR: '1'},
							 | 
						|
								                                        [ShuffleFlag(), RandomSeedFlag(20)])
							 | 
						|
								    [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
							 | 
						|
								                                         SHARD_INDEX_ENV_VAR: '2'},
							 | 
						|
								                                        [ShuffleFlag(), RandomSeedFlag(25)])
							 | 
						|
								    sorted_sharded_tests = tests1 + tests2 + tests3
							 | 
						|
								    sorted_sharded_tests.sort()
							 | 
						|
								    sorted_active_tests = []
							 | 
						|
								    sorted_active_tests.extend(ACTIVE_TESTS)
							 | 
						|
								    sorted_active_tests.sort()
							 | 
						|
								    self.assertEqual(sorted_active_tests, sorted_sharded_tests)
							 | 
						|
								
							 | 
						|
								if __name__ == '__main__':
							 | 
						|
								  gtest_test_utils.Main()
							 |