SERVER-111373 parse test.xml more robustly with better diagnostics (#41734)

GitOrigin-RevId: a3cb25fc5dedbc89e817cc4a431d9a6941465a56
This commit is contained in:
Steve McClure 2025-09-24 15:56:13 -04:00 committed by MongoDB Bot
parent 3f0ab60115
commit 12c0c32f12
4 changed files with 45 additions and 4 deletions

View File

@ -217,11 +217,25 @@ sh_binary(
srcs = ["mount_drives.sh"], srcs = ["mount_drives.sh"],
) )
py_library(
name = "parse_test_xml",
srcs = [
"parse_test_xml.py",
],
deps = [
dependency(
"pyyaml",
group = "core",
),
],
)
py_binary( py_binary(
name = "gather_failed_unittests", name = "gather_failed_unittests",
srcs = ["gather_failed_unittests.py"], srcs = ["gather_failed_unittests.py"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":parse_test_xml",
"//buildscripts/util", "//buildscripts/util",
dependency( dependency(
"typer", "typer",

View File

@ -1,6 +1,5 @@
import json import json
import time import time
import xml.etree.ElementTree as ET
from glob import glob from glob import glob
from typing import List from typing import List
@ -8,6 +7,8 @@ import typer
from typing_extensions import TypedDict from typing_extensions import TypedDict
from util.expansions import get_expansion from util.expansions import get_expansion
from buildscripts.parse_test_xml import parse_test_xml
class Result(TypedDict): class Result(TypedDict):
"""A single test result""" """A single test result"""
@ -36,7 +37,7 @@ def main(testlog_dir: str):
report = Report({"results": []}) report = Report({"results": []})
for test_xml in glob(f"{testlog_dir}/**/test.xml", recursive=True): for test_xml in glob(f"{testlog_dir}/**/test.xml", recursive=True):
testsuite = ET.parse(test_xml).getroot().find("testsuite") testsuite = parse_test_xml(test_xml).find("testsuite")
testcase = testsuite.find("testcase") testcase = testsuite.find("testcase")
# Replace part of the name added by the remote test wrapper script # Replace part of the name added by the remote test wrapper script

View File

@ -1,19 +1,20 @@
import os import os
import shutil import shutil
import subprocess import subprocess
import xml.etree.ElementTree as ET
from glob import glob from glob import glob
from pathlib import Path from pathlib import Path
from typing import List from typing import List
import typer import typer
from buildscripts.parse_test_xml import parse_test_xml
def _collect_test_results(testlog_dir: str) -> List[str]: def _collect_test_results(testlog_dir: str) -> List[str]:
failed_tests = [] failed_tests = []
successful_tests = [] successful_tests = []
for test_xml in glob(f"{testlog_dir}/**/test.xml", recursive=True): for test_xml in glob(f"{testlog_dir}/**/test.xml", recursive=True):
testsuite = ET.parse(test_xml).getroot().find("testsuite") testsuite = parse_test_xml(test_xml).find("testsuite")
testcase = testsuite.find("testcase") testcase = testsuite.find("testcase")
test_file = testcase.attrib["name"] test_file = testcase.attrib["name"]

View File

@ -0,0 +1,25 @@
import os
import xml.etree.ElementTree as ET
def parse_test_xml(xml_file: str) -> ET.ElementTree:
"""Parse the test.xml file and return the ElementTree object. Throws with diagnostics if unparsable."""
# Check if file exists and has content
if not os.path.exists(xml_file):
raise Exception(f"Failed to parse {xml_file}: file does not exist")
with open(xml_file, "r", encoding="utf-8") as f:
content = f.read().strip()
if not content:
raise Exception(f"Failed to parse {xml_file}: file is empty")
try:
root = ET.fromstring(content)
return ET.ElementTree(root)
except (ET.ParseError, UnicodeDecodeError) as e:
print(f"Failed to parse {xml_file}: {e}")
print(content)
raise