# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import json import logging from functools import partial
from taskgraph.util.taskcluster import get_artifact, get_task_definition, list_artifacts
from .registry import register_callback_action from .retrigger import retrigger_action from .util import add_args_to_command, create_tasks, fetch_graph_and_labels
logger = logging.getLogger(__name__)
def get_failures(task_id, task_definition): """Returns a dict containing properties containing a list of
directories containing test failures and a separate list of
individual test failures from the errorsummary.log artifact for
the task.
Find test path to pass to the task in
MOZHARNESS_TEST_PATHS. If no appropriate test path can be
determined, nothing is returned. """
def fix_wpt_name(test): # TODO: find other cases to handle if".any."in test:
test = "%s.any.js" % test.split(".any.")[0] if".window.html"in test:
test = test.replace(".window.html", ".window.js")
if test.startswith("/_mozilla"):
test = "testing/web-platform/mozilla/tests" + test[len("_mozilla") :] else:
test = "testing/web-platform/tests/" + test.strip("/") # some wpt tests have params, those are not supported
test = test.split("?")[0]
return test
# collect dirs that don't have a specific manifest
dirs = []
tests = []
artifacts = list_artifacts(task_id) for artifact in artifacts: if"name"notin artifact ornot artifact["name"].endswith("errorsummary.log"): continue
# We handle the stream as raw bytes because it may contain invalid # UTF-8 characters in portions other than those containing the error # messages we're looking for. for line in stream.read().split(b"\n"): ifnot line.strip(): continue
l = json.loads(line) if"group_results"in l.keys() and l["status"] != "OK":
dirs.append(l["group_results"].group())
elif"test"in l.keys(): ifnot l["test"]:
print("Warning: no testname in errorsummary line: %s" % l) continue
# tests with url params (wpt), will get confused here if"?"notin test_path:
test_path = test_path.split(":")[-1]
# edge case where a crash on shutdown has a "test" name == group name if (
test_path.endswith(".toml") or test_path.endswith(".ini") or test_path.endswith(".list")
): # TODO: consider running just the manifest continue
# edge cases with missing test names if (
test_path isNone or test_path == "None" or"SimpleTest"in test_path
): continue
if"signature"in l.keys(): # dealing with a crash
found_path = True if"web-platform"in task_definition["extra"]["suite"]:
test_path = fix_wpt_name(test_path) else: if"status"notin l and"expected"notin l: continue
if l["status"] != l["expected"]: if l["status"] notin l.get("known_intermittent", []):
found_path = True if"web-platform"in task_definition["extra"]["suite"]:
test_path = fix_wpt_name(test_path)
if found_path and test_path:
fpath = test_path.replace("\\", "/")
tval = {"path": fpath, "group": l["group"]} # only store one failure per test ifnot [t for t in tests if t["path"] == fpath]:
tests.append(tval)
# only run the failing test not both test + dir if l["group"] in dirs:
dirs.remove(l["group"])
# TODO: 10 is too much; how to get only NEW failures? if len(tests) > 10: break
dirs = [{"path": "", "group": d} for d in list(set(dirs))] return {"dirs": dirs, "tests": tests}
if failure_group == "dirs": # execute 3 total loops
repeat_args = ["--repeat=2"] if repeatable_task else [] elif failure_group == "tests": # execute 5 total loops
repeat_args = ["--repeat=4"] if repeatable_task else []
return repeat_args
def confirm_modifier(task, input): if task.label != input["label"]: return task
logger.debug(f"Modifying paths for {task.label}")
# If the original task has defined test paths
suite = input.get("suite")
test_path = input.get("test_path")
test_group = input.get("test_group") if test_path or test_group:
repeat_args = input.get("repeat_args")
if repeat_args:
task.task["payload"]["command"] = add_args_to_command(
task.task["payload"]["command"], extra_args=repeat_args
)
# TODO: do we need this attribute?
task.attributes["test_path"] = test_path
@register_callback_action(
name="confirm-failures",
title="Confirm failures in job",
symbol="cf",
description="Re-run Tests for original manifest, directories or tests for failing tests.",
order=150,
context=[{"kind": "test"}],
schema={ "type": "object", "properties": { "label": {"type": "string", "description": "A task label"}, "suite": {"type": "string", "description": "Test suite"}, "test_path": {"type": "string", "description": "A full path to test"}, "test_group": { "type": "string", "description": "A full path to group name",
}, "repeat_args": { "type": "string", "description": "args to pass to test harness",
},
}, "additionalProperties": False,
},
) def confirm_failures(parameters, graph_config, input, task_group_id, task_id):
task_definition = get_task_definition(task_id)
decision_task_id, full_task_graph, label_to_taskid, _ = fetch_graph_and_labels(
parameters, graph_config
)
# create -cf label; ideally make this a common function
task_definition["metadata"]["name"].split("-")
cfname = "%s-cf" % task_definition["metadata"]["name"]
if cfname notin full_task_graph.tasks: raise Exception(f"{cfname} was not found in the task-graph")
to_run = [cfname]
suite = task_definition["extra"]["suite"] if"-coverage"in suite:
suite = suite[: suite.index("-coverage")] if"-qr"in suite:
suite = suite[: suite.index("-qr")]
failures = get_failures(task_id, task_definition)
if failures["dirs"] == [] and failures["tests"] == []:
logger.info("need to retrigger task as no specific test failures found")
retrigger_action(parameters, graph_config, input, decision_task_id, task_id) return
# for each unique failure, create a new confirm failure job for failure_group in failures: for failure_path in failures[failure_group]:
repeat_args = get_repeat_args(task_definition, failure_group)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.