googletest-failfast-unittest.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2020 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. """Unit test for Google Test fail_fast.
  31. A user can specify if a Google Test program should continue test execution
  32. after a test failure via the GTEST_FAIL_FAST environment variable or the
  33. --gtest_fail_fast flag. The default value of the flag can also be changed
  34. by Bazel fail fast environment variable TESTBRIDGE_TEST_RUNNER_FAIL_FAST.
  35. This script tests such functionality by invoking googletest-failfast-unittest_
  36. (a program written with Google Test) with different environments and command
  37. line flags.
  38. """
  39. import os
  40. from googletest.test import gtest_test_utils
  41. # Constants.
  42. # Bazel testbridge environment variable for fail fast
  43. BAZEL_FAIL_FAST_ENV_VAR = 'TESTBRIDGE_TEST_RUNNER_FAIL_FAST'
  44. # The environment variable for specifying fail fast.
  45. FAIL_FAST_ENV_VAR = 'GTEST_FAIL_FAST'
  46. # The command line flag for specifying fail fast.
  47. FAIL_FAST_FLAG = 'gtest_fail_fast'
  48. # The command line flag to run disabled tests.
  49. RUN_DISABLED_FLAG = 'gtest_also_run_disabled_tests'
  50. # The command line flag for specifying a filter.
  51. FILTER_FLAG = 'gtest_filter'
  52. # Command to run the googletest-failfast-unittest_ program.
  53. COMMAND = gtest_test_utils.GetTestExecutablePath(
  54. 'googletest-failfast-unittest_'
  55. )
  56. # The command line flag to tell Google Test to output the list of tests it
  57. # will run.
  58. LIST_TESTS_FLAG = '--gtest_list_tests'
  59. # Indicates whether Google Test supports death tests.
  60. SUPPORTS_DEATH_TESTS = (
  61. 'HasDeathTest'
  62. in gtest_test_utils.Subprocess([COMMAND, LIST_TESTS_FLAG]).output
  63. )
  64. # Utilities.
  65. environ = os.environ.copy()
  66. def SetEnvVar(env_var, value):
  67. """Sets the env variable to 'value'; unsets it when 'value' is None."""
  68. if value is not None:
  69. environ[env_var] = value
  70. elif env_var in environ:
  71. del environ[env_var]
  72. def RunAndReturnOutput(test_suite=None, fail_fast=None, run_disabled=False):
  73. """Runs the test program and returns its output."""
  74. args = []
  75. xml_path = os.path.join(
  76. gtest_test_utils.GetTempDir(), '.GTestFailFastUnitTest.xml'
  77. )
  78. args += ['--gtest_output=xml:' + xml_path]
  79. if fail_fast is not None:
  80. if isinstance(fail_fast, str):
  81. args += ['--%s=%s' % (FAIL_FAST_FLAG, fail_fast)]
  82. elif fail_fast:
  83. args += ['--%s' % FAIL_FAST_FLAG]
  84. else:
  85. args += ['--no%s' % FAIL_FAST_FLAG]
  86. if test_suite:
  87. args += ['--%s=%s.*' % (FILTER_FLAG, test_suite)]
  88. if run_disabled:
  89. args += ['--%s' % RUN_DISABLED_FLAG]
  90. txt_out = gtest_test_utils.Subprocess([COMMAND] + args, env=environ).output
  91. with open(xml_path) as xml_file:
  92. return txt_out, xml_file.read()
  93. # The unit test.
  94. class GTestFailFastUnitTest(gtest_test_utils.TestCase):
  95. """Tests the env variable or the command line flag for fail_fast."""
  96. def testDefaultBehavior(self):
  97. """Tests the behavior of not specifying the fail_fast."""
  98. txt, _ = RunAndReturnOutput()
  99. self.assertIn('22 FAILED TEST', txt)
  100. def testGoogletestFlag(self):
  101. txt, _ = RunAndReturnOutput(test_suite='HasSimpleTest', fail_fast=True)
  102. self.assertIn('1 FAILED TEST', txt)
  103. self.assertIn('[ SKIPPED ] 3 tests', txt)
  104. txt, _ = RunAndReturnOutput(test_suite='HasSimpleTest', fail_fast=False)
  105. self.assertIn('4 FAILED TEST', txt)
  106. self.assertNotIn('[ SKIPPED ]', txt)
  107. def testGoogletestEnvVar(self):
  108. """Tests the behavior of specifying fail_fast via Googletest env var."""
  109. try:
  110. SetEnvVar(FAIL_FAST_ENV_VAR, '1')
  111. txt, _ = RunAndReturnOutput('HasSimpleTest')
  112. self.assertIn('1 FAILED TEST', txt)
  113. self.assertIn('[ SKIPPED ] 3 tests', txt)
  114. SetEnvVar(FAIL_FAST_ENV_VAR, '0')
  115. txt, _ = RunAndReturnOutput('HasSimpleTest')
  116. self.assertIn('4 FAILED TEST', txt)
  117. self.assertNotIn('[ SKIPPED ]', txt)
  118. finally:
  119. SetEnvVar(FAIL_FAST_ENV_VAR, None)
  120. def testBazelEnvVar(self):
  121. """Tests the behavior of specifying fail_fast via Bazel testbridge."""
  122. try:
  123. SetEnvVar(BAZEL_FAIL_FAST_ENV_VAR, '1')
  124. txt, _ = RunAndReturnOutput('HasSimpleTest')
  125. self.assertIn('1 FAILED TEST', txt)
  126. self.assertIn('[ SKIPPED ] 3 tests', txt)
  127. SetEnvVar(BAZEL_FAIL_FAST_ENV_VAR, '0')
  128. txt, _ = RunAndReturnOutput('HasSimpleTest')
  129. self.assertIn('4 FAILED TEST', txt)
  130. self.assertNotIn('[ SKIPPED ]', txt)
  131. finally:
  132. SetEnvVar(BAZEL_FAIL_FAST_ENV_VAR, None)
  133. def testFlagOverridesEnvVar(self):
  134. """Tests precedence of flag over env var."""
  135. try:
  136. SetEnvVar(FAIL_FAST_ENV_VAR, '0')
  137. txt, _ = RunAndReturnOutput('HasSimpleTest', True)
  138. self.assertIn('1 FAILED TEST', txt)
  139. self.assertIn('[ SKIPPED ] 3 tests', txt)
  140. finally:
  141. SetEnvVar(FAIL_FAST_ENV_VAR, None)
  142. def testGoogletestEnvVarOverridesBazelEnvVar(self):
  143. """Tests that the Googletest native env var over Bazel testbridge."""
  144. try:
  145. SetEnvVar(BAZEL_FAIL_FAST_ENV_VAR, '0')
  146. SetEnvVar(FAIL_FAST_ENV_VAR, '1')
  147. txt, _ = RunAndReturnOutput('HasSimpleTest')
  148. self.assertIn('1 FAILED TEST', txt)
  149. self.assertIn('[ SKIPPED ] 3 tests', txt)
  150. finally:
  151. SetEnvVar(FAIL_FAST_ENV_VAR, None)
  152. SetEnvVar(BAZEL_FAIL_FAST_ENV_VAR, None)
  153. def testEventListener(self):
  154. txt, _ = RunAndReturnOutput(test_suite='HasSkipTest', fail_fast=True)
  155. self.assertIn('1 FAILED TEST', txt)
  156. self.assertIn('[ SKIPPED ] 3 tests', txt)
  157. for expected_count, callback in [
  158. (1, 'OnTestSuiteStart'),
  159. (5, 'OnTestStart'),
  160. (5, 'OnTestEnd'),
  161. (5, 'OnTestPartResult'),
  162. (1, 'OnTestSuiteEnd'),
  163. ]:
  164. self.assertEqual(
  165. expected_count,
  166. txt.count(callback),
  167. 'Expected %d calls to callback %s match count on output: %s '
  168. % (expected_count, callback, txt),
  169. )
  170. txt, _ = RunAndReturnOutput(test_suite='HasSkipTest', fail_fast=False)
  171. self.assertIn('3 FAILED TEST', txt)
  172. self.assertIn('[ SKIPPED ] 1 test', txt)
  173. for expected_count, callback in [
  174. (1, 'OnTestSuiteStart'),
  175. (5, 'OnTestStart'),
  176. (5, 'OnTestEnd'),
  177. (5, 'OnTestPartResult'),
  178. (1, 'OnTestSuiteEnd'),
  179. ]:
  180. self.assertEqual(
  181. expected_count,
  182. txt.count(callback),
  183. 'Expected %d calls to callback %s match count on output: %s '
  184. % (expected_count, callback, txt),
  185. )
  186. def assertXmlResultCount(self, result, count, xml):
  187. self.assertEqual(
  188. count,
  189. xml.count('result="%s"' % result),
  190. 'Expected \'result="%s"\' match count of %s: %s '
  191. % (result, count, xml),
  192. )
  193. def assertXmlStatusCount(self, status, count, xml):
  194. self.assertEqual(
  195. count,
  196. xml.count('status="%s"' % status),
  197. 'Expected \'status="%s"\' match count of %s: %s '
  198. % (status, count, xml),
  199. )
  200. def assertFailFastXmlAndTxtOutput(
  201. self,
  202. fail_fast,
  203. test_suite,
  204. passed_count,
  205. failure_count,
  206. skipped_count,
  207. suppressed_count,
  208. run_disabled=False,
  209. ):
  210. """Assert XML and text output of a test execution."""
  211. txt, xml = RunAndReturnOutput(test_suite, fail_fast, run_disabled)
  212. if failure_count > 0:
  213. self.assertIn('%s FAILED TEST' % failure_count, txt)
  214. if suppressed_count > 0:
  215. self.assertIn('%s DISABLED TEST' % suppressed_count, txt)
  216. if skipped_count > 0:
  217. self.assertIn('[ SKIPPED ] %s tests' % skipped_count, txt)
  218. self.assertXmlStatusCount(
  219. 'run', passed_count + failure_count + skipped_count, xml
  220. )
  221. self.assertXmlStatusCount('notrun', suppressed_count, xml)
  222. self.assertXmlResultCount('completed', passed_count + failure_count, xml)
  223. self.assertXmlResultCount('skipped', skipped_count, xml)
  224. self.assertXmlResultCount('suppressed', suppressed_count, xml)
  225. def assertFailFastBehavior(
  226. self,
  227. test_suite,
  228. passed_count,
  229. failure_count,
  230. skipped_count,
  231. suppressed_count,
  232. run_disabled=False,
  233. ):
  234. """Assert --fail_fast via flag."""
  235. for fail_fast in ('true', '1', 't', True):
  236. self.assertFailFastXmlAndTxtOutput(
  237. fail_fast,
  238. test_suite,
  239. passed_count,
  240. failure_count,
  241. skipped_count,
  242. suppressed_count,
  243. run_disabled,
  244. )
  245. def assertNotFailFastBehavior(
  246. self,
  247. test_suite,
  248. passed_count,
  249. failure_count,
  250. skipped_count,
  251. suppressed_count,
  252. run_disabled=False,
  253. ):
  254. """Assert --nofail_fast via flag."""
  255. for fail_fast in ('false', '0', 'f', False):
  256. self.assertFailFastXmlAndTxtOutput(
  257. fail_fast,
  258. test_suite,
  259. passed_count,
  260. failure_count,
  261. skipped_count,
  262. suppressed_count,
  263. run_disabled,
  264. )
  265. def testFlag_HasFixtureTest(self):
  266. """Tests the behavior of fail_fast and TEST_F."""
  267. self.assertFailFastBehavior(
  268. test_suite='HasFixtureTest',
  269. passed_count=1,
  270. failure_count=1,
  271. skipped_count=3,
  272. suppressed_count=0,
  273. )
  274. self.assertNotFailFastBehavior(
  275. test_suite='HasFixtureTest',
  276. passed_count=1,
  277. failure_count=4,
  278. skipped_count=0,
  279. suppressed_count=0,
  280. )
  281. def testFlag_HasSimpleTest(self):
  282. """Tests the behavior of fail_fast and TEST."""
  283. self.assertFailFastBehavior(
  284. test_suite='HasSimpleTest',
  285. passed_count=1,
  286. failure_count=1,
  287. skipped_count=3,
  288. suppressed_count=0,
  289. )
  290. self.assertNotFailFastBehavior(
  291. test_suite='HasSimpleTest',
  292. passed_count=1,
  293. failure_count=4,
  294. skipped_count=0,
  295. suppressed_count=0,
  296. )
  297. def testFlag_HasParametersTest(self):
  298. """Tests the behavior of fail_fast and TEST_P."""
  299. self.assertFailFastBehavior(
  300. test_suite='HasParametersSuite/HasParametersTest',
  301. passed_count=0,
  302. failure_count=1,
  303. skipped_count=3,
  304. suppressed_count=0,
  305. )
  306. self.assertNotFailFastBehavior(
  307. test_suite='HasParametersSuite/HasParametersTest',
  308. passed_count=0,
  309. failure_count=4,
  310. skipped_count=0,
  311. suppressed_count=0,
  312. )
  313. def testFlag_HasDisabledTest(self):
  314. """Tests the behavior of fail_fast and Disabled test cases."""
  315. self.assertFailFastBehavior(
  316. test_suite='HasDisabledTest',
  317. passed_count=1,
  318. failure_count=1,
  319. skipped_count=2,
  320. suppressed_count=1,
  321. run_disabled=False,
  322. )
  323. self.assertNotFailFastBehavior(
  324. test_suite='HasDisabledTest',
  325. passed_count=1,
  326. failure_count=3,
  327. skipped_count=0,
  328. suppressed_count=1,
  329. run_disabled=False,
  330. )
  331. def testFlag_HasDisabledRunDisabledTest(self):
  332. """Tests the behavior of fail_fast and Disabled test cases enabled."""
  333. self.assertFailFastBehavior(
  334. test_suite='HasDisabledTest',
  335. passed_count=1,
  336. failure_count=1,
  337. skipped_count=3,
  338. suppressed_count=0,
  339. run_disabled=True,
  340. )
  341. self.assertNotFailFastBehavior(
  342. test_suite='HasDisabledTest',
  343. passed_count=1,
  344. failure_count=4,
  345. skipped_count=0,
  346. suppressed_count=0,
  347. run_disabled=True,
  348. )
  349. def testFlag_HasDisabledSuiteTest(self):
  350. """Tests the behavior of fail_fast and Disabled test suites."""
  351. self.assertFailFastBehavior(
  352. test_suite='DISABLED_HasDisabledSuite',
  353. passed_count=0,
  354. failure_count=0,
  355. skipped_count=0,
  356. suppressed_count=5,
  357. run_disabled=False,
  358. )
  359. self.assertNotFailFastBehavior(
  360. test_suite='DISABLED_HasDisabledSuite',
  361. passed_count=0,
  362. failure_count=0,
  363. skipped_count=0,
  364. suppressed_count=5,
  365. run_disabled=False,
  366. )
  367. def testFlag_HasDisabledSuiteRunDisabledTest(self):
  368. """Tests the behavior of fail_fast and Disabled test suites enabled."""
  369. self.assertFailFastBehavior(
  370. test_suite='DISABLED_HasDisabledSuite',
  371. passed_count=1,
  372. failure_count=1,
  373. skipped_count=3,
  374. suppressed_count=0,
  375. run_disabled=True,
  376. )
  377. self.assertNotFailFastBehavior(
  378. test_suite='DISABLED_HasDisabledSuite',
  379. passed_count=1,
  380. failure_count=4,
  381. skipped_count=0,
  382. suppressed_count=0,
  383. run_disabled=True,
  384. )
  385. if SUPPORTS_DEATH_TESTS:
  386. def testFlag_HasDeathTest(self):
  387. """Tests the behavior of fail_fast and death tests."""
  388. self.assertFailFastBehavior(
  389. test_suite='HasDeathTest',
  390. passed_count=1,
  391. failure_count=1,
  392. skipped_count=3,
  393. suppressed_count=0,
  394. )
  395. self.assertNotFailFastBehavior(
  396. test_suite='HasDeathTest',
  397. passed_count=1,
  398. failure_count=4,
  399. skipped_count=0,
  400. suppressed_count=0,
  401. )
  402. if __name__ == '__main__':
  403. gtest_test_utils.Main()