tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit d550c4e679b642116e3a3272a16df3637918ae2a
parent 7cff206a9328fca93178cc3cccbc8896e87e23b6
Author: Florian Quèze <florian@queze.net>
Date:   Mon,  6 Oct 2025 21:51:03 +0000

Bug 1992181 - Resource usage profiles should show test_status and log messages, r=ahal.

Differential Revision: https://phabricator.services.mozilla.com/D267451

Diffstat:
Mtesting/mozbase/mozlog/mozlog/handlers/resourcehandler.py | 7++++---
Mtesting/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mtesting/mozharness/mozharness/mozilla/structuredlog.py | 6++++--
3 files changed, 119 insertions(+), 11 deletions(-)

diff --git a/testing/mozbase/mozlog/mozlog/handlers/resourcehandler.py b/testing/mozbase/mozlog/mozlog/handlers/resourcehandler.py @@ -53,7 +53,8 @@ class ResourceHandler(LogHandler): def test_end(self, data): SystemResourceMonitor.end_test(data) + def test_status(self, data): + SystemResourceMonitor.test_status(data) + def log(self, data): - level = data.get("level").upper() - time = self.resources.convert_to_monotonic_time(data.get("time") / 1000) - SystemResourceMonitor.record_marker(level, time, time, data.get("message")) + SystemResourceMonitor.test_status(data) diff --git a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py @@ -507,14 +507,24 @@ class SystemResourceMonitor: # Methods to record events alongside the monitored data. @staticmethod - def record_event(name): + def record_event(name, timestamp=None, data=None): """Record an event as occuring now. Events are actions that occur at a specific point in time. If you are looking for an action that has a duration, see the phase API below. + + Args: + name: Name of the event (string) + timestamp: Optional timestamp (monotonic time). If not provided, uses current time. + data: Optional marker payload dictionary (e.g., {"type": "TestStatus", ...}) """ if SystemResourceMonitor.instance: - SystemResourceMonitor.instance.events.append((time.monotonic(), name)) + if timestamp is None: + timestamp = time.monotonic() + if data: + SystemResourceMonitor.instance.events.append((timestamp, name, data)) + else: + SystemResourceMonitor.instance.events.append((timestamp, name)) @staticmethod def record_marker(name, start, end, data): @@ -612,6 +622,8 @@ class SystemResourceMonitor: if status in ("SKIP", "TIMEOUT"): marker_data["color"] = "yellow" + if message: + marker_data["message"] = message elif status in ("CRASH", "ERROR"): marker_data["color"] = "red" elif expected is None and not will_retry: @@ -622,6 +634,54 @@ class SystemResourceMonitor: SystemResourceMonitor.instance.record_marker("test", start, end, marker_data) + @staticmethod + def test_status(data): + """Record a test_status event with color based on status. + + Args: + data: Dictionary containing test_status data including: + - "test": test name (optional) + - "subtest": subtest name (optional) + - "status" or "level": status ("PASS", "FAIL", "ERROR", "INFO", etc.) + - "time": timestamp in milliseconds + - "message": optional message + """ + if not SystemResourceMonitor.instance: + return + + time_sec = data["time"] / 1000 + timestamp = SystemResourceMonitor.instance.convert_to_monotonic_time(time_sec) + + # Accept either "status" or "level" field + status = (data.get("status") or data.get("level")).upper() + + # Create marker data + marker_data = { + "type": "TestStatus", + } + + test_name = data.get("test") + if test_name: + marker_data["test"] = test_name + + subtest = data.get("subtest") + if subtest: + marker_data["subtest"] = subtest + + # Determine color based on status + if status == "PASS": + marker_data["color"] = "green" + elif status == "FAIL": + marker_data["color"] = "orange" + elif status == "ERROR": + marker_data["color"] = "red" + + message = data.get("message") + if message: + marker_data["message"] = message + + SystemResourceMonitor.record_event(status, timestamp, marker_data) + @contextmanager def phase(self, name): """Context manager for recording an active phase.""" @@ -1030,7 +1090,7 @@ class SystemResourceMonitor: { "name": "Test", "tooltipLabel": "{marker.data.name}", - "tableLabel": "{marker.data.test} — {marker.data.status}", + "tableLabel": "{marker.data.status} — {marker.data.test}", "chartLabel": "{marker.data.name}", "display": ["marker-chart", "marker-table"], "colorField": "color", @@ -1057,6 +1117,38 @@ class SystemResourceMonitor: "format": "string", }, { + "key": "message", + "label": "Message", + "format": "string", + }, + { + "key": "color", + "hidden": True, + }, + ], + }, + { + "name": "TestStatus", + "tableLabel": "{marker.data.message} — {marker.data.test} {marker.data.subtest}", + "display": ["marker-chart", "marker-table"], + "colorField": "color", + "data": [ + { + "key": "message", + "label": "Message", + "format": "string", + }, + { + "key": "test", + "label": "Test Name", + "format": "string", + }, + { + "key": "subtest", + "label": "Subtest", + "format": "string", + }, + { "key": "color", "hidden": True, }, @@ -1423,14 +1515,27 @@ class SystemResourceMonitor: add_marker(get_string_index(name), start, end, markerData, TASK_CATEGORY, 3) if self.events: event_string_index = get_string_index("Event") - for event_time, text in self.events: - if text: + for event in self.events: + if len(event) == 3: + # Event with payload: (time, name, data) + event_time, name, data = event + add_marker( + get_string_index(name), + event_time, + None, + data, + OTHER_CATEGORY, + 3, + ) + elif len(event) == 2: + # Simple event: (time, text) + event_time, text = event add_marker( event_string_index, event_time, None, {"type": "Text", "text": text}, - TASK_CATEGORY, + OTHER_CATEGORY, 3, ) diff --git a/testing/mozharness/mozharness/mozilla/structuredlog.py b/testing/mozharness/mozharness/mozilla/structuredlog.py @@ -106,6 +106,10 @@ class StructuredOutputParser(OutputParser): SystemResourceMonitor.begin_test(data) elif action == "test_end": SystemResourceMonitor.end_test(data) + elif action == "test_status": + SystemResourceMonitor.test_status(data) + elif action == "log": + SystemResourceMonitor.test_status(data) elif action == "suite_start": SystemResourceMonitor.begin_marker("suite", data["source"]) elif action == "suite_end": @@ -114,8 +118,6 @@ class StructuredOutputParser(OutputParser): SystemResourceMonitor.begin_marker("test", data["name"]) elif action == "group_end": SystemResourceMonitor.end_marker("test", data["name"]) - if line.startswith("TEST-UNEXPECTED-FAIL"): - SystemResourceMonitor.record_event(line) if action in ("log", "process_output"): if action == "log":