Fix add_to_suite losing the testcase under junitparser>=5 - #179
Conversation
TestSuite.add_testsuite() started deepcopying the suite before appending it to the tree in junitparser 5.x. add_to_suite() created a new TestSuite, passed it to add_testsuite() immediately, then mutated the same (now orphaned) suite object by adding the testcase afterward - the tree kept the pre-testcase deepcopy, so the case silently vanished with no exception anywhere in the call chain. Reproduced against a real production status-data file: under junitparser==5.0.1, every add for a scenario that hadn't already created its suite in that run's junit.xml (i.e. every single kessel-k6 run, since each uses a unique per-run filename) produced a testcase-less <testsuite/>, which explains ReportPortal launches showing a bare item with no attached log despite the pipeline reporting success at every step. Fix: attach the testcase to the suite before it is ever passed to add_testsuite(), so newer junitparser's deepcopy carries it along. Verified against both the new-suite and existing-suite code paths on junitparser 5.0.1, and the existing test_add_to_suite unit test still passes.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughSummary by CodeRabbit
Walkthrough
ChangesJUnit suite insertion
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
core/opl/junit_cli.py (1)
111-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStop iteration early and use
for...elseto simplify suite lookup.Adding a
breakprevents redundant iterations and avoids adding the testcase multiple times if duplicate suite names exist. Furthermore, using Python'sfor...elseconstruct eliminates the need for thesuite_foundflag, streamlining the logic.♻️ Proposed refactor
- suite_found = False for suite in self: if suite.name == suite_name: logging.debug(f"Suite {suite_name} found, going to add into it") suite.add_testcase(case) - suite_found = True - if not suite_found: + break + else:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/opl/junit_cli.py` around lines 111 - 117, Refactor the suite lookup around the loop in the JUnit CLI code to use Python’s for...else construct instead of the suite_found flag. In the suite.name == suite_name branch, add the testcase once and immediately break to stop iteration; move the current not-found handling into the loop’s else block, preserving existing behavior when no matching suite exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@core/opl/junit_cli.py`:
- Around line 111-117: Refactor the suite lookup around the loop in the JUnit
CLI code to use Python’s for...else construct instead of the suite_found flag.
In the suite.name == suite_name branch, add the testcase once and immediately
break to stop iteration; move the current not-found handling into the loop’s
else block, preserving existing behavior when no matching suite exists.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 5323c281-b6b6-4c0d-b39d-956bfb681dc2
📒 Files selected for processing (1)
core/opl/junit_cli.py
Addresses review nitpick. No behavior change: break on match instead of continuing to iterate, and move the not-found handling into the loop's else clause. Re-verified against junitparser==5.0.1 (existing test_add_to_suite unit test, plus a direct two-call accumulation test against the same suite) - both new-suite and existing-suite paths still work correctly.
Both new tests fail against the pre-fix code under junitparser==5.0.1 (confirmed on a real environment with that version installed): add_to_suite() for a suite that doesn't exist yet silently drops the testcase, both in-memory and once the file is reloaded from disk (the latter matching how junit_cli.py is actually used - "add" and "upload" are separate CLI invocations reading back a previously written file). Also confirmed the existing test_add_to_suite fails the same way under junitparser==5.0.1, it just hadn't been exercised against that version.
Summary
TestSuite.add_testsuite()in junitparser 5.x deep-copies the suite before appending it to the tree (a behavior change from 4.x).add_to_suite()created a newTestSuite, passed it toadd_testsuite()immediately, then mutated the same (now orphaned) suite object by adding the testcase afterward — the tree kept the pre-testcase deep copy, so the case silently vanished with no exception anywhere in the call chain.junitparser>=5, while environments still pinned tojunitparser<5are unaffected — apip install -e git+...without an upper bound means different agents can silently drift onto different junitparser majors.add,upload, and Ibutsu import all exit 0/succeed since nothing raises).Fix
Attach the testcase to the suite before it is ever passed to
add_testsuite(), so newer junitparser's deep copy carries it along. Both the new-suite and existing-suite code paths are otherwise unchanged.Test plan
status-data-*.json/log files withjunitparser==5.0.1:addfor PASS/FAIL/ERROR all produced an empty<testsuite/>(no exception, exit code 0).<testcase>.tests/test_junit_cli.py::test_add_to_suitestill passes.junit-*.xmlwent from 111 bytes (empty) to ~15KB with a populated<system-out>, and the resulting ReportPortal launch showed a proper 3-level hierarchy (launch → suite → item) with the log attached.🤖 Generated with Claude Code