Skip to content

Commit e2ea91e

Browse files
committed
Bug 1777063 - add intermittent failure data to test-info report. r=gbrown
Differential Revision: https://phabricator.services.mozilla.com/D150668
1 parent ea3afb4 commit e2ea91e

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

testing/mach_commands.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,14 @@ def test_info_tests(
868868
)
869869
@CommandArgument("--output-file", help="Path to report file.")
870870
@CommandArgument("--verbose", action="store_true", help="Enable debug logging.")
871+
@CommandArgument(
872+
"--start",
873+
default=(date.today() - timedelta(30)).strftime("%Y-%m-%d"),
874+
help="Start date (YYYY-MM-DD)",
875+
)
876+
@CommandArgument(
877+
"--end", default=date.today().strftime("%Y-%m-%d"), help="End date (YYYY-MM-DD)"
878+
)
871879
def test_report(
872880
command_context,
873881
components,
@@ -883,6 +891,8 @@ def test_report(
883891
show_components,
884892
output_file,
885893
verbose,
894+
start,
895+
end,
886896
):
887897
import testinfo
888898
from mozbuild import build_commands
@@ -907,6 +917,8 @@ def test_report(
907917
filter_keys,
908918
show_components,
909919
output_file,
920+
start,
921+
end,
910922
)
911923

912924

testing/testinfo.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ def description(
308308
show_annotations,
309309
filter_values,
310310
filter_keys,
311+
start_date,
312+
end_date,
311313
):
312314
# provide a natural language description of the report options
313315
what = []
@@ -339,9 +341,80 @@ def description(
339341
d += " in manifest keys '%s'" % filter_keys
340342
else:
341343
d += " in any part of manifest entry"
342-
d += " as of %s." % datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
344+
d += ", including historical run-time data for the last "
345+
346+
start = datetime.datetime.strptime(start_date, "%Y-%m-%d")
347+
end = datetime.datetime.strptime(end_date, "%Y-%m-%d")
348+
d += "%s days on trunk (autoland/m-c)" % ((end - start).days)
349+
d += " as of %s." % end_date
343350
return d
344351

352+
# TODO: this is hacked for now and very limited
353+
def parse_test(self, summary):
354+
if summary.endswith("single tracking bug"):
355+
name_part = summary.split("|")[0] # remove 'single tracking bug'
356+
name_part.strip()
357+
return name_part.split()[-1] # get just the test name, not extra words
358+
return None
359+
360+
def get_intermittent_failure_data(self, start, end):
361+
retVal = {}
362+
363+
# get IFV bug list
364+
# i.e. https://th.m.o/api/failures/?startday=2022-06-22&endday=2022-06-29&tree=all
365+
url = (
366+
"https://treeherder.mozilla.org/api/failures/?startday=%s&endday=%s&tree=trunk"
367+
% (start, end)
368+
)
369+
r = requests.get(url, headers={"User-agent": "mach-test-info/1.0"})
370+
if_data = r.json()
371+
buglist = [x["bug_id"] for x in if_data]
372+
373+
# get bug data for summary, 800 bugs at a time
374+
# i.e. https://b.m.o/rest/bug?include_fields=id,product,component,summary&id=1,2,3...
375+
max_bugs = 800
376+
bug_data = []
377+
fields = ["id", "product", "component", "summary"]
378+
for bug_index in range(0, len(buglist), max_bugs):
379+
bugs = [str(x) for x in buglist[bug_index:max_bugs]]
380+
url = "https://bugzilla.mozilla.org/rest/bug?include_fields=%s&id=%s" % (
381+
",".join(fields),
382+
",".join(bugs),
383+
)
384+
r = requests.get(url, headers={"User-agent": "mach-test-info/1.0"})
385+
data = r.json()
386+
if data and "bugs" in data.keys():
387+
bug_data.extend(data["bugs"])
388+
389+
# for each summary, parse filename, store component
390+
# IF we find >1 bug with same testname, for now summarize as one
391+
for bug in bug_data:
392+
test_name = self.parse_test(bug["summary"])
393+
if not test_name:
394+
continue
395+
396+
c = int([x["bug_count"] for x in if_data if x["bug_id"] == bug["id"]][0])
397+
if test_name not in retVal.keys():
398+
retVal[test_name] = {
399+
"id": bug["id"],
400+
"count": 0,
401+
"product": bug["product"],
402+
"component": bug["component"],
403+
}
404+
retVal[test_name]["count"] += c
405+
406+
if bug["product"] != retVal[test_name]["product"]:
407+
print(
408+
"ERROR | %s | mismatched bugzilla product, bugzilla (%s) != repo (%s)"
409+
% (bug["id"], bug["product"], retVal[test_name]["product"])
410+
)
411+
if bug["component"] != retVal[test_name]["component"]:
412+
print(
413+
"ERROR | %s | mismatched bugzilla component, bugzilla (%s) != repo (%s)"
414+
% (bug["id"], bug["component"], retVal[test_name]["component"])
415+
)
416+
return retVal
417+
345418
def report(
346419
self,
347420
components,
@@ -356,6 +429,8 @@ def report(
356429
filter_keys,
357430
show_components,
358431
output_file,
432+
start,
433+
end,
359434
):
360435
def matches_filters(test):
361436
"""
@@ -396,6 +471,7 @@ def matches_filters(test):
396471
filter_values = []
397472
display_keys = (filter_keys or []) + ["skip-if", "fail-if", "fails-if"]
398473
display_keys = set(display_keys)
474+
ifd = self.get_intermittent_failure_data(start, end)
399475

400476
print("Finding tests...")
401477
here = os.path.abspath(os.path.dirname(__file__))
@@ -537,6 +613,12 @@ def matches_filters(test):
537613
failed_count += 1
538614
if t.get("skip-if"):
539615
skipped_count += 1
616+
617+
# add in intermittent failure data
618+
if ifd.get(relpath):
619+
if_data = ifd.get(relpath)
620+
test_info["failure_count"] = if_data["count"]
621+
540622
if show_tests:
541623
rkey = key if show_components else "all"
542624
if rkey in by_component["tests"]:
@@ -566,6 +648,8 @@ def matches_filters(test):
566648
show_annotations,
567649
filter_values,
568650
filter_keys,
651+
start,
652+
end,
569653
)
570654

571655
if show_summary:

0 commit comments

Comments
 (0)