Skip to content

test(rtps): interop cases for lease liveliness, many participants, and the CycloneDDS addressing fixes - #874

Merged
finger563 merged 4 commits into
mainfrom
test/rtps-interop-dds-cases
Nov 2, 2026
Merged

finger563 merged 4 commits into
mainfrom
test/rtps-interop-dds-cases

Conversation

@finger563

@finger563 finger563 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

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.

case guards FastDDS CycloneDDS
ros2_pub->espp_sub_liveliness samples keep arriving 22 s in, past a remote participant lease (CycloneDDS: 10 s, re-announced with readerId ENTITYID_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. control yes
espp_pub->ros2_sub_liveliness the reverse leg, counted on the ROS 2 side by a small rclpy subscriber (ros2 topic echo --once cannot count) control yes
many_participants_late_joiner twelve unrelated ROS 2 participants are on the domain before espp starts, then the publisher espp needs joins last and must still be matched. (CycloneDDS allows ten participants per host per domain by default; the CycloneDDS pass raises MaxAutoParticipantIndex through CYCLONEDDS_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. yes yes
  • rtps_interop_sub gains a backward-compatible ninth argument, count_after_s: samples that arrive earlier are reported but not counted. ros2_count_subscriber.py is the ROS 2-side counterpart.
  • The cases are shell functions called from both the FastDDS and the CycloneDDS pass (same convention as the rest: timeout on 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 on main: 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 both many_participants_late_joiner cases pass. (The README records the asymmetry.)

Left out: a live multi-homed peer (the #865 / #866 / #867 class, whose selection logic locator_subnet already 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-container run.sh) as follow-up work rather than shipping a half-test.

Test plan

  • Host build of the interop binaries; count_after_s verified 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)
  • CI interop matrix, run 41378439624: 53 pass / 1 fail, the one expected failure above
  • CI interop matrix after the review follow-ups (bf0b16e)

🤖 Generated with Claude Code

https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU

…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
Copilot AI balanced review requested due to automatic review settings November 2, 2026 01:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
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_s gating to rtps_interop_sub so 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

Comment thread components/rtps/interop/run_interop.sh Resolved
Comment thread components/rtps/interop/run_interop.sh Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
…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
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

✅Static analysis result - no issues found! ✅

@finger563
finger563 requested a balanced review from Copilot November 2, 2026 04:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Review effort: Lite

Comment thread components/rtps/interop/run_interop.sh Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
Comment thread pc/tests/rtps_interop_sub.cpp Resolved
finger563 and others added 2 commits November 2, 2026 07:00
…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
@finger563
finger563 merged commit 4c0f71f into main Nov 2, 2026
23 checks passed
@finger563
finger563 deleted the test/rtps-interop-dds-cases branch November 2, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants