Loading ansible/tests/unit/test_feature_report.py +17 −0 Changes for ansible/tests/unit/test_feature_report.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -63,3 +63,20 @@ def test_outer_wrapper_failure_cannot_leave_a_green_matrix(tmp_path, exit_code, ET.SubElement(case, "failure") ET.ElementTree(root).write(tmp_path / "wrapper-junit.xml") assert finalize_report(tmp_path, exit_code) is False @pytest.mark.parametrize("label",["platform-lab","platform-lab-helm","platform-lab-network"]) def test_gitlab_phase_names_are_unique_by_job_without_changing_outcomes(tmp_path,monkeypatch,label): evidence(tmp_path) monkeypatch.setenv("CI_JOB_NAME",label) write_report(tmp_path,{"checkpoint":"terminated"}) (tmp_path/"wrapper-junit.xml").write_text('<testsuite><testcase name="cleanup"/></testsuite>') (tmp_path/"junit.xml").write_text('<testsuite><testcase name="health" time="1.5"/></testsuite>') assert finalize_report(tmp_path,0) for filename,name in [("junit.xml","health"),("wrapper-junit.xml","cleanup")]: case=ET.parse(tmp_path/filename).find(".//testcase") assert case.get("name")==label+": "+name assert case.get("classname").startswith(label+".") assert case.find("failure") is None assert finalize_report(tmp_path,0) # Metadata finalization is idempotent. assert ET.parse(tmp_path/"junit.xml").find(".//testcase").get("name")==label+": health" ci/feature_report.py +14 −0 Changes for ci/feature_report.py: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -112,6 +112,20 @@ def finalize_report(output, exit_code): cases = wrapper.findall(".//testcase") cleanup_passed = len(cases) == 1 and not any( case.find(tag) is not None for case in cases for tag in ("failure", "error", "skipped")) # GitLab drops duplicate test identities across jobs. Keep each variant visible. label = os.environ.get("CI_JOB_NAME") if label: for name in ("junit.xml", "wrapper-junit.xml"): path = output / name if not path.is_file(): continue document = ET.parse(path) for case in document.findall(".//testcase"): if not case.get("name", "").startswith(label + ": "): case.set("name", label + ": " + case.get("name", "")) if not case.get("classname", "").startswith(label + "."): case.set("classname", label + "." + case.get("classname", "PlatformE2E")) document.write(path, encoding="utf-8", xml_declaration=True) matrix.update(wrapper_verified=True, wrapper_exit_code=exit_code, wrapper_cleanup_passed=cleanup_passed, candidate_run_passed=exit_code == 0 and cleanup_passed and matrix["lab_transaction_passed"]) save_report(output, matrix) Loading ci/lab/README.md +5 −0 Changes for ci/lab/README.md: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -92,6 +92,11 @@ listed phase. Each invocation creates and removes its own lab. Keep the default health checkpoint unchanged; refresh and review candidate pins before qualification of a later release image. Phase and cleanup JUnit cases carry the job name, keeping container, Helm and network outcomes distinct in GitLab's Tests tab. Their labels preserve failure, skip and timing data. Raw pytest case identities remain unchanged for reruns; phase-report counts and actual application-case counts are separate. On the release branch/MR and integration pushes, the small `release-feature-report` job consumes the actual container, Helm and network artifacts after execution, including failed runs. Separate report directories Loading Loading
ansible/tests/unit/test_feature_report.py +17 −0 Changes for ansible/tests/unit/test_feature_report.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -63,3 +63,20 @@ def test_outer_wrapper_failure_cannot_leave_a_green_matrix(tmp_path, exit_code, ET.SubElement(case, "failure") ET.ElementTree(root).write(tmp_path / "wrapper-junit.xml") assert finalize_report(tmp_path, exit_code) is False @pytest.mark.parametrize("label",["platform-lab","platform-lab-helm","platform-lab-network"]) def test_gitlab_phase_names_are_unique_by_job_without_changing_outcomes(tmp_path,monkeypatch,label): evidence(tmp_path) monkeypatch.setenv("CI_JOB_NAME",label) write_report(tmp_path,{"checkpoint":"terminated"}) (tmp_path/"wrapper-junit.xml").write_text('<testsuite><testcase name="cleanup"/></testsuite>') (tmp_path/"junit.xml").write_text('<testsuite><testcase name="health" time="1.5"/></testsuite>') assert finalize_report(tmp_path,0) for filename,name in [("junit.xml","health"),("wrapper-junit.xml","cleanup")]: case=ET.parse(tmp_path/filename).find(".//testcase") assert case.get("name")==label+": "+name assert case.get("classname").startswith(label+".") assert case.find("failure") is None assert finalize_report(tmp_path,0) # Metadata finalization is idempotent. assert ET.parse(tmp_path/"junit.xml").find(".//testcase").get("name")==label+": health"
ci/feature_report.py +14 −0 Changes for ci/feature_report.py: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -112,6 +112,20 @@ def finalize_report(output, exit_code): cases = wrapper.findall(".//testcase") cleanup_passed = len(cases) == 1 and not any( case.find(tag) is not None for case in cases for tag in ("failure", "error", "skipped")) # GitLab drops duplicate test identities across jobs. Keep each variant visible. label = os.environ.get("CI_JOB_NAME") if label: for name in ("junit.xml", "wrapper-junit.xml"): path = output / name if not path.is_file(): continue document = ET.parse(path) for case in document.findall(".//testcase"): if not case.get("name", "").startswith(label + ": "): case.set("name", label + ": " + case.get("name", "")) if not case.get("classname", "").startswith(label + "."): case.set("classname", label + "." + case.get("classname", "PlatformE2E")) document.write(path, encoding="utf-8", xml_declaration=True) matrix.update(wrapper_verified=True, wrapper_exit_code=exit_code, wrapper_cleanup_passed=cleanup_passed, candidate_run_passed=exit_code == 0 and cleanup_passed and matrix["lab_transaction_passed"]) save_report(output, matrix) Loading
ci/lab/README.md +5 −0 Changes for ci/lab/README.md: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -92,6 +92,11 @@ listed phase. Each invocation creates and removes its own lab. Keep the default health checkpoint unchanged; refresh and review candidate pins before qualification of a later release image. Phase and cleanup JUnit cases carry the job name, keeping container, Helm and network outcomes distinct in GitLab's Tests tab. Their labels preserve failure, skip and timing data. Raw pytest case identities remain unchanged for reruns; phase-report counts and actual application-case counts are separate. On the release branch/MR and integration pushes, the small `release-feature-report` job consumes the actual container, Helm and network artifacts after execution, including failed runs. Separate report directories Loading