Chromium Code Reviews

Side by Side Diff: webkit/tools/layout_tests/layout_package/json_results_generator.py

Issue 213031: Insert summary results to the JSON. These are the same results spit to stdout... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « no previous file | webkit/tools/layout_tests/run_webkit_tests.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import logging 5 import logging
6 import os 6 import os
7 import re 7 import re
8 import subprocess 8 import subprocess
9 import sys 9 import sys
10 import time 10 import time
11 import xml.dom.minidom 11 import xml.dom.minidom
12 12
13 from layout_package import path_utils 13 from layout_package import path_utils
14 from layout_package import test_failures 14 from layout_package import test_failures
15 15
16 sys.path.append(path_utils.PathFromBase('third_party')) 16 sys.path.append(path_utils.PathFromBase('third_party'))
17 import simplejson 17 import simplejson
18 18
19 class JSONResultsGenerator: 19 class JSONResultsGenerator:
20 20
21 MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 500 21 MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 500
22 # Min time (seconds) that will be added to the JSON. 22 # Min time (seconds) that will be added to the JSON.
23 MIN_TIME = 1 23 MIN_TIME = 1
24 JSON_PREFIX = "ADD_RESULTS(" 24 JSON_PREFIX = "ADD_RESULTS("
25 JSON_SUFFIX = ");" 25 JSON_SUFFIX = ");"
26 WEBKIT_PATH = "WebKit" 26 WEBKIT_PATH = "WebKit"
27 LAYOUT_TESTS_PATH = "layout_tests" 27 LAYOUT_TESTS_PATH = "layout_tests"
28 PASS_RESULT = "P" 28 PASS_RESULT = "P"
29 SKIP_RESULT = "X"
29 NO_DATA_RESULT = "N" 30 NO_DATA_RESULT = "N"
30 VERSION = 1 31 VERSION = 1
31 VERSION_KEY = "version" 32 VERSION_KEY = "version"
32 RESULTS = "results" 33 RESULTS = "results"
33 TIMES = "times" 34 TIMES = "times"
34 BUILD_NUMBERS = "buildNumbers" 35 BUILD_NUMBERS = "buildNumbers"
35 WEBKIT_SVN = "webkitRevision" 36 WEBKIT_SVN = "webkitRevision"
36 CHROME_SVN = "chromeRevision" 37 CHROME_SVN = "chromeRevision"
37 TIME = "secondsSinceEpoch" 38 TIME = "secondsSinceEpoch"
38 TESTS = "tests" 39 TESTS = "tests"
40 NON_WONTFIX = "nonWontfixCounts"
41 DEFERRED = "deferredCounts"
42 ALL = "allCounts"
43 FIXABLE_COUNT = "fixableCount"
44 FAILURE_CHARS = ["C", "T", "I", "S", "F", "O"]
39 45
40 def __init__(self, failures, individual_test_timings, builder_name, 46 def __init__(self, failures, individual_test_timings, builder_name,
41 build_number, results_file_path, all_tests): 47 build_number, results_file_path, all_tests, result_summary):
42 """ 48 """
43 failures: Map of test name to list of failures. 49 failures: Map of test name to list of failures.
44 individual_test_times: Map of test name to a tuple containing the 50 individual_test_times: Map of test name to a tuple containing the
45 test_run-time. 51 test_run-time.
46 builder_name: The name of the builder the tests are being run on. 52 builder_name: The name of the builder the tests are being run on.
47 build_number: The build number for this run. 53 build_number: The build number for this run.
48 results_file_path: Absolute path to the results json file. 54 results_file_path: Absolute path to the results json file.
49 all_tests: List of all the tests that were run. 55 all_tests: List of all the tests that were run.
56 result_summary: ResultsSummary object containing failure counts for
57 different groups of tests.
50 """ 58 """
51 # Make sure all test paths are relative to the layout test root directory. 59 # Make sure all test paths are relative to the layout test root directory.
52 self._failures = {} 60 self._failures = {}
53 for test in failures: 61 for test in failures:
54 test_path = self._GetPathRelativeToLayoutTestRoot(test) 62 test_path = self._GetPathRelativeToLayoutTestRoot(test)
55 self._failures[test_path] = failures[test] 63 self._failures[test_path] = failures[test]
56 64
57 self._all_tests = [self._GetPathRelativeToLayoutTestRoot(test) 65 self._all_tests = [self._GetPathRelativeToLayoutTestRoot(test)
58 for test in all_tests] 66 for test in all_tests]
59 67
68 self._result_summary = result_summary
69
60 self._test_timings = {} 70 self._test_timings = {}
61 for test_tuple in individual_test_timings: 71 for test_tuple in individual_test_timings:
62 test_path = self._GetPathRelativeToLayoutTestRoot(test_tuple.filename) 72 test_path = self._GetPathRelativeToLayoutTestRoot(test_tuple.filename)
63 self._test_timings[test_path] = test_tuple.test_run_time 73 self._test_timings[test_path] = test_tuple.test_run_time
64 74
65 self._builder_name = builder_name 75 self._builder_name = builder_name
66 self._build_number = build_number 76 self._build_number = build_number
67 self._results_file_path = results_file_path 77 self._results_file_path = results_file_path
68 78
69 def _GetSVNRevision(self, in_directory=None): 79 def _GetSVNRevision(self, in_directory=None):
(...skipping 36 matching lines...)
106 relativePath = test[index + 1:] 116 relativePath = test[index + 1:]
107 117
108 # Make sure all paths are unix-style. 118 # Make sure all paths are unix-style.
109 return relativePath.replace('\\', '/') 119 return relativePath.replace('\\', '/')
110 120
111 def GetJSON(self): 121 def GetJSON(self):
112 """Gets the results for the results.json file.""" 122 """Gets the results for the results.json file."""
113 failures_for_json = {} 123 failures_for_json = {}
114 for test in self._failures: 124 for test in self._failures:
115 failures_for_json[test] = ResultAndTime(test, self._all_tests) 125 failures_for_json[test] = ResultAndTime(test, self._all_tests)
116 failures_for_json[test].result = self._GetResultsCharForFailure(test) 126 failures_for_json[test].result = self._GetResultsCharForTest(test)
117 127
118 for test in self._test_timings: 128 for test in self._test_timings:
119 if not test in failures_for_json: 129 if not test in failures_for_json:
120 failures_for_json[test] = ResultAndTime(test, self._all_tests) 130 failures_for_json[test] = ResultAndTime(test, self._all_tests)
121 # Floor for now to get time in seconds. 131 # Floor for now to get time in seconds.
122 # TODO(ojan): As we make tests faster, reduce to tenth of a second 132 # TODO(ojan): As we make tests faster, reduce to tenth of a second
123 # granularity. 133 # granularity.
124 failures_for_json[test].time = int(self._test_timings[test]) 134 failures_for_json[test].time = int(self._test_timings[test])
125 135
126 # If results file exists, read it out, put new info in it. 136 # If results file exists, read it out, put new info in it.
(...skipping 40 matching lines...)
167 177
168 path_to_chrome_base = path_utils.PathFromBase() 178 path_to_chrome_base = path_utils.PathFromBase()
169 self._InsertItemIntoRawList(results_for_builder, 179 self._InsertItemIntoRawList(results_for_builder,
170 self._GetSVNRevision(path_to_chrome_base), 180 self._GetSVNRevision(path_to_chrome_base),
171 self.CHROME_SVN) 181 self.CHROME_SVN)
172 182
173 self._InsertItemIntoRawList(results_for_builder, 183 self._InsertItemIntoRawList(results_for_builder,
174 int(time.time()), 184 int(time.time()),
175 self.TIME) 185 self.TIME)
176 186
187 self._InsertFailureSummaries(results_for_builder)
188
177 for test in all_failing_tests: 189 for test in all_failing_tests:
178 if test in failures_for_json: 190 if test in failures_for_json:
179 result_and_time = failures_for_json[test] 191 result_and_time = failures_for_json[test]
180 else: 192 else:
181 result_and_time = ResultAndTime(test, self._all_tests) 193 result_and_time = ResultAndTime(test, self._all_tests)
182 194
183 if test not in tests: 195 if test not in tests:
184 tests[test] = self._CreateResultsAndTimesJSON() 196 tests[test] = self._CreateResultsAndTimesJSON()
185 197
186 thisTest = tests[test] 198 thisTest = tests[test]
187 self._InsertItemRunLengthEncoded(result_and_time.result, 199 self._InsertItemRunLengthEncoded(result_and_time.result,
188 thisTest[self.RESULTS]) 200 thisTest[self.RESULTS])
189 self._InsertItemRunLengthEncoded(result_and_time.time, 201 self._InsertItemRunLengthEncoded(result_and_time.time,
190 thisTest[self.TIMES]) 202 thisTest[self.TIMES])
191 self._NormalizeResultsJSON(thisTest, test, tests) 203 self._NormalizeResultsJSON(thisTest, test, tests)
192 204
193 # Specify separators in order to get compact encoding. 205 # Specify separators in order to get compact encoding.
194 results_str = simplejson.dumps(results_json, separators=(',', ':')) 206 results_str = simplejson.dumps(results_json, separators=(',', ':'))
195 return self.JSON_PREFIX + results_str + self.JSON_SUFFIX 207 return self.JSON_PREFIX + results_str + self.JSON_SUFFIX
196 208
209 def _InsertFailureSummaries(self, results_for_builder):
210 """Inserts aggregate pass/failure statistics into the JSON.
211
212 Args:
213 results_for_builder: Dictionary containing the test results for a single
214 builder.
215 """
216 self._InsertItemIntoRawList(results_for_builder,
217 self._result_summary.fixable_count,
218 self.FIXABLE_COUNT)
219
220 self._InsertItemIntoRawList(results_for_builder,
221 self._GetFailureSummaryEntry(self._result_summary.deferred),
222 self.DEFERRED)
223 self._InsertItemIntoRawList(results_for_builder,
224 self._GetFailureSummaryEntry(self._result_summary.non_wontfix),
225 self.NON_WONTFIX)
226 self._InsertItemIntoRawList(results_for_builder,
227 self._GetFailureSummaryEntry(self._result_summary.all),
228 self.ALL)
229
230 def _GetFailureSummaryEntry(self, result_summary_entry):
231 """Creates a summary object to insert into the JSON.
232
233 Args:
234 result_summary_entry: ResultSummaryEntry for a group of tests
235 (e.g. deferred tests).
236 """
237 entry = {}
238 entry[self.SKIP_RESULT] = result_summary_entry.skip_count
239 entry[self.PASS_RESULT] = result_summary_entry.pass_count
240 for char in self.FAILURE_CHARS:
241 # There can be multiple failures that map to "O", so keep existing entry
242 # values if they already exist.
243 if char in entry:
244 count = entry[char]
245 else:
246 count = 0
247
248 for failure in result_summary_entry.failure_counts:
249 if char == self._GetResultsCharForFailure([failure]):
250 count = result_summary_entry.failure_counts[failure]
251 entry[char] = count
252 return entry
253
197 def _InsertItemIntoRawList(self, results_for_builder, item, key): 254 def _InsertItemIntoRawList(self, results_for_builder, item, key):
198 """Inserts the item into the list with the given key in the results for 255 """Inserts the item into the list with the given key in the results for
199 this builder. Creates the list if no such list exists. 256 this builder. Creates the list if no such list exists.
200 257
201 Args: 258 Args:
202 results_for_builder: Dictionary containing the test results for a single 259 results_for_builder: Dictionary containing the test results for a single
203 builder. 260 builder.
204 item: Number or string to insert into the list. 261 item: Number or string to insert into the list.
205 key: Key in results_for_builder for the list to insert into. 262 key: Key in results_for_builder for the list to insert into.
206 """ 263 """
(...skipping 50 matching lines...)
257 results_and_times = {} 314 results_and_times = {}
258 results_and_times[self.RESULTS] = [] 315 results_and_times[self.RESULTS] = []
259 results_and_times[self.TIMES] = [] 316 results_and_times[self.TIMES] = []
260 return results_and_times 317 return results_and_times
261 318
262 def _CreateResultsForBuilderJSON(self): 319 def _CreateResultsForBuilderJSON(self):
263 results_for_builder = {} 320 results_for_builder = {}
264 results_for_builder[self.TESTS] = {} 321 results_for_builder[self.TESTS] = {}
265 return results_for_builder 322 return results_for_builder
266 323
267 def _GetResultsCharForFailure(self, test): 324 def _GetResultsCharForTest(self, test):
268 """Returns the worst failure from the list of failures for this test 325 """Returns the worst failure from the list of failures for this test
269 since we can only show one failure per run for each test on the dashboard. 326 since we can only show one failure per run for each test on the dashboard.
270 """ 327 """
271 failures = [failure.__class__ for failure in self._failures[test]] 328 failures = [failure.__class__ for failure in self._failures[test]]
329 return self._GetResultsCharForFailure(failures)
272 330
331 def _GetResultsCharForFailure(self, failures):
332 """Returns the worst failure from the list of failures
333 since we can only show one failure per run for each test on the dashboard.
334 """
273 if test_failures.FailureCrash in failures: 335 if test_failures.FailureCrash in failures:
274 return "C" 336 return "C"
275 elif test_failures.FailureTimeout in failures: 337 elif test_failures.FailureTimeout in failures:
276 return "T" 338 return "T"
277 elif test_failures.FailureImageHashMismatch in failures: 339 elif test_failures.FailureImageHashMismatch in failures:
278 return "I" 340 return "I"
279 elif test_failures.FailureSimplifiedTextMismatch in failures: 341 elif test_failures.FailureSimplifiedTextMismatch in failures:
280 return "S" 342 return "S"
281 elif test_failures.FailureTextMismatch in failures: 343 elif test_failures.FailureTextMismatch in failures:
282 return "F" 344 return "F"
(...skipping 50 matching lines...)
333 395
334 class ResultAndTime: 396 class ResultAndTime:
335 """A holder for a single result and runtime for a test.""" 397 """A holder for a single result and runtime for a test."""
336 def __init__(self, test, all_tests): 398 def __init__(self, test, all_tests):
337 self.time = 0 399 self.time = 0
338 # If the test was run, then we don't want to default the result to nodata. 400 # If the test was run, then we don't want to default the result to nodata.
339 if test in all_tests: 401 if test in all_tests:
340 self.result = JSONResultsGenerator.PASS_RESULT 402 self.result = JSONResultsGenerator.PASS_RESULT
341 else: 403 else:
342 self.result = JSONResultsGenerator.NO_DATA_RESULT 404 self.result = JSONResultsGenerator.NO_DATA_RESULT
OLDNEW
« no previous file with comments | « no previous file | webkit/tools/layout_tests/run_webkit_tests.py » ('j') | no next file with comments »

Powered by Google App Engine