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

  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2009 Google Inc. All Rights Reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are
  7. # met:
  8. #
  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
  14. # distribution.
  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.
  18. #
  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.
  30. """Verifies that test shuffling works."""
  31. __author__ = 'wan@google.com (Zhanyong Wan)'
  32. import os
  33. import gtest_test_utils
  34. # Command to run the gtest_shuffle_test_ program.
  35. COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_')
  36. # The environment variables for test sharding.
  37. TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
  38. SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
  39. TEST_FILTER = 'A*.A:A*.B:C*'
  40. ALL_TESTS = []
  41. ACTIVE_TESTS = []
  42. FILTERED_TESTS = []
  43. SHARDED_TESTS = []
  44. SHUFFLED_ALL_TESTS = []
  45. SHUFFLED_ACTIVE_TESTS = []
  46. SHUFFLED_FILTERED_TESTS = []
  47. SHUFFLED_SHARDED_TESTS = []
  48. def AlsoRunDisabledTestsFlag():
  49. return '--gtest_also_run_disabled_tests'
  50. def FilterFlag(test_filter):
  51. return '--gtest_filter=%s' % (test_filter,)
  52. def RepeatFlag(n):
  53. return '--gtest_repeat=%s' % (n,)
  54. def ShuffleFlag():
  55. return '--gtest_shuffle'
  56. def RandomSeedFlag(n):
  57. return '--gtest_random_seed=%s' % (n,)
  58. def RunAndReturnOutput(extra_env, args):
  59. """Runs the test program and returns its output."""
  60. environ_copy = os.environ.copy()
  61. environ_copy.update(extra_env)
  62. return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output
  63. def GetTestsForAllIterations(extra_env, args):
  64. """Runs the test program and returns a list of test lists.
  65. Args:
  66. extra_env: a map from environment variables to their values
  67. args: command line flags to pass to gtest_shuffle_test_
  68. Returns:
  69. A list where the i-th element is the list of tests run in the i-th
  70. test iteration.
  71. """
  72. test_iterations = []
  73. for line in RunAndReturnOutput(extra_env, args).split('\n'):
  74. if line.startswith('----'):
  75. tests = []
  76. test_iterations.append(tests)
  77. elif line.strip():
  78. tests.append(line.strip()) # 'TestCaseName.TestName'
  79. return test_iterations
  80. def GetTestCases(tests):
  81. """Returns a list of test cases in the given full test names.
  82. Args:
  83. tests: a list of full test names
  84. Returns:
  85. A list of test cases from 'tests', in their original order.
  86. Consecutive duplicates are removed.
  87. """
  88. test_cases = []
  89. for test in tests:
  90. test_case = test.split('.')[0]
  91. if not test_case in test_cases:
  92. test_cases.append(test_case)
  93. return test_cases
  94. def CalculateTestLists():
  95. """Calculates the list of tests run under different flags."""
  96. if not ALL_TESTS:
  97. ALL_TESTS.extend(
  98. GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0])
  99. if not ACTIVE_TESTS:
  100. ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0])
  101. if not FILTERED_TESTS:
  102. FILTERED_TESTS.extend(
  103. GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0])
  104. if not SHARDED_TESTS:
  105. SHARDED_TESTS.extend(
  106. GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
  107. SHARD_INDEX_ENV_VAR: '1'},
  108. [])[0])
  109. if not SHUFFLED_ALL_TESTS:
  110. SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations(
  111. {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0])
  112. if not SHUFFLED_ACTIVE_TESTS:
  113. SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations(
  114. {}, [ShuffleFlag(), RandomSeedFlag(1)])[0])
  115. if not SHUFFLED_FILTERED_TESTS:
  116. SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations(
  117. {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0])
  118. if not SHUFFLED_SHARDED_TESTS:
  119. SHUFFLED_SHARDED_TESTS.extend(
  120. GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
  121. SHARD_INDEX_ENV_VAR: '1'},
  122. [ShuffleFlag(), RandomSeedFlag(1)])[0])
  123. class GTestShuffleUnitTest(gtest_test_utils.TestCase):
  124. """Tests test shuffling."""
  125. def setUp(self):
  126. CalculateTestLists()
  127. def testShufflePreservesNumberOfTests(self):
  128. self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS))
  129. self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS))
  130. self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS))
  131. self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS))
  132. def testShuffleChangesTestOrder(self):
  133. self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
  134. self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
  135. self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
  136. SHUFFLED_FILTERED_TESTS)
  137. self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
  138. SHUFFLED_SHARDED_TESTS)
  139. def testShuffleChangesTestCaseOrder(self):
  140. self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
  141. GetTestCases(SHUFFLED_ALL_TESTS))
  142. self.assert_(
  143. GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS),
  144. GetTestCases(SHUFFLED_ACTIVE_TESTS))
  145. self.assert_(
  146. GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS),
  147. GetTestCases(SHUFFLED_FILTERED_TESTS))
  148. self.assert_(
  149. GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS),
  150. GetTestCases(SHUFFLED_SHARDED_TESTS))
  151. def testShuffleDoesNotRepeatTest(self):
  152. for test in SHUFFLED_ALL_TESTS:
  153. self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test),
  154. '%s appears more than once' % (test,))
  155. for test in SHUFFLED_ACTIVE_TESTS:
  156. self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test),
  157. '%s appears more than once' % (test,))
  158. for test in SHUFFLED_FILTERED_TESTS:
  159. self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test),
  160. '%s appears more than once' % (test,))
  161. for test in SHUFFLED_SHARDED_TESTS:
  162. self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test),
  163. '%s appears more than once' % (test,))
  164. def testShuffleDoesNotCreateNewTest(self):
  165. for test in SHUFFLED_ALL_TESTS:
  166. self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,))
  167. for test in SHUFFLED_ACTIVE_TESTS:
  168. self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,))
  169. for test in SHUFFLED_FILTERED_TESTS:
  170. self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,))
  171. for test in SHUFFLED_SHARDED_TESTS:
  172. self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,))
  173. def testShuffleIncludesAllTests(self):
  174. for test in ALL_TESTS:
  175. self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,))
  176. for test in ACTIVE_TESTS:
  177. self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,))
  178. for test in FILTERED_TESTS:
  179. self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,))
  180. for test in SHARDED_TESTS:
  181. self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,))
  182. def testShuffleLeavesDeathTestsAtFront(self):
  183. non_death_test_found = False
  184. for test in SHUFFLED_ACTIVE_TESTS:
  185. if 'DeathTest.' in test:
  186. self.assert_(not non_death_test_found,
  187. '%s appears after a non-death test' % (test,))
  188. else:
  189. non_death_test_found = True
  190. def _VerifyTestCasesDoNotInterleave(self, tests):
  191. test_cases = []
  192. for test in tests:
  193. [test_case, _] = test.split('.')
  194. if test_cases and test_cases[-1] != test_case:
  195. test_cases.append(test_case)
  196. self.assertEqual(1, test_cases.count(test_case),
  197. 'Test case %s is not grouped together in %s' %
  198. (test_case, tests))
  199. def testShuffleDoesNotInterleaveTestCases(self):
  200. self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS)
  201. self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS)
  202. self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS)
  203. self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS)
  204. def testShuffleRestoresOrderAfterEachIteration(self):
  205. # Get the test lists in all 3 iterations, using random seed 1, 2,
  206. # and 3 respectively. Google Test picks a different seed in each
  207. # iteration, and this test depends on the current implementation
  208. # picking successive numbers. This dependency is not ideal, but
  209. # makes the test much easier to write.
  210. [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
  211. GetTestsForAllIterations(
  212. {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
  213. # Make sure running the tests with random seed 1 gets the same
  214. # order as in iteration 1 above.
  215. [tests_with_seed1] = GetTestsForAllIterations(
  216. {}, [ShuffleFlag(), RandomSeedFlag(1)])
  217. self.assertEqual(tests_in_iteration1, tests_with_seed1)
  218. # Make sure running the tests with random seed 2 gets the same
  219. # order as in iteration 2 above. Success means that Google Test
  220. # correctly restores the test order before re-shuffling at the
  221. # beginning of iteration 2.
  222. [tests_with_seed2] = GetTestsForAllIterations(
  223. {}, [ShuffleFlag(), RandomSeedFlag(2)])
  224. self.assertEqual(tests_in_iteration2, tests_with_seed2)
  225. # Make sure running the tests with random seed 3 gets the same
  226. # order as in iteration 3 above. Success means that Google Test
  227. # correctly restores the test order before re-shuffling at the
  228. # beginning of iteration 3.
  229. [tests_with_seed3] = GetTestsForAllIterations(
  230. {}, [ShuffleFlag(), RandomSeedFlag(3)])
  231. self.assertEqual(tests_in_iteration3, tests_with_seed3)
  232. def testShuffleGeneratesNewOrderInEachIteration(self):
  233. [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
  234. GetTestsForAllIterations(
  235. {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
  236. self.assert_(tests_in_iteration1 != tests_in_iteration2,
  237. tests_in_iteration1)
  238. self.assert_(tests_in_iteration1 != tests_in_iteration3,
  239. tests_in_iteration1)
  240. self.assert_(tests_in_iteration2 != tests_in_iteration3,
  241. tests_in_iteration2)
  242. def testShuffleShardedTestsPreservesPartition(self):
  243. # If we run M tests on N shards, the same M tests should be run in
  244. # total, regardless of the random seeds used by the shards.
  245. [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
  246. SHARD_INDEX_ENV_VAR: '0'},
  247. [ShuffleFlag(), RandomSeedFlag(1)])
  248. [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
  249. SHARD_INDEX_ENV_VAR: '1'},
  250. [ShuffleFlag(), RandomSeedFlag(20)])
  251. [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
  252. SHARD_INDEX_ENV_VAR: '2'},
  253. [ShuffleFlag(), RandomSeedFlag(25)])
  254. sorted_sharded_tests = tests1 + tests2 + tests3
  255. sorted_sharded_tests.sort()
  256. sorted_active_tests = []
  257. sorted_active_tests.extend(ACTIVE_TESTS)
  258. sorted_active_tests.sort()
  259. self.assertEqual(sorted_active_tests, sorted_sharded_tests)
  260. if __name__ == '__main__':
  261. gtest_test_utils.Main()