tor-browser

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

commit 472cfdd8400641ad88f4d36487a6525fea693396
parent 9ee356d4f4b015f72f6e4568e5cc741aa74809a6
Author: iulian moraru <imoraru@mozilla.com>
Date:   Tue,  7 Oct 2025 05:28:15 +0300

Revert "Bug 1992477, Bug 1992181 - replay the logs of failures that happened in parallel, without failing the treeherder jobs, r=jmaher." for causing xpcshell failures on test_ExperimentManager_prefs.

This reverts commit 71e9bf363fd74835bf0bc7c81158f1179cb2960a.

Revert "Bug 1992181 - show 'artifact' markers for files found in the upload dir when stopping the resource monitor, r=ahal."

This reverts commit aad0350f350f4b6bdeb88bb0a09402cacfa534e0.

Revert "Bug 1992181 - Include 'process_output' structured log messages in resource usage profiles, r=ahal."

This reverts commit 0009d2b54a739c12351c91b17d078d6a9013f5a5.

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

This reverts commit d550c4e679b642116e3a3272a16df3637918ae2a.

Diffstat:
Mtesting/mozbase/mozlog/mozlog/handlers/resourcehandler.py | 10+++-------
Mtesting/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py | 166++++---------------------------------------------------------------------------
Mtesting/mozharness/mozharness/base/python.py | 6++----
Mtesting/mozharness/mozharness/mozilla/structuredlog.py | 8++------
Mtesting/xpcshell/runxpcshelltests.py | 63+++++++++------------------------------------------------------
5 files changed, 23 insertions(+), 230 deletions(-)

diff --git a/testing/mozbase/mozlog/mozlog/handlers/resourcehandler.py b/testing/mozbase/mozlog/mozlog/handlers/resourcehandler.py @@ -53,11 +53,7 @@ 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): - SystemResourceMonitor.test_status(data) - - def process_output(self, data): - SystemResourceMonitor.test_status(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")) diff --git a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py @@ -404,16 +404,13 @@ class SystemResourceMonitor: self.start_time = time.monotonic() SystemResourceMonitor.instance = self - def stop(self, upload_dir=None): + def stop(self): """Stop measuring system-wide CPU resource utilization. You should call this if and only if you have called start(). You should always pair a stop() with a start(). Currently, data is not available until you call stop(). - - Args: - upload_dir: Optional path to upload directory for artifact markers. """ if not self._process: self._stopped = True @@ -507,48 +504,17 @@ class SystemResourceMonitor: SystemResourceUsage.instance = None self.end_time = time.monotonic() - # Add event markers for files in upload directory - if upload_dir is None: - upload_dir = os.environ.get("UPLOAD_DIR") or os.environ.get( - "MOZ_UPLOAD_DIR" - ) - if upload_dir and os.path.isdir(upload_dir): - try: - for filename in os.listdir(upload_dir): - filepath = os.path.join(upload_dir, filename) - if os.path.isfile(filepath): - stat = os.stat(filepath) - timestamp = self.convert_to_monotonic_time(stat.st_mtime) - marker_data = { - "type": "Artifact", - "filename": filename, - "size": stat.st_size, - } - self.events.append((timestamp, "artifact", marker_data)) - except Exception as e: - warnings.warn(f"Failed to scan upload directory: {e}") - # Methods to record events alongside the monitored data. @staticmethod - def record_event(name, timestamp=None, data=None): + def record_event(name): """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: - if timestamp is None: - timestamp = time.monotonic() - if data: - SystemResourceMonitor.instance.events.append((timestamp, name, data)) - else: - SystemResourceMonitor.instance.events.append((timestamp, name)) + SystemResourceMonitor.instance.events.append((time.monotonic(), name)) @staticmethod def record_marker(name, start, end, data): @@ -646,8 +612,6 @@ 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: @@ -658,60 +622,6 @@ class SystemResourceMonitor: SystemResourceMonitor.instance.record_marker("test", start, end, marker_data) - @staticmethod - def test_status(data): - """Record a test_status/log/process_output event. - - Args: - data: Dictionary containing test_status/log/process_output data including: - - "action": the action type - - "test": test name (optional) - - "subtest": subtest name (optional, only for test_status/log) - - "status" or "level": status for test_status/log - - "time": timestamp in milliseconds - - "message" or "data": optional message - """ - if not SystemResourceMonitor.instance: - return - - time_sec = data["time"] / 1000 - timestamp = SystemResourceMonitor.instance.convert_to_monotonic_time(time_sec) - - action = data.get("action") - marker_data = {"type": "TestStatus"} - - if action == "process_output": - # Process output uses "output" as marker name - marker_name = "output" - message = data.get("data") - else: - # test_status and log actions - status = (data.get("status") or data.get("level")).upper() - marker_name = status - - # 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" - - subtest = data.get("subtest") - if subtest: - marker_data["subtest"] = subtest - - message = data.get("message") - - test_name = data.get("test") - if test_name: - marker_data["test"] = test_name - - if message: - marker_data["message"] = message - - SystemResourceMonitor.record_event(marker_name, timestamp, marker_data) - @contextmanager def phase(self, name): """Context manager for recording an active phase.""" @@ -1120,7 +1030,7 @@ class SystemResourceMonitor: { "name": "Test", "tooltipLabel": "{marker.data.name}", - "tableLabel": "{marker.data.status} — {marker.data.test}", + "tableLabel": "{marker.data.test} — {marker.data.status}", "chartLabel": "{marker.data.name}", "display": ["marker-chart", "marker-table"], "colorField": "color", @@ -1147,61 +1057,12 @@ 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, - }, - ], - }, - { - "name": "Artifact", - "tableLabel": "{marker.data.filename} — {marker.data.size}", - "display": ["marker-chart", "marker-table"], - "data": [ - { - "key": "filename", - "label": "Filename", - "format": "string", - }, - { - "key": "size", - "label": "Size", - "format": "bytes", - }, - ], - }, - { "name": "Mem", "tooltipLabel": "{marker.name}", "display": [], @@ -1562,27 +1423,14 @@ 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 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 + for event_time, text in self.events: + if text: add_marker( event_string_index, event_time, None, {"type": "Text", "text": text}, - OTHER_CATEGORY, + TASK_CATEGORY, 3, ) diff --git a/testing/mozharness/mozharness/base/python.py b/testing/mozharness/mozharness/base/python.py @@ -880,14 +880,12 @@ class ResourceMonitoringMixin(PerfherderResourceOptionsMixin): if not self._resource_monitor: return - # Get upload directory to pass to stop() for artifact markers - upload_dir = self.query_abs_dirs()["abs_blob_upload_dir"] - - self._resource_monitor.stop(upload_dir=upload_dir) + self._resource_monitor.stop() self._log_resource_usage() # Upload a JSON file containing the raw resource data. try: + upload_dir = self.query_abs_dirs()["abs_blob_upload_dir"] if not os.path.exists(upload_dir): os.makedirs(upload_dir) with open(os.path.join(upload_dir, "resource-usage.json"), "w") as fh: diff --git a/testing/mozharness/mozharness/mozilla/structuredlog.py b/testing/mozharness/mozharness/mozilla/structuredlog.py @@ -106,12 +106,6 @@ 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 == "process_output": - SystemResourceMonitor.test_status(data) elif action == "suite_start": SystemResourceMonitor.begin_marker("suite", data["source"]) elif action == "suite_end": @@ -120,6 +114,8 @@ 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": diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py @@ -433,7 +433,6 @@ class XPCShellTestThread(Thread): expected="TIMEOUT", message="Test timed out", ) - self.log_full_output(mark_failures_as_expected=True) else: result = "TIMEOUT" if self.timeoutAsPass: @@ -711,15 +710,12 @@ class XPCShellTestThread(Thread): line = line.decode("utf-8") return line - def log_line(self, line, time=None): + def log_line(self, line): """Log a line of output (either a parser json object or text output from the test process""" if isinstance(line, (str, bytes)): line = self.fix_text_output(line).rstrip("\r\n") - kwargs = {"command": self.command, "test": self.test_object["id"]} - if time is not None: - kwargs["time"] = time - self.log.process_output(self.proc_ident, line, **kwargs) + self.log.process_output(self.proc_ident, line, command=self.command) else: if "message" in line: line["message"] = self.fix_text_output(line["message"]) @@ -731,41 +727,14 @@ class XPCShellTestThread(Thread): line["thread"] = current_thread().name self.log.log_raw(line) - def log_full_output(self, mark_failures_as_expected=False): - """Logs any buffered output from the test process, and clears the buffer. - - Args: - mark_failures_as_expected: If True, failures will be marked as expected - (TEST-EXPECTED-FAIL instead of TEST-UNEXPECTED-FAIL). This is used - when a test will be retried. - """ + def log_full_output(self): + """Logs any buffered output from the test process, and clears the buffer.""" if not self.output_lines: return - self.log.info(f">>>>>>> Begin of full log for {self.test_object['id']}") - for timestamp, line in self.output_lines: - if isinstance(line, dict): - # Always ensure the 'test' field is present for resource usage profiles - if "test" not in line: - line["test"] = self.test_object["id"] - - if mark_failures_as_expected: - if line.get("action") == "test_status" and "expected" in line: - # Ensure the 'expected' field matches the 'status' to avoid failing the job - line["expected"] = line.get("status") - elif line.get("action") == "log" and line.get("level") == "ERROR": - # Convert ERROR log to test_status so it gets colored - # properly without causing a test failure. - line["action"] = "test_status" - line["status"] = "ERROR" - line["expected"] = "ERROR" - line["subtest"] = "" - del line["level"] - self.log_line(line) - else: - # For text lines, we need to provide the timestamp that was - # recorded when appending the message to self.output_lines - self.log_line(line, time=timestamp) - self.log.info(f"<<<<<<< End of full log for {self.test_object['id']}") + self.log.info(">>>>>>>") + for line in self.output_lines: + self.log_line(line) + self.log.info("<<<<<<<") self.output_lines = [] def report_message(self, message): @@ -773,15 +742,7 @@ class XPCShellTestThread(Thread): if self.verbose: self.log_line(message) else: - # Store timestamp only for string messages (dicts already have timestamps) - # We need valid timestamps to replay messages correctly in resource - # usage profiles. - import time - - timestamp = ( - int(time.time() * 1000) if isinstance(message, (str, bytes)) else None - ) - self.output_lines.append((timestamp, message)) + self.output_lines.append(message) def process_line(self, line_string): """Parses a single line of output, determining its significance and @@ -2415,9 +2376,6 @@ class XPCShellTests: if test.retry or test.is_alive(): # if the join call timed out, test.is_alive => True self.try_again_list.append(test.test_object) - # Print the failure output now, marking failures as expected - # since we'll retry sequentially - test.log_full_output(mark_failures_as_expected=True) continue # did the test encounter any exception? if test.exception: @@ -2457,9 +2415,6 @@ class XPCShellTests: self.test_ended(test) if (test.failCount > 0 or test.passCount <= 0) and test.retry: self.try_again_list.append(test.test_object) - # Print the failure output now, marking failures as expected - # since we'll retry sequentially - test.log_full_output(mark_failures_as_expected=True) continue self.addTestResults(test) # did the test encounter any exception?