summaryrefslogtreecommitdiffstats
path: root/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/mozbase/mozlog/mozlog/handlers/statushandler.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/testing/mozbase/mozlog/mozlog/handlers/statushandler.py b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
new file mode 100644
index 0000000000..5093c934fe
--- /dev/null
+++ b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
@@ -0,0 +1,93 @@
+# 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/.
+
+from __future__ import absolute_import
+
+from collections import (
+ defaultdict,
+ namedtuple,
+)
+
+
+RunSummary = namedtuple(
+ "RunSummary",
+ (
+ "unexpected_statuses",
+ "expected_statuses",
+ "known_intermittent_statuses",
+ "log_level_counts",
+ "action_counts",
+ ),
+)
+
+
+class StatusHandler(object):
+ """A handler used to determine an overall status for a test run according
+ to a sequence of log messages."""
+
+ def __init__(self):
+ # The count of each type of unexpected result status (includes tests and subtests)
+ self.unexpected_statuses = defaultdict(int)
+ # The count of each type of expected result status (includes tests and subtests)
+ self.expected_statuses = defaultdict(int)
+ # The count of known intermittent result statuses (includes tests and subtests)
+ self.known_intermittent_statuses = defaultdict(int)
+ # The count of actions logged
+ self.action_counts = defaultdict(int)
+ # The count of messages logged at each log level
+ self.log_level_counts = defaultdict(int)
+ # The count of "No tests run" error messages seen
+ self.no_tests_run_count = 0
+
+ def __call__(self, data):
+ action = data["action"]
+ known_intermittent = data.get("known_intermittent", [])
+ self.action_counts[action] += 1
+
+ if action == "log":
+ if data["level"] == "ERROR" and data["message"] == "No tests ran":
+ self.no_tests_run_count += 1
+ self.log_level_counts[data["level"]] += 1
+
+ if action in ("test_status", "test_end"):
+ status = data["status"]
+ # Don't count known_intermittent status as unexpected
+ if "expected" in data and status not in known_intermittent:
+ self.unexpected_statuses[status] += 1
+ else:
+ self.expected_statuses[status] += 1
+ # Count known_intermittent as expected and intermittent.
+ if status in known_intermittent:
+ self.known_intermittent_statuses[status] += 1
+
+ if action == "assertion_count":
+ if data["count"] < data["min_expected"]:
+ self.unexpected_statuses["PASS"] += 1
+ elif data["count"] > data["max_expected"]:
+ self.unexpected_statuses["FAIL"] += 1
+ elif data["count"]:
+ self.expected_statuses["FAIL"] += 1
+ else:
+ self.expected_statuses["PASS"] += 1
+
+ if action == "lsan_leak":
+ if not data.get("allowed_match"):
+ self.unexpected_statuses["FAIL"] += 1
+
+ if action == "lsan_summary":
+ if not data.get("allowed", False):
+ self.unexpected_statuses["FAIL"] += 1
+
+ if action == "mozleak_total":
+ if data["bytes"] is not None and data["bytes"] > data.get("threshold", 0):
+ self.unexpected_statuses["FAIL"] += 1
+
+ def summarize(self):
+ return RunSummary(
+ dict(self.unexpected_statuses),
+ dict(self.expected_statuses),
+ dict(self.known_intermittent_statuses),
+ dict(self.log_level_counts),
+ dict(self.action_counts),
+ )