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.
7 from auto_bisect
import source_control
as source_control_module
9 # Special import necessary because filename contains dash characters.
10 bisect_perf_module
= __import__('bisect-perf-regression')
13 class BisectPerfRegressionTest(unittest
.TestCase
):
14 """Test case for other functions and classes in bisect-perf-regression.py."""
16 def _AssertConfidence(self
, score
, bad_values
, good_values
):
17 """Checks whether the given sets of values have a given confidence score.
19 The score represents our confidence that the two sets of values wouldn't
20 be as different as they are just by chance; that is, that some real change
21 occurred between the two sets of values.
24 score: Expected confidence score.
25 bad_values: First list of numbers.
26 good_values: Second list of numbers.
28 # ConfidenceScore takes a list of lists but these lists are flattened
29 # inside the function.
30 confidence
= bisect_perf_module
.ConfidenceScore(
31 [[v
] for v
in bad_values
],
32 [[v
] for v
in good_values
])
33 self
.assertEqual(score
, confidence
)
35 def testConfidenceScore_ZeroConfidence(self
):
36 # The good and bad sets contain the same values, so the confidence that
37 # they're different should be zero.
38 self
._AssertConfidence
(0.0, [4, 5, 7, 6, 8, 7], [8, 7, 6, 7, 5, 4])
40 def testConfidenceScore_MediumConfidence(self
):
41 self
._AssertConfidence
(80.0, [0, 1, 1, 1, 2, 2], [1, 1, 1, 3, 3, 4])
43 def testConfidenceScore_HighConfidence(self
):
44 self
._AssertConfidence
(95.0, [0, 1, 1, 1, 2, 2], [1, 2, 2, 3, 3, 4])
46 def testConfidenceScore_VeryHighConfidence(self
):
47 # Confidence is high if the two sets of values have no internal variance.
48 self
._AssertConfidence
(99.9, [1, 1, 1, 1], [1.2, 1.2, 1.2, 1.2])
49 self
._AssertConfidence
(99.9, [1, 1, 1, 1], [1.01, 1.01, 1.01, 1.01])
51 def testConfidenceScore_UnbalancedSampleSize(self
):
52 # The second set of numbers only contains one number, so confidence is 0.
53 self
._AssertConfidence
(0.0, [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2], [1.4])
55 def testConfidenceScore_EmptySample(self
):
56 # Confidence is zero if either or both samples are empty.
57 self
._AssertConfidence
(0.0, [], [])
58 self
._AssertConfidence
(0.0, [], [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2, 1.3])
59 self
._AssertConfidence
(0.0, [1.1, 1.2, 1.1, 1.2, 1.0, 1.3, 1.2, 1.3], [])
61 def testConfidenceScore_FunctionalTestResults(self
):
62 self
._AssertConfidence
(80.0, [1, 1, 0, 1, 1, 1, 0, 1], [0, 0, 1, 0, 1, 0])
63 self
._AssertConfidence
(99.9, [1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0])
65 def testParseDEPSStringManually(self
):
66 """Tests DEPS parsing."""
67 deps_file_contents
= """
70 '@ac4a9f31fe2610bd146857bbd55d7a260003a888',
72 'https://chromium.googlesource.com/chromium/blink.git',
74 'https://chromium.googlesource.com',
76 '@e01ac0a267d1017288bc67fa3c366b10469d8a24',
78 '74697cf2064c0a2c0d7e1b1b28db439286766a05'
81 # Should only expect SVN/git revisions to come through, and URLs should be
83 expected_vars_dict
= {
84 'ffmpeg_hash': '@ac4a9f31fe2610bd146857bbd55d7a260003a888',
85 'webkit_rev': '@e01ac0a267d1017288bc67fa3c366b10469d8a24',
86 'angle_revision': '74697cf2064c0a2c0d7e1b1b28db439286766a05'
88 # Testing private function.
89 # pylint: disable=W0212
90 vars_dict
= bisect_perf_module
._ParseRevisionsFromDEPSFileManually
(
92 self
.assertEqual(vars_dict
, expected_vars_dict
)
94 def _AssertParseResult(self
, expected_values
, result_string
):
95 """Asserts some values are parsed from a RESULT line."""
96 results_template
= ('RESULT other_chart: other_trace= 123 count\n'
97 'RESULT my_chart: my_trace= %(value)s\n')
98 results
= results_template
% {'value': result_string
}
99 metric
= ['my_chart', 'my_trace']
100 # Testing private function.
101 # pylint: disable=W0212
102 values
= bisect_perf_module
._TryParseResultValuesFromOutput
(metric
, results
)
103 self
.assertEqual(expected_values
, values
)
105 def testTryParseResultValuesFromOutput_WithSingleValue(self
):
106 """Tests result pattern <*>RESULT <graph>: <trace>= <value>"""
107 self
._AssertParseResult
([66.88], '66.88 kb')
108 self
._AssertParseResult
([66.88], '66.88 ')
109 self
._AssertParseResult
([-66.88], '-66.88 kb')
110 self
._AssertParseResult
([66], '66 kb')
111 self
._AssertParseResult
([0.66], '.66 kb')
112 self
._AssertParseResult
([], '. kb')
113 self
._AssertParseResult
([], 'aaa kb')
115 def testTryParseResultValuesFromOutput_WithMultiValue(self
):
116 """Tests result pattern <*>RESULT <graph>: <trace>= [<value>,<value>, ..]"""
117 self
._AssertParseResult
([66.88], '[66.88] kb')
118 self
._AssertParseResult
([66.88, 99.44], '[66.88, 99.44]kb')
119 self
._AssertParseResult
([66.88, 99.44], '[ 66.88, 99.44 ]')
120 self
._AssertParseResult
([-66.88, 99.44], '[-66.88, 99.44] kb')
121 self
._AssertParseResult
([-66, 99], '[-66,99] kb')
122 self
._AssertParseResult
([-66, 99], '[-66,99,] kb')
123 self
._AssertParseResult
([-66, 0.99], '[-66,.99] kb')
124 self
._AssertParseResult
([], '[] kb')
125 self
._AssertParseResult
([], '[-66,abc] kb')
127 def testTryParseResultValuesFromOutputWithMeanStd(self
):
128 """Tests result pattern <*>RESULT <graph>: <trace>= {<mean, std}"""
129 self
._AssertParseResult
([33.22], '{33.22, 3.6} kb')
130 self
._AssertParseResult
([33.22], '{33.22, 3.6} kb')
131 self
._AssertParseResult
([33.22], '{33.22,3.6}kb')
132 self
._AssertParseResult
([33.22], '{33.22,3.6} kb')
133 self
._AssertParseResult
([33.22], '{ 33.22,3.6 }kb')
134 self
._AssertParseResult
([-33.22], '{-33.22,3.6}kb')
135 self
._AssertParseResult
([22], '{22,6}kb')
136 self
._AssertParseResult
([.22], '{.22,6}kb')
137 self
._AssertParseResult
([], '{.22,6, 44}kb')
138 self
._AssertParseResult
([], '{}kb')
139 self
._AssertParseResult
([], '{XYZ}kb')
141 def _AssertCompatibleCommand(
142 self
, expected_command
, original_command
, revision
, target_platform
):
143 """Tests the modification of the command that might be done.
145 This modification to the command is done in order to get a Telemetry
146 command that works; before some revisions, the browser name that Telemetry
147 expects is different in some cases, but we want it to work anyway.
149 Specifically, only for android:
150 After r276628, only android-chrome-shell works.
151 Prior to r274857, only android-chromium-testshell works.
152 In the range [274857, 276628], both work.
154 bisect_options
= bisect_perf_module
.BisectOptions()
155 bisect_options
.output_buildbot_annotations
= None
156 source_control
= source_control_module
.DetermineAndCreateSourceControl(
158 bisect_instance
= bisect_perf_module
.BisectPerformanceMetrics(
159 source_control
, bisect_options
)
160 bisect_instance
.opts
.target_platform
= target_platform
161 git_revision
= bisect_instance
.source_control
.ResolveToRevision(
162 revision
, 'chromium', bisect_perf_module
.DEPOT_DEPS_NAME
, 100)
164 command
= bisect_instance
.GetCompatibleCommand(
165 original_command
, git_revision
, depot
)
166 self
.assertEqual(expected_command
, command
)
168 def testGetCompatibleCommand_ChangeToTestShell(self
):
169 # For revisions <= r274857, only android-chromium-testshell is used.
170 self
._AssertCompatibleCommand
(
171 'tools/perf/run_benchmark -v --browser=android-chromium-testshell foo',
172 'tools/perf/run_benchmark -v --browser=android-chrome-shell foo',
175 def testGetCompatibleCommand_ChangeToShell(self
):
176 # For revisions >= r276728, only android-chrome-shell can be used.
177 self
._AssertCompatibleCommand
(
178 'tools/perf/run_benchmark -v --browser=android-chrome-shell foo',
179 'tools/perf/run_benchmark -v --browser=android-chromium-testshell foo',
182 def testGetCompatibleCommand_NoChange(self
):
183 # For revisions < r276728, android-chromium-testshell can be used.
184 self
._AssertCompatibleCommand
(
185 'tools/perf/run_benchmark -v --browser=android-chromium-testshell foo',
186 'tools/perf/run_benchmark -v --browser=android-chromium-testshell foo',
188 # For revisions > r274857, android-chrome-shell can be used.
189 self
._AssertCompatibleCommand
(
190 'tools/perf/run_benchmark -v --browser=android-chrome-shell foo',
191 'tools/perf/run_benchmark -v --browser=android-chrome-shell foo',
194 def testGetCompatibleCommand_NonAndroidPlatform(self
):
195 # In most cases, there's no need to change Telemetry command.
196 # For revisions >= r276728, only android-chrome-shell can be used.
197 self
._AssertCompatibleCommand
(
198 'tools/perf/run_benchmark -v --browser=release foo',
199 'tools/perf/run_benchmark -v --browser=release foo',
202 # This method doesn't reference self; it fails if an error is thrown.
203 # pylint: disable=R0201
204 def testDryRun(self
):
205 """Does a dry run of the bisect script.
207 This serves as a smoke test to catch errors in the basic execution of the
211 'debug_ignore_build': True,
212 'debug_ignore_sync': True,
213 'debug_ignore_perf_test': True,
214 'command': 'fake_command',
215 'metric': 'fake/metric',
216 'good_revision': 280000,
217 'bad_revision': 280005,
219 bisect_options
= bisect_perf_module
.BisectOptions
.FromDict(options_dict
)
220 source_control
= source_control_module
.DetermineAndCreateSourceControl(
222 bisect_instance
= bisect_perf_module
.BisectPerformanceMetrics(
223 source_control
, bisect_options
)
224 results
= bisect_instance
.Run(bisect_options
.command
,
225 bisect_options
.bad_revision
,
226 bisect_options
.good_revision
,
227 bisect_options
.metric
)
228 bisect_instance
.FormatAndPrintResults(results
)
231 if __name__
== '__main__':