3 # Copyright 2009 Google Inc. All Rights Reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 """Verifies that test shuffling works."""
34 import gtest_test_utils
36 # Command to run the googletest-shuffle-test_ program.
37 COMMAND
= gtest_test_utils
.GetTestExecutablePath('googletest-shuffle-test_')
39 # The environment variables for test sharding.
40 TOTAL_SHARDS_ENV_VAR
= 'GTEST_TOTAL_SHARDS'
41 SHARD_INDEX_ENV_VAR
= 'GTEST_SHARD_INDEX'
43 TEST_FILTER
= 'A*.A:A*.B:C*'
50 SHUFFLED_ALL_TESTS
= []
51 SHUFFLED_ACTIVE_TESTS
= []
52 SHUFFLED_FILTERED_TESTS
= []
53 SHUFFLED_SHARDED_TESTS
= []
56 def AlsoRunDisabledTestsFlag():
57 return '--gtest_also_run_disabled_tests'
60 def FilterFlag(test_filter
):
61 return '--gtest_filter=%s' % (test_filter
,)
65 return '--gtest_repeat=%s' % (n
,)
69 return '--gtest_shuffle'
72 def RandomSeedFlag(n
):
73 return '--gtest_random_seed=%s' % (n
,)
76 def RunAndReturnOutput(extra_env
, args
):
77 """Runs the test program and returns its output."""
79 environ_copy
= os
.environ
.copy()
80 environ_copy
.update(extra_env
)
82 return gtest_test_utils
.Subprocess([COMMAND
] + args
, env
=environ_copy
).output
85 def GetTestsForAllIterations(extra_env
, args
):
86 """Runs the test program and returns a list of test lists.
89 extra_env: a map from environment variables to their values
90 args: command line flags to pass to googletest-shuffle-test_
93 A list where the i-th element is the list of tests run in the i-th
98 for line
in RunAndReturnOutput(extra_env
, args
).split('\n'):
99 if line
.startswith('----'):
101 test_iterations
.append(tests
)
103 tests
.append(line
.strip()) # 'TestCaseName.TestName'
105 return test_iterations
108 def GetTestCases(tests
):
109 """Returns a list of test cases in the given full test names.
112 tests: a list of full test names
115 A list of test cases from 'tests', in their original order.
116 Consecutive duplicates are removed.
121 test_case
= test
.split('.')[0]
122 if not test_case
in test_cases
:
123 test_cases
.append(test_case
)
128 def CalculateTestLists():
129 """Calculates the list of tests run under different flags."""
133 GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0])
136 ACTIVE_TESTS
.extend(GetTestsForAllIterations({}, [])[0])
138 if not FILTERED_TESTS
:
139 FILTERED_TESTS
.extend(
140 GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER
)])[0])
142 if not SHARDED_TESTS
:
143 SHARDED_TESTS
.extend(
144 GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR
: '3',
145 SHARD_INDEX_ENV_VAR
: '1'},
148 if not SHUFFLED_ALL_TESTS
:
149 SHUFFLED_ALL_TESTS
.extend(GetTestsForAllIterations(
150 {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0])
152 if not SHUFFLED_ACTIVE_TESTS
:
153 SHUFFLED_ACTIVE_TESTS
.extend(GetTestsForAllIterations(
154 {}, [ShuffleFlag(), RandomSeedFlag(1)])[0])
156 if not SHUFFLED_FILTERED_TESTS
:
157 SHUFFLED_FILTERED_TESTS
.extend(GetTestsForAllIterations(
158 {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER
)])[0])
160 if not SHUFFLED_SHARDED_TESTS
:
161 SHUFFLED_SHARDED_TESTS
.extend(
162 GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR
: '3',
163 SHARD_INDEX_ENV_VAR
: '1'},
164 [ShuffleFlag(), RandomSeedFlag(1)])[0])
167 class GTestShuffleUnitTest(gtest_test_utils
.TestCase
):
168 """Tests test shuffling."""
173 def testShufflePreservesNumberOfTests(self
):
174 self
.assertEqual(len(ALL_TESTS
), len(SHUFFLED_ALL_TESTS
))
175 self
.assertEqual(len(ACTIVE_TESTS
), len(SHUFFLED_ACTIVE_TESTS
))
176 self
.assertEqual(len(FILTERED_TESTS
), len(SHUFFLED_FILTERED_TESTS
))
177 self
.assertEqual(len(SHARDED_TESTS
), len(SHUFFLED_SHARDED_TESTS
))
179 def testShuffleChangesTestOrder(self
):
180 self
.assert_(SHUFFLED_ALL_TESTS
!= ALL_TESTS
, SHUFFLED_ALL_TESTS
)
181 self
.assert_(SHUFFLED_ACTIVE_TESTS
!= ACTIVE_TESTS
, SHUFFLED_ACTIVE_TESTS
)
182 self
.assert_(SHUFFLED_FILTERED_TESTS
!= FILTERED_TESTS
,
183 SHUFFLED_FILTERED_TESTS
)
184 self
.assert_(SHUFFLED_SHARDED_TESTS
!= SHARDED_TESTS
,
185 SHUFFLED_SHARDED_TESTS
)
187 def testShuffleChangesTestCaseOrder(self
):
188 self
.assert_(GetTestCases(SHUFFLED_ALL_TESTS
) != GetTestCases(ALL_TESTS
),
189 GetTestCases(SHUFFLED_ALL_TESTS
))
191 GetTestCases(SHUFFLED_ACTIVE_TESTS
) != GetTestCases(ACTIVE_TESTS
),
192 GetTestCases(SHUFFLED_ACTIVE_TESTS
))
194 GetTestCases(SHUFFLED_FILTERED_TESTS
) != GetTestCases(FILTERED_TESTS
),
195 GetTestCases(SHUFFLED_FILTERED_TESTS
))
197 GetTestCases(SHUFFLED_SHARDED_TESTS
) != GetTestCases(SHARDED_TESTS
),
198 GetTestCases(SHUFFLED_SHARDED_TESTS
))
200 def testShuffleDoesNotRepeatTest(self
):
201 for test
in SHUFFLED_ALL_TESTS
:
202 self
.assertEqual(1, SHUFFLED_ALL_TESTS
.count(test
),
203 '%s appears more than once' % (test
,))
204 for test
in SHUFFLED_ACTIVE_TESTS
:
205 self
.assertEqual(1, SHUFFLED_ACTIVE_TESTS
.count(test
),
206 '%s appears more than once' % (test
,))
207 for test
in SHUFFLED_FILTERED_TESTS
:
208 self
.assertEqual(1, SHUFFLED_FILTERED_TESTS
.count(test
),
209 '%s appears more than once' % (test
,))
210 for test
in SHUFFLED_SHARDED_TESTS
:
211 self
.assertEqual(1, SHUFFLED_SHARDED_TESTS
.count(test
),
212 '%s appears more than once' % (test
,))
214 def testShuffleDoesNotCreateNewTest(self
):
215 for test
in SHUFFLED_ALL_TESTS
:
216 self
.assert_(test
in ALL_TESTS
, '%s is an invalid test' % (test
,))
217 for test
in SHUFFLED_ACTIVE_TESTS
:
218 self
.assert_(test
in ACTIVE_TESTS
, '%s is an invalid test' % (test
,))
219 for test
in SHUFFLED_FILTERED_TESTS
:
220 self
.assert_(test
in FILTERED_TESTS
, '%s is an invalid test' % (test
,))
221 for test
in SHUFFLED_SHARDED_TESTS
:
222 self
.assert_(test
in SHARDED_TESTS
, '%s is an invalid test' % (test
,))
224 def testShuffleIncludesAllTests(self
):
225 for test
in ALL_TESTS
:
226 self
.assert_(test
in SHUFFLED_ALL_TESTS
, '%s is missing' % (test
,))
227 for test
in ACTIVE_TESTS
:
228 self
.assert_(test
in SHUFFLED_ACTIVE_TESTS
, '%s is missing' % (test
,))
229 for test
in FILTERED_TESTS
:
230 self
.assert_(test
in SHUFFLED_FILTERED_TESTS
, '%s is missing' % (test
,))
231 for test
in SHARDED_TESTS
:
232 self
.assert_(test
in SHUFFLED_SHARDED_TESTS
, '%s is missing' % (test
,))
234 def testShuffleLeavesDeathTestsAtFront(self
):
235 non_death_test_found
= False
236 for test
in SHUFFLED_ACTIVE_TESTS
:
237 if 'DeathTest.' in test
:
238 self
.assert_(not non_death_test_found
,
239 '%s appears after a non-death test' % (test
,))
241 non_death_test_found
= True
243 def _VerifyTestCasesDoNotInterleave(self
, tests
):
246 [test_case
, _
] = test
.split('.')
247 if test_cases
and test_cases
[-1] != test_case
:
248 test_cases
.append(test_case
)
249 self
.assertEqual(1, test_cases
.count(test_case
),
250 'Test case %s is not grouped together in %s' %
253 def testShuffleDoesNotInterleaveTestCases(self
):
254 self
._VerifyTestCasesDoNotInterleave
(SHUFFLED_ALL_TESTS
)
255 self
._VerifyTestCasesDoNotInterleave
(SHUFFLED_ACTIVE_TESTS
)
256 self
._VerifyTestCasesDoNotInterleave
(SHUFFLED_FILTERED_TESTS
)
257 self
._VerifyTestCasesDoNotInterleave
(SHUFFLED_SHARDED_TESTS
)
259 def testShuffleRestoresOrderAfterEachIteration(self
):
260 # Get the test lists in all 3 iterations, using random seed 1, 2,
261 # and 3 respectively. Google Test picks a different seed in each
262 # iteration, and this test depends on the current implementation
263 # picking successive numbers. This dependency is not ideal, but
264 # makes the test much easier to write.
265 [tests_in_iteration1
, tests_in_iteration2
, tests_in_iteration3
] = (
266 GetTestsForAllIterations(
267 {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
269 # Make sure running the tests with random seed 1 gets the same
270 # order as in iteration 1 above.
271 [tests_with_seed1
] = GetTestsForAllIterations(
272 {}, [ShuffleFlag(), RandomSeedFlag(1)])
273 self
.assertEqual(tests_in_iteration1
, tests_with_seed1
)
275 # Make sure running the tests with random seed 2 gets the same
276 # order as in iteration 2 above. Success means that Google Test
277 # correctly restores the test order before re-shuffling at the
278 # beginning of iteration 2.
279 [tests_with_seed2
] = GetTestsForAllIterations(
280 {}, [ShuffleFlag(), RandomSeedFlag(2)])
281 self
.assertEqual(tests_in_iteration2
, tests_with_seed2
)
283 # Make sure running the tests with random seed 3 gets the same
284 # order as in iteration 3 above. Success means that Google Test
285 # correctly restores the test order before re-shuffling at the
286 # beginning of iteration 3.
287 [tests_with_seed3
] = GetTestsForAllIterations(
288 {}, [ShuffleFlag(), RandomSeedFlag(3)])
289 self
.assertEqual(tests_in_iteration3
, tests_with_seed3
)
291 def testShuffleGeneratesNewOrderInEachIteration(self
):
292 [tests_in_iteration1
, tests_in_iteration2
, tests_in_iteration3
] = (
293 GetTestsForAllIterations(
294 {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
296 self
.assert_(tests_in_iteration1
!= tests_in_iteration2
,
298 self
.assert_(tests_in_iteration1
!= tests_in_iteration3
,
300 self
.assert_(tests_in_iteration2
!= tests_in_iteration3
,
303 def testShuffleShardedTestsPreservesPartition(self
):
304 # If we run M tests on N shards, the same M tests should be run in
305 # total, regardless of the random seeds used by the shards.
306 [tests1
] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR
: '3',
307 SHARD_INDEX_ENV_VAR
: '0'},
308 [ShuffleFlag(), RandomSeedFlag(1)])
309 [tests2
] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR
: '3',
310 SHARD_INDEX_ENV_VAR
: '1'},
311 [ShuffleFlag(), RandomSeedFlag(20)])
312 [tests3
] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR
: '3',
313 SHARD_INDEX_ENV_VAR
: '2'},
314 [ShuffleFlag(), RandomSeedFlag(25)])
315 sorted_sharded_tests
= tests1
+ tests2
+ tests3
316 sorted_sharded_tests
.sort()
317 sorted_active_tests
= []
318 sorted_active_tests
.extend(ACTIVE_TESTS
)
319 sorted_active_tests
.sort()
320 self
.assertEqual(sorted_active_tests
, sorted_sharded_tests
)
322 if __name__
== '__main__':
323 gtest_test_utils
.Main()