Auto merge of #14331 - Manishearth:filter-intermittents, r=larsbergstrom,jdm

Add ./mach filter-intermittents for catching intermittents on CI

cc @metajack

The plan here is to run this on the error summary of the logs after each WPT/CSS run, as `./mach filter-intermittents wpt-errorsummary.log --output filtered-errorsummary.log --auth /path/to/authfile`

The `filtered-errorsummary.log` file will be a buildbot artifact for this run, and can be used for updating test results.

We change WPT/CSS runs to not cause test failures on Buildbot; instead; the test failure will be caused by this job.

We should at some point add a separate highfive task which ccs the appropriate bugs and tracks consistent failures. (We can change mach filter-intermittents to output a second file of intermittents matched to bug numbers to make this easy)

A small issue with this is that this simple task might mask failures of the WPT harness itself. We have a separate test that tests if the test harness works though. (This test will fail if the log files it requires don't exist, perhaps that's enough to solve the problem)

r? @larsbergstrom

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14331)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-11-28 15:18:04 -08:00 committed by GitHub
commit 4021d057c9
2 changed files with 80 additions and 7 deletions

View file

@ -17,6 +17,9 @@ import os.path as path
import copy
from collections import OrderedDict
from time import time
import json
import urllib2
import base64
from mach.registrar import Registrar
from mach.decorators import (
@ -65,6 +68,8 @@ def create_parser_wpt():
help="Run under chaos mode in rr until a failure is captured")
parser.add_argument('--pref', default=[], action="append", dest="prefs",
help="Pass preferences to servo")
parser.add_argument('--always-succeed', default=False, action="store_true",
help="Always yield exit code of zero")
return parser
@ -396,7 +401,11 @@ class MachCommands(CommandBase):
parser=create_parser_wpt)
def test_wpt(self, **kwargs):
self.ensure_bootstrapped()
return self.run_test_list_or_dispatch(kwargs["test_list"], "wpt", self._test_wpt, **kwargs)
ret = self.run_test_list_or_dispatch(kwargs["test_list"], "wpt", self._test_wpt, **kwargs)
if kwargs["always_succeed"]:
return 0
else:
return ret
def _test_wpt(self, **kwargs):
hosts_file_path = path.join(self.context.topdir, 'tests', 'wpt', 'hosts')
@ -470,6 +479,61 @@ class MachCommands(CommandBase):
execfile(run_file, run_globals)
return run_globals["update_tests"](**kwargs)
@Command('filter-intermittents',
description='Given a WPT error summary file, filter out intermittents and other cruft.',
category='testing')
@CommandArgument('summary',
help="Error summary log to take un")
@CommandArgument('--log-filteredsummary', default=None,
help='Print filtered log to file')
@CommandArgument('--auth', default=None,
help='File containing basic authorization credentials for Github API (format `username:password`)')
@CommandArgument('--use-tracker', default=False, action='store_true',
help='Use https://www.joshmatthews.net/intermittent-tracker')
def filter_intermittents(self, summary, log_filteredsummary, auth, use_tracker):
encoded_auth = None
if auth:
with open(auth, "r") as file:
encoded_auth = base64.encodestring(file.read().strip()).replace('\n', '')
failures = []
with open(summary, "r") as file:
for line in file:
line_json = json.loads(line)
if 'status' in line_json:
failures += [line_json]
actual_failures = []
for failure in failures:
if use_tracker:
query = urllib2.quote(failure['test'], safe='')
request = urllib2.Request("https://www.joshmatthews.net/intermittent-tracker/query.py?name=%s" % query)
search = urllib2.urlopen(request)
data = json.load(search)
if len(data) == 0:
actual_failures += [failure]
else:
qstr = "repo:servo/servo+label:I-intermittent+type:issue+state:open+%s" % failure['test']
# we want `/` to get quoted, but not `+` (github's API doesn't like that), so we set `safe` to `+`
query = urllib2.quote(qstr, safe='+')
request = urllib2.Request("https://api.github.com/search/issues?q=%s" % query)
if encoded_auth:
request.add_header("Authorization", "Basic %s" % encoded_auth)
search = urllib2.urlopen(request)
data = json.load(search)
if data['total_count'] == 0:
actual_failures += [failure]
if len(actual_failures) == 0:
return 0
output = open(log_filteredsummary, "w") if log_filteredsummary else sys.stdout
for failure in actual_failures:
json.dump(failure, output)
print("\n", end='', file=output)
if output is not sys.stdout:
output.close()
return 1
@Command('test-jquery',
description='Run the jQuery test suite',
category='testing')
@ -508,7 +572,11 @@ class MachCommands(CommandBase):
parser=create_parser_wpt)
def test_css(self, **kwargs):
self.ensure_bootstrapped()
return self.run_test_list_or_dispatch(kwargs["test_list"], "css", self._test_css, **kwargs)
ret = self.run_test_list_or_dispatch(kwargs["test_list"], "css", self._test_css, **kwargs)
if kwargs["always_succeed"]:
return 0
else:
return ret
def _test_css(self, **kwargs):
run_file = path.abspath(path.join("tests", "wpt", "run_css.py"))