Repository navigation
test(rtps): interop cases for lease liveliness, many participants, and the CycloneDDS addressing fixes - #874
Conversation
…FastDDS and CycloneDDS Two defect classes found against CycloneDDS peers had no coverage because every ROS 2 pair in the matrix proves a single sample within a few seconds: - Liveliness past the remote participant lease. A peer whose SPDP re-announcements are not delivered to the SPDP reader has its lease expire (10 s for CycloneDDS, which addresses the repeats to readerId ENTITYID_UNKNOWN) and loses every matched endpoint - discovery looked fine, data stopped after the lease. Both legs now run ~30 s and count only samples that arrive after 16 s: `rtps_interop_sub` gains a backward-compatible `count_after_s` argument, and a small rclpy `ros2_count_subscriber.py` does the same on the ROS 2 side. Run on the FastDDS pass as a control and on the CycloneDDS pass, where it fails until the SPDP-reader delivery fix (#871) is in. - A busy domain. Twelve unrelated ROS 2 participants are up before espp starts, then the publisher espp needs joins last and must still be matched: a participant beyond the remote-participant pool is ignored silently. The harness builds the host profile (32 slots) so this passes; the embedded profile's 10 slots need the pool raised for such a domain (#870's knob), which the note and README say. A live multi-homed-peer case (the #865 class) is described in the README as follow-up work: it needs a peer address espp cannot reach, which one shared network namespace cannot provide. Workflow timeout 30 -> 40 min for the ~3 min the four new runs add. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
8 open issues
rospubis the PID of thetimeoutwrapper, sokill $rospubmay not terminate the underlying… · New Same cleanup issue as the liveliness case: the stored PIDs are fortimeout, not necessarily the… · New If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… · New If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… · New If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… · Newcount_after_sis a new user-facing argument but is not validated. Negative values effectively… · Newcount_after_sis a new user-facing argument but is not validated. Negative values effectively… · New This prints + flushes once per early sample. In the liveliness cases, this can be tens/hundreds of… · New
What changed in this PR
Extends the RTPS/DDS interop matrix to cover liveliness past participant lease expiry and high-participant-count discovery edge cases (notably those found during recent CycloneDDS addressing work).
Changes:
- Add
count_after_sgating tortps_interop_subso early samples are reported but not counted (used for liveliness/lease tests). - Introduce new interop harness cases for lease-liveliness and “many participants + late joiner”, and add a ROS 2 counting subscriber helper.
- Increase CI workflow timeout to accommodate the expanded matrix runtime.
| File | Description |
|---|---|
| pc/tests/rtps_interop_sub.cpp | Adds count_after_s argument and gating logic for counted samples. |
| components/rtps/interop/run_interop.sh | Adds new liveliness/lease and many-participants cases to the interop run matrix. |
| components/rtps/interop/ros2_count_subscriber.py | New ROS 2 helper to count messages after a time gate for liveliness validation. |
| components/rtps/interop/README.md | Documents the new interop cases and notes a not-yet-covered multi-homed scenario. |
| .github/workflows/rtps_interop.yml | Increases workflow timeout from 30 to 40 minutes. |
Review effort: Lite
…t CycloneDDS's participant-index cap Count from 22 s in, not 16: discovery, the 10 s lease and the liveliness check cadence all fit before that, so a peer dropped at its lease cannot contribute to the count. CycloneDDS allows ten participants per host per domain by default (MaxAutoParticipantIndex 9); the busy-domain case creates thirteen, so the CycloneDDS pass raises it through CYCLONEDDS_URI. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
13 open issues
Same cleanup issue as the liveliness case: the stored PIDs are fortimeout, not necessarily the…rospubis the PID of thetimeoutwrapper, sokill $rospubmay not terminate the underlying…waitcan return a non-zero status (e.g., if a PID has already exited/reaped), which can… · Newcount_after_saccepts negative values (viaatoi), which contradicts the documented semantics… · Newcount_after_saccepts negative values (viaatoi), which contradicts the documented semantics… · New Withcount_after_s > 0, early samples skip the large-payload byte-exact verification entirely due… · New This prints + flushes once per early sample. In the liveliness cases, this can be tens/hundreds of…count_after_sis a new user-facing argument but is not validated. Negative values effectively…count_after_sis a new user-facing argument but is not validated. Negative values effectively… If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… If an exception occurs (e.g., ROS 2 initialization/spin errors), the node may not be destroyed and… Invalid CLI values (e.g., non-numericSECONDS/COUNT_AFTER_S) will currently raise a Python… · New
Review effort: Lite
…er liveliness leg detects a dropped peer - cleanup `wait`s in the new cases tolerate an already-reaped PID - rtps_interop_sub: count_after_s < 0 is a usage error (exit 1); early samples are verified byte-exact and reported like counted ones, only the count differs - ros2_count_subscriber.py: argparse with typed, non-negative arguments - README: CI showed only `espp_pub->ros2_sub_liveliness` failing on CycloneDDS. A HEARTBEAT reaching a matched espp reader refreshes the sending participant's liveliness, so a CycloneDDS writer keeps its participant alive through its heartbeats even with its SPDP re-announcements lost; an espp writer only gets ACKNACKs, which do not, and the peer expires. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU



Summary
Extends the DDS interop matrix (
components/rtps/interop) with the defect classes the recent CycloneDDS work turned up. Every ROS 2 pair in the matrix proved a single sample within a few seconds, which is why none of them caught a peer that is discovered and then silently lost.ros2_pub->espp_sub_livelinessENTITYID_UNKNOWN). Only samples after 22 s count - discovery, the lease and the liveliness check cadence all fit before that, so a peer whose SPDP re-announcements were not delivered - lease expired, every matched endpoint dropped - fails. The #871 class.espp_pub->ros2_sub_livelinessros2 topic echo --oncecannot count)many_participants_late_joinerMaxAutoParticipantIndexthroughCYCLONEDDS_URI.) A participant beyond the remote-participant pool (SPDP_MAX_NUMBER_FOUND_PARTICIPANTS) is ignored silently - the #870 class. The harness builds the host profile (32 slots), so this passes; the embedded profile's 10 slots need #870's knob for such a domain, which the case note and README say.rtps_interop_subgains a backward-compatible ninth argument,count_after_s: samples that arrive earlier are reported but not counted.ros2_count_subscriber.pyis the ROS 2-side counterpart.timeouton every process, background publishers killed and waited after the subscriber exits, log tails on the way out). They add about three minutes; the workflow timeout goes from 30 to 40 minutes.Observed on CI (run 41378439624, 53 pass / 1 fail): the one failure is
cyclone: espp_pub->ros2_sub_liveliness(FAIL received=0 required=10 (not counted, before 22s: 75)): espp stops sending to the CycloneDDS peer once its 10 s lease expires, the #871 signature; it fails until #871 merges. The other CycloneDDS leg,cyclone: ros2_pub->espp_sub_liveliness, passes onmain: a HEARTBEAT that reaches a matched espp reader also refreshes the sending participant's liveliness (MessageReceiver::processHeartbeat), so a CycloneDDS writer keeps its participant alive through its heartbeats even with its SPDP re-announcements lost, while an espp writer only gets ACKNACKs back, which do not refresh it. Both FastDDS controls and bothmany_participants_late_joinercases pass. (The README records the asymmetry.)Left out: a live multi-homed peer (the #865 / #866 / #867 class, whose selection logic
locator_subnetalready checks on canned announcements). It needs a peer address espp cannot reach, which one shared network namespace cannot provide - every local address is reachable there. The README describes the design (a second Docker network, the ROS 2 side on both, espp on one, i.e. a two-containerrun.sh) as follow-up work rather than shipping a half-test.Test plan
count_after_sverified both ways on a local cross-process pair (counts only after the window opens; fails with the early samples reported when the publisher stops before it)🤖 Generated with Claude Code
https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU