| Index: webkit/tools/layout_tests/canary-webkit-revisions.py
|
| diff --git a/webkit/tools/layout_tests/canary-webkit-revisions.py b/webkit/tools/layout_tests/canary-webkit-revisions.py
|
| deleted file mode 100755
|
| index 2ba5fd68617e020c0e87e2208c71ded6886e8f04..0000000000000000000000000000000000000000
|
| --- a/webkit/tools/layout_tests/canary-webkit-revisions.py
|
| +++ /dev/null
|
| @@ -1,291 +0,0 @@
|
| -#!/usr/bin/env python
|
| -# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Retrieve passing and failing WebKit revision numbers from canaries.
|
| -
|
| -From each canary,
|
| -- the last WebKit revision number for which all the tests have passed,
|
| -- the last WebKit revision number for which the tests were run, and
|
| -- the names of failing layout tests
|
| -are retrieved and printed.
|
| -"""
|
| -
|
| -
|
| -import json
|
| -import optparse
|
| -import re
|
| -import sys
|
| -import urllib2
|
| -
|
| -_WEBKIT_REVISION_IN_DEPS_RE = re.compile(r'"webkit_revision"\s*:\s*"(\d+)"')
|
| -_DEPS_FILE_URL = "http://src.chromium.org/viewvc/chrome/trunk/src/DEPS"
|
| -_DEFAULT_BUILDERS = [
|
| - "Webkit Win",
|
| - "Webkit Vista",
|
| - "Webkit Win7",
|
| - "Webkit Win (dbg)(1)",
|
| - "Webkit Win (dbg)(2)",
|
| - "Webkit Mac10.5 (CG)",
|
| - "Webkit Mac10.6 (CG)",
|
| - "Webkit Mac10.5 (CG)(dbg)(1)",
|
| - "Webkit Mac10.5 (CG)(dbg)(2)",
|
| - "Webkit Mac10.6 (CG)(dbg)",
|
| - "Webkit Linux",
|
| - "Webkit Linux 32",
|
| - "Webkit Linux (dbg)(1)",
|
| - "Webkit Linux (dbg)(2)",
|
| -]
|
| -_DEFAULT_MAX_BUILDS = 10
|
| -_TEST_PREFIX = "&tests="
|
| -_TEST_SUFFIX = '">'
|
| -_WEBKIT_TESTS = "webkit_tests"
|
| -
|
| -
|
| -def _OpenUrl(url):
|
| - """Opens a URL.
|
| -
|
| - Returns:
|
| - A file-like object in case of success, an empty list otherwise.
|
| - """
|
| - try:
|
| - return urllib2.urlopen(url)
|
| - except urllib2.URLError, url_error:
|
| - message = ""
|
| - # Surprisingly, urllib2.URLError has different attributes based on the
|
| - # kinds of errors -- "code" for HTTP-level errors, "reason" for others.
|
| - if hasattr(url_error, "code"):
|
| - message = "Status code: %d" % url_error.code
|
| - if hasattr(url_error, "reason"):
|
| - message = url_error.reason
|
| - print >>sys.stderr, "Failed to open %s: %s" % (url, message)
|
| - return []
|
| -
|
| -
|
| -def _WebkitRevisionInDeps():
|
| - """Returns the WebKit revision specified in DEPS file.
|
| -
|
| - Returns:
|
| - Revision number as int. -1 in case of error.
|
| - """
|
| - for line in _OpenUrl(_DEPS_FILE_URL):
|
| - match = _WEBKIT_REVISION_IN_DEPS_RE.search(line)
|
| - if match:
|
| - return int(match.group(1))
|
| - return -1
|
| -
|
| -
|
| -class _BuildResult(object):
|
| - """Build result for a builder.
|
| -
|
| - Holds builder name, the last passing revision, the last run revision, and
|
| - a list of names of failing tests. Revision nubmer 0 is used to represent
|
| - that the revision doesn't exist.
|
| - """
|
| - def __init__(self, builder, last_passing_revision, last_run_revision,
|
| - failing_tests):
|
| - """Constructs build results."""
|
| - self.builder = builder
|
| - self.last_passing_revision = last_passing_revision
|
| - self.last_run_revision = last_run_revision
|
| - self.failing_tests = failing_tests
|
| -
|
| -
|
| -def _BuilderUrlFor(builder, max_builds):
|
| - """Constructs the URL for a builder to retrieve the last results."""
|
| - url = ("http://build.chromium.org/p/chromium.webkit/json/builders/%s/builds" %
|
| - urllib2.quote(builder))
|
| - if max_builds == -1:
|
| - return url + "/_all?as_text=1"
|
| - return (url + "?as_text=1&" +
|
| - '&'.join(["select=%d" % -i for i in range(1, 1 + max_builds)]))
|
| -
|
| -
|
| -def _ExtractFailingTests(build):
|
| - """Extracts failing test names from a build result entry JSON object."""
|
| - failing_tests = []
|
| - for step in build["steps"]:
|
| - if step["name"] == _WEBKIT_TESTS:
|
| - for text in step["text"]:
|
| - prefix = text.find(_TEST_PREFIX)
|
| - suffix = text.find(_TEST_SUFFIX)
|
| - if prefix != -1 and suffix != -1:
|
| - failing_tests += sorted(
|
| - text[prefix + len(_TEST_PREFIX): suffix].split(","))
|
| - elif "results" in step:
|
| - # Existence of "results" entry seems to mean failure.
|
| - failing_tests.append(" ".join(step["text"]))
|
| - return failing_tests
|
| -
|
| -
|
| -def _RetrieveBuildResult(builder, max_builds, oldest_revision_to_check):
|
| - """Retrieves build results for a builder.
|
| -
|
| - Checks the last passing revision, the last run revision, and failing tests
|
| - for the last builds of a builder.
|
| -
|
| - Args:
|
| - builder: Builder name.
|
| - max_builds: Maximum number of builds to check.
|
| - oldest_revision_to_check: Oldest WebKit revision to check.
|
| -
|
| - Returns:
|
| - _BuildResult instance.
|
| - """
|
| - last_run_revision = 0
|
| - failing_tests = []
|
| - succeeded = False
|
| - builds_json = _OpenUrl(_BuilderUrlFor(builder, max_builds))
|
| - if not builds_json:
|
| - return _BuildResult(builder, 0, 0, failing_tests)
|
| - builds = [(int(value["number"]), value) for unused_key, value
|
| - in json.loads(''.join(builds_json)).items()
|
| - if value.has_key("number")]
|
| - builds.sort()
|
| - builds.reverse()
|
| - for unused_key, build in builds:
|
| - if not build.has_key("text"):
|
| - continue
|
| - if len(build["text"]) < 2:
|
| - continue
|
| - if not build.has_key("sourceStamp"):
|
| - continue
|
| - if build["text"][1] == "successful":
|
| - succeeded = True
|
| - elif not failing_tests:
|
| - failing_tests = _ExtractFailingTests(build)
|
| - revision = 0
|
| - if build["sourceStamp"]["branch"] == "trunk":
|
| - revision = int(build["sourceStamp"]["changes"][-1]["revision"])
|
| - if revision and not last_run_revision:
|
| - last_run_revision = revision
|
| - if revision and revision < oldest_revision_to_check:
|
| - break
|
| - if not succeeded or not revision:
|
| - continue
|
| - return _BuildResult(builder, revision, last_run_revision, failing_tests)
|
| - return _BuildResult(builder, 0, last_run_revision, failing_tests)
|
| -
|
| -
|
| -def _PrintPassingRevisions(results, unused_verbose):
|
| - """Prints passing revisions and the range of such revisions.
|
| -
|
| - Args:
|
| - results: A list of build results.
|
| - """
|
| - print "**** Passing revisions *****"
|
| - min_passing_revision = sys.maxint
|
| - max_passing_revision = 0
|
| - for result in results:
|
| - if result.last_passing_revision:
|
| - min_passing_revision = min(min_passing_revision,
|
| - result.last_passing_revision)
|
| - max_passing_revision = max(max_passing_revision,
|
| - result.last_passing_revision)
|
| - print 'The last passing run was at r%d on "%s"' % (
|
| - result.last_passing_revision, result.builder)
|
| - else:
|
| - print 'No passing runs on "%s"' % result.builder
|
| - if max_passing_revision:
|
| - print "Passing revision range: r%d - r%d" % (
|
| - min_passing_revision, max_passing_revision)
|
| -
|
| -
|
| -def _PrintFailingRevisions(results, verbose):
|
| - """Prints failing revisions and the failing tests.
|
| -
|
| - Args:
|
| - results: A list of build results.
|
| - """
|
| - failing_test_to_builders = {}
|
| - print "**** Failing revisions *****"
|
| - for result in results:
|
| - if result.last_run_revision and result.failing_tests:
|
| - print ('The last run was at r%d on "%s" and the following %d tests'
|
| - ' failed' % (result.last_run_revision, result.builder,
|
| - len(result.failing_tests)))
|
| - for test in result.failing_tests:
|
| - print " " + test
|
| - failing_test_to_builders.setdefault(test, set()).add(result.builder)
|
| - if verbose:
|
| - _PrintFailingTestsForBuilderSubsets(failing_test_to_builders)
|
| -
|
| -
|
| -class _FailingTestsForBuilderSubset(object):
|
| - def __init__(self, subset_size):
|
| - self._subset_size = subset_size
|
| - self._tests = []
|
| -
|
| - def SubsetSize(self):
|
| - return self._subset_size
|
| -
|
| - def Tests(self):
|
| - return self._tests
|
| -
|
| -
|
| -def _PrintFailingTestsForBuilderSubsets(failing_test_to_builders):
|
| - """Prints failing test for builder subsets.
|
| -
|
| - Prints failing tests for each subset of builders, in descending order of the
|
| - set size.
|
| - """
|
| - print "**** Failing tests ****"
|
| - builders_to_tests = {}
|
| - for test in failing_test_to_builders:
|
| - builders = sorted(failing_test_to_builders[test])
|
| - subset_name = ", ".join(builders)
|
| - tests = builders_to_tests.setdefault(
|
| - subset_name, _FailingTestsForBuilderSubset(len(builders))).Tests()
|
| - tests.append(test)
|
| - # Sort subsets in descending order of size and then name.
|
| - builder_subsets = [(builders_to_tests[subset_name].SubsetSize(), subset_name)
|
| - for subset_name in builders_to_tests]
|
| - for subset_size, subset_name in reversed(sorted(builder_subsets)):
|
| - print "** Tests failing for %d builders: %s **" % (subset_size,
|
| - subset_name)
|
| - for test in sorted(builders_to_tests[subset_name].Tests()):
|
| - print test
|
| -
|
| -
|
| -def _ParseOptions():
|
| - """Parses command-line options."""
|
| - parser = optparse.OptionParser(usage="%prog [options] [builders]")
|
| - parser.add_option("-m", "--max_builds", type="int",
|
| - default=-1,
|
| - help="Maximum number of builds to check for each builder."
|
| - " Defaults to all builds for which record is"
|
| - " available. Checking is ended either when the maximum"
|
| - " number is reached, the remaining builds are older"
|
| - " than the DEPS WebKit revision, or a passing"
|
| - " revision is found.")
|
| - parser.add_option("-v", "--verbose", action="store_true", default=False,
|
| - dest="verbose")
|
| - return parser.parse_args()
|
| -
|
| -
|
| -def _Main():
|
| - """The main function."""
|
| - options, builders = _ParseOptions()
|
| - if not builders:
|
| - builders = _DEFAULT_BUILDERS
|
| - oldest_revision_to_check = _WebkitRevisionInDeps()
|
| - if options.max_builds == -1 and oldest_revision_to_check == -1:
|
| - options.max_builds = _DEFAULT_MAX_BUILDS
|
| - if options.max_builds != -1:
|
| - print "Maxium number of builds to check: %d" % options.max_builds
|
| - if oldest_revision_to_check != -1:
|
| - print "Oldest revision to check: %d" % oldest_revision_to_check
|
| - sys.stdout.flush()
|
| - results = []
|
| - for builder in builders:
|
| - print '"%s"' % builder
|
| - sys.stdout.flush()
|
| - results.append(_RetrieveBuildResult(
|
| - builder, options.max_builds, oldest_revision_to_check))
|
| - _PrintFailingRevisions(results, options.verbose)
|
| - _PrintPassingRevisions(results, options.verbose)
|
| -
|
| -
|
| -if __name__ == "__main__":
|
| - _Main()
|
|
|