PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/tools/auto_bisect/bisect_results_test.py

https://gitlab.com/jonnialva90/iridium-browser
Python | 283 lines | 203 code | 53 blank | 27 comment | 3 complexity | b17b34fcdc1f2eff60b27c5e1ab99ca6 MD5 | raw file
  1. # Copyright 2014 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. import os
  5. import unittest
  6. from bisect_results import BisectResults
  7. import source_control
  8. class MockDepotRegistry(object):
  9. def ChangeToDepotDir(self, depot):
  10. pass
  11. class MockRevisionState(object):
  12. def __init__(self, revision, index, depot='chromium', value=None,
  13. perf_time=0, build_time=0, passed='?', external=None):
  14. self.depot = depot
  15. self.revision = revision
  16. self.index = index
  17. self.value = value
  18. self.perf_time = perf_time
  19. self.build_time = build_time
  20. self.passed = passed
  21. self.external = external
  22. class MockBisectState(object):
  23. def __init__(self):
  24. self.mock_revision_states = []
  25. mock_bad_val = {'values': [100, 105, 95]}
  26. for i, rev in enumerate(['a', 'b']):
  27. mock_rev_state = MockRevisionState(rev, i, value=mock_bad_val, passed=0)
  28. self.mock_revision_states.append(mock_rev_state)
  29. mock_good_val = {'values': [1, 2, 3]}
  30. for i, rev in enumerate(['c', 'd', 'e'], start=2):
  31. mock_rev_state = MockRevisionState(rev, i, value=mock_good_val, passed=1)
  32. self.mock_revision_states.append(mock_rev_state)
  33. def GetRevisionStates(self):
  34. return self.mock_revision_states
  35. class MockBisectOptions(object):
  36. def __init__(self):
  37. self.repeat_test_count = 3
  38. class BisectResultsTest(unittest.TestCase):
  39. def setUp(self):
  40. self.mock_bisect_state = MockBisectState()
  41. self.mock_depot_registry = MockDepotRegistry()
  42. self.mock_opts = MockBisectOptions()
  43. self.mock_warnings = []
  44. self.original_getcwd = os.getcwd
  45. self.original_chdir = os.chdir
  46. self.original_query_revision_info = source_control.QueryRevisionInfo
  47. os.getcwd = lambda: '/path'
  48. os.chdir = lambda _: None
  49. revision_infos = {'b': {'test': 'b'}, 'c': {'test': 'c'}}
  50. source_control.QueryRevisionInfo = lambda rev: revision_infos[rev]
  51. def tearDown(self):
  52. os.getcwd = self.original_getcwd
  53. os.chdir = self.original_chdir
  54. source_control.QueryRevisionInfo = self.original_query_revision_info
  55. def _AssertConfidence(self, score, bad_values, good_values):
  56. """Checks whether the given sets of values have a given confidence score.
  57. The score represents our confidence that the two sets of values wouldn't
  58. be as different as they are just by chance; that is, that some real change
  59. occurred between the two sets of values.
  60. Args:
  61. score: Expected confidence score.
  62. bad_values: First list of numbers.
  63. good_values: Second list of numbers.
  64. """
  65. confidence = BisectResults.ConfidenceScore(bad_values, good_values)
  66. self.assertEqual(score, confidence)
  67. def testConfidenceScoreIsZeroOnTooFewLists(self):
  68. self._AssertConfidence(0.0, [], [1, 2])
  69. self._AssertConfidence(0.0, [1, 2], [])
  70. self._AssertConfidence(0.0, [1], [1, 2])
  71. self._AssertConfidence(0.0, [1, 2], [1])
  72. def testConfidenceScore_ZeroConfidence(self):
  73. # The good and bad sets contain the same values, so the confidence that
  74. # they're different should be zero.
  75. self._AssertConfidence(0.0, [4, 5, 7, 6, 8, 7], [8, 7, 6, 7, 5, 4])
  76. def testConfidenceScore_MediumConfidence(self):
  77. self._AssertConfidence(80.0, [0, 1, 1, 1, 2, 2], [1, 1, 1, 3, 3, 4])
  78. def testConfidenceScore_HighConfidence(self):
  79. self._AssertConfidence(95.0, [0, 1, 1, 1, 2, 2], [1, 2, 2, 3, 3, 4])
  80. def testConfidenceScore_VeryHighConfidence(self):
  81. # Confidence is high if the two sets of values have no internal variance.
  82. self._AssertConfidence(99.9, [1, 1, 1, 1], [1.2, 1.2, 1.2, 1.2])
  83. self._AssertConfidence(99.9, [1, 1, 1, 1], [1.01, 1.01, 1.01, 1.01])
  84. def testConfidenceScore_UnbalancedSampleSize(self):
  85. # The second set of numbers only contains one number, so confidence is 0.
  86. self._AssertConfidence(0.0, [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2], [1.4])
  87. def testConfidenceScore_EmptySample(self):
  88. # Confidence is zero if either or both samples are empty.
  89. self._AssertConfidence(0.0, [], [])
  90. self._AssertConfidence(0.0, [], [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2, 1.3])
  91. self._AssertConfidence(0.0, [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2, 1.3], [])
  92. def testConfidenceScore_FunctionalTestResults(self):
  93. self._AssertConfidence(80.0, [1, 1, 0, 1, 1, 1, 0, 1], [0, 0, 1, 0, 1, 0])
  94. self._AssertConfidence(99.9, [1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0])
  95. def testConfidenceScore_RealWorldCases(self):
  96. """This method contains a set of data from actual bisect results.
  97. The confidence scores asserted below were all copied from the actual
  98. results, so the purpose of this test method is mainly to show what the
  99. results for real cases are, and compare when we change the confidence
  100. score function in the future.
  101. """
  102. self._AssertConfidence(80, [133, 130, 132, 132, 130, 129], [129, 129, 125])
  103. self._AssertConfidence(99.5, [668, 667], [498, 498, 499])
  104. self._AssertConfidence(80, [67, 68], [65, 65, 67])
  105. self._AssertConfidence(0, [514], [514])
  106. self._AssertConfidence(90, [616, 613, 607, 615], [617, 619, 619, 617])
  107. self._AssertConfidence(0, [3.5, 5.8, 4.7, 3.5, 3.6], [2.8])
  108. self._AssertConfidence(90, [3, 3, 3], [2, 2, 2, 3])
  109. self._AssertConfidence(0, [1999004, 1999627], [223355])
  110. self._AssertConfidence(90, [1040, 934, 961], [876, 875, 789])
  111. self._AssertConfidence(90, [309, 305, 304], [302, 302, 299, 303, 298])
  112. def testCorrectlyFindsBreakingRange(self):
  113. revision_states = self.mock_bisect_state.mock_revision_states
  114. revision_states[0].passed = 0
  115. revision_states[1].passed = 0
  116. revision_states[2].passed = 1
  117. revision_states[3].passed = 1
  118. revision_states[4].passed = 1
  119. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  120. self.mock_opts, self.mock_warnings)
  121. self.assertEqual(revision_states[2], results.first_working_revision)
  122. self.assertEqual(revision_states[1], results.last_broken_revision)
  123. def testCorrectlyFindsBreakingRangeNotInOrder(self):
  124. revision_states = self.mock_bisect_state.mock_revision_states
  125. revision_states[0].passed = 0
  126. revision_states[1].passed = 1
  127. revision_states[2].passed = 0
  128. revision_states[3].passed = 1
  129. revision_states[4].passed = 1
  130. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  131. self.mock_opts, self.mock_warnings)
  132. self.assertEqual(revision_states[1], results.first_working_revision)
  133. self.assertEqual(revision_states[2], results.last_broken_revision)
  134. def testCorrectlyFindsBreakingRangeIncompleteBisect(self):
  135. revision_states = self.mock_bisect_state.mock_revision_states
  136. revision_states[0].passed = 0
  137. revision_states[1].passed = 0
  138. revision_states[2].passed = '?'
  139. revision_states[3].passed = 1
  140. revision_states[4].passed = 1
  141. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  142. self.mock_opts, self.mock_warnings)
  143. self.assertEqual(revision_states[3], results.first_working_revision)
  144. self.assertEqual(revision_states[1], results.last_broken_revision)
  145. def testFindBreakingRangeAllPassed(self):
  146. revision_states = self.mock_bisect_state.mock_revision_states
  147. revision_states[0].passed = 1
  148. revision_states[1].passed = 1
  149. revision_states[2].passed = 1
  150. revision_states[3].passed = 1
  151. revision_states[4].passed = 1
  152. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  153. self.mock_opts, self.mock_warnings)
  154. self.assertEqual(revision_states[0], results.first_working_revision)
  155. self.assertIsNone(results.last_broken_revision)
  156. def testFindBreakingRangeNonePassed(self):
  157. revision_states = self.mock_bisect_state.mock_revision_states
  158. revision_states[0].passed = 0
  159. revision_states[1].passed = 0
  160. revision_states[2].passed = 0
  161. revision_states[3].passed = 0
  162. revision_states[4].passed = 0
  163. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  164. self.mock_opts, self.mock_warnings)
  165. self.assertIsNone(results.first_working_revision)
  166. self.assertEqual(revision_states[4], results.last_broken_revision)
  167. def testCorrectlyComputesRegressionStatistics(self):
  168. revision_states = self.mock_bisect_state.mock_revision_states
  169. revision_states[0].passed = 0
  170. revision_states[0].value = {'values': [1000, 999, 998]}
  171. revision_states[1].passed = 0
  172. revision_states[1].value = {'values': [980, 1000, 999]}
  173. revision_states[2].passed = 1
  174. revision_states[2].value = {'values': [50, 45, 55]}
  175. revision_states[3].passed = 1
  176. revision_states[3].value = {'values': [45, 56, 45]}
  177. revision_states[4].passed = 1
  178. revision_states[4].value = {'values': [51, 41, 58]}
  179. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  180. self.mock_opts, self.mock_warnings)
  181. self.assertAlmostEqual(99.9, results.confidence)
  182. self.assertAlmostEqual(1909.86547085, results.regression_size)
  183. self.assertAlmostEqual(7.16625904, results.regression_std_err)
  184. def testFindsCulpritRevisions(self):
  185. revision_states = self.mock_bisect_state.mock_revision_states
  186. revision_states[1].depot = 'chromium'
  187. revision_states[2].depot = 'webkit'
  188. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  189. self.mock_opts, self.mock_warnings)
  190. self.assertEqual(1, len(results.culprit_revisions))
  191. self.assertEqual(('b', {'test': 'b'}, 'chromium'),
  192. results.culprit_revisions[0])
  193. def testNoResultBasedWarningsForNormalState(self):
  194. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  195. self.mock_opts, self.mock_warnings)
  196. self.assertEqual(0, len(results.warnings))
  197. def testWarningForMultipleCulpritRevisions(self):
  198. self.mock_bisect_state.mock_revision_states[2].passed = 'Skipped'
  199. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  200. self.mock_opts, self.mock_warnings)
  201. self.assertEqual(1, len(results.warnings))
  202. def testWarningForTooLowRetryLimit(self):
  203. self.mock_opts.repeat_test_count = 1
  204. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  205. self.mock_opts, self.mock_warnings)
  206. self.assertEqual(1, len(results.warnings))
  207. def testWarningForTooLowConfidence(self):
  208. revision_states = self.mock_bisect_state.mock_revision_states
  209. revision_states[2].value = {'values': [95, 90, 90]}
  210. revision_states[3].value = {'values': [95, 90, 90]}
  211. revision_states[4].value = {'values': [95, 90, 90]}
  212. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  213. self.mock_opts, self.mock_warnings)
  214. self.assertGreater(results.confidence, 0)
  215. self.assertEqual(1, len(results.warnings))
  216. def testWarningForZeroConfidence(self):
  217. revision_states = self.mock_bisect_state.mock_revision_states
  218. revision_states[2].value = {'values': [100, 105, 95]}
  219. revision_states[3].value = {'values': [100, 105, 95]}
  220. revision_states[4].value = {'values': [100, 105, 95]}
  221. results = BisectResults(self.mock_bisect_state, self.mock_depot_registry,
  222. self.mock_opts, self.mock_warnings)
  223. self.assertEqual(0, results.confidence)
  224. self.assertEqual(1, len(results.warnings))
  225. if __name__ == '__main__':
  226. unittest.main()