Skip to content

CAMEL-24049: Fix flaky JMS Spring tests - queue name isolation and readiness#24660

Open
gnodet wants to merge 1 commit into
apache:mainfrom
gnodet:fix/CAMEL-24049-jms-spring-queue-isolation-readiness
Open

CAMEL-24049: Fix flaky JMS Spring tests - queue name isolation and readiness#24660
gnodet wants to merge 1 commit into
apache:mainfrom
gnodet:fix/CAMEL-24049-jms-spring-queue-isolation-readiness

Conversation

@gnodet

@gnodet gnodet commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix flaky JMS tests that use Spring XML configuration by addressing two root causes: queue name collisions between tests sharing a singleton Artemis broker, and race conditions where messages are sent before JMS consumers are fully subscribed.

Changes

  • Queue name isolation: Renamed hardcoded generic queue names (foo, bar) to class-scoped names (e.g., JmsSpringLoadBalanceFailOver.foo) in JmsSpringLoadBalanceFailOverIT.xml to prevent cross-test contamination via the shared broker
  • Route IDs for readiness: Added explicit route IDs to Spring XML routes and Java route builders so JmsTestHelper.waitForJmsConsumerRoutes() can target them
  • Readiness checks: Added JmsTestHelper.waitForJmsConsumerRoutes() calls before sending messages to ensure JMS consumers are fully subscribed to the broker
  • Timed assertions: Replaced bare MockEndpoint.assertIsSatisfied() calls with MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS) for deterministic timeouts
  • Queue name fix: Corrected queue name mismatch in RouteIdTransactedIT (was using old class name RouteIdTransactedTest)

Affected tests (7 test classes, 13 test methods)

Test Class Fix Applied
JmsSpringLoadBalanceFailOverJMSIT Queue isolation + readiness check
RouteIdTransactedIT Queue name fix + readiness check
JmsRouteUsingSpringIT Route IDs + readiness + timed assertions (via JmsRouteTest)
JmsRouteUsingSpringAndJmsNameIT Route IDs + readiness + timed assertions (via JmsRouteTest)
JmsRouteUsingSpringJMSTemplateIT Route IDs + readiness + timed assertions (via JmsRouteTest)
JmsRouteUsingSpringWithAutoWireIT Route IDs + readiness + timed assertions (via JmsRouteTest)

All 13 test methods pass locally.

Claude Code on behalf of gnodet

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

…adiness checks

- Rename hardcoded queue names (foo, bar) to class-scoped names in
  JmsSpringLoadBalanceFailOverIT.xml to prevent cross-test contamination
- Add route IDs to Spring XML routes for readiness check targeting
- Add JmsTestHelper.waitForJmsConsumerRoutes() calls to ensure JMS consumers
  are fully subscribed before sending messages
- Replace bare MockEndpoint.assertIsSatisfied() with timed assertions
- Fix queue name mismatch in RouteIdTransactedIT (was using old class name)

Affected tests: JmsSpringLoadBalanceFailOverJMSIT, RouteIdTransactedIT,
JmsRouteUsingSpringIT, JmsRouteUsingSpringAndJmsNameIT,
JmsRouteUsingSpringJMSTemplateIT, JmsRouteUsingSpringWithAutoWireIT

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude Code review on behalf of @gnodet

Summary

Well-structured fix for flaky JMS Spring tests, addressing two distinct root causes:

  1. Queue name collisions -- Generic queue names (foo, bar) in JmsSpringLoadBalanceFailOverIT.xml could be contaminated by other tests sharing the same Artemis broker. Renaming to JmsSpringLoadBalanceFailOver.foo/.bar eliminates this. Similarly, RouteIdTransactedIT was still using the old class name RouteIdTransactedTest as the queue name -- a leftover from a class rename.

  2. JMS consumer readiness races -- Messages sent before JMS consumers are fully subscribed to the broker get lost. Adding JmsTestHelper.waitForJmsConsumerRoutes() (which uses Awaitility internally) ensures consumers are registered before tests send messages.

Review Notes

Testing conventions compliance (CLAUDE.md):

  • No Thread.sleep() introduced -- the PR correctly uses JmsTestHelper.waitForJmsConsumerRoutes() which delegates to Awaitility.
  • MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS) is correctly used instead of wrapping with Awaitility (per CLAUDE.md: "Do NOT wrap MockEndpoint assertions with Awaitility").
  • The readiness check in JmsRouteTest.setUpRequirements() (@BeforeEach) runs after the context is started via TransientCamelContextExtension, so the route uptime check is valid.

Queue name isolation:

  • JmsSpringLoadBalanceFailOverIT.xml: foo/bar renamed to JmsSpringLoadBalanceFailOver.foo/.bar -- prevents cross-test contamination.
  • RouteIdTransactedIT: queue name corrected from RouteIdTransactedTest to RouteIdTransactedIT to match the current class name.

Route IDs:

  • Added routeId("jmsRoute1") and routeId("jmsRoute2") in JmsRouteTest.createRouteBuilder() to support readiness checks. These IDs are per-CamelContext so no collision risk across test instances.
  • Added id="loadBalanceRoute", id="fooConsumerRoute", id="barConsumerRoute" in the Spring XML -- correctly targeted by the waitForJmsConsumerRoutes() call.

Git history check:

  • Prior fixes (commits bcccded6e33 and e38a0788492) increased the MockEndpoint timeout but did not address the queue name mismatch or consumer readiness -- this PR correctly layers the remaining fixes on top.
  • The prior fix 05aed0bd195 for JmsSpringLoadBalanceFailOverJMSIT added timeout and @Timeout(60) but did not isolate queue names or add readiness checks.

Scanner coverage: No static analysis tools (PMD, Checkstyle, semgrep) are available in this environment. Rely on CI for static analysis results.

LGTM -- no blocking issues found.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-jms

🔬 Scalpel shadow comparison — Scalpel: 1 tested, 0 compile-only — current: 12 all tested

Maveniverse Scalpel detected 1 affected modules (current approach: 12).

Modules only in current approach (11)
  • camel-activemq
  • camel-activemq6
  • camel-amqp
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-launcher-container
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin

Skip-tests mode would test 1 modules (1 direct + 0 downstream), skip tests for 0 (generated code, meta-modules)

Modules Scalpel would test (1)
  • camel-jms

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-jms: 1 test(s) disabled on GitHub Actions
All tested modules (12 modules)
  • Camel :: AMQP
  • Camel :: ActiveMQ 5.x
  • Camel :: ActiveMQ 6.x
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JMS
  • Camel :: Launcher :: Container
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@oscerd oscerd 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.

Reviewed against the project's async-testing rules with particular attention to the base-class change — clean, no change requests.

The one structural risk in this diff was adding the jmsRoute1/jmsRoute2 readiness wait to JmsRouteTest.setUpRequirements() (a @BeforeEach inherited by subclasses): if any subclass replaced the routes without those IDs, the wait would time out. Verified it's safe — JmsRouteTest is abstract and both concrete subclasses (JmsRouteWithObjectMessageTest, JmsRouteUsingSpringIT) inherit createRouteBuilder() unchanged; the Spring variant's XML (jmsRouteUsingSpring.xml) contributes only the ActiveMQ component bean, no routes, so the ID'd routes come from the same inherited builder via the @RouteFixture in AbstractJMSTest. Both subclasses therefore get the readiness wait for free, which is a nice side effect.

Other checks, all fine:

  • waitForJmsConsumerRoutes is Awaitility-based with a hard atMost cap, and treats an unknown route id as not-yet-ready — so a future misconfigured id surfaces as a clear timeout rather than an NPE. No Thread.sleep, no Awaitility-wrapping of assertIsSatisfied.
  • The resultEndpoint.assertIsSatisfied()MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS) migrations follow the prescribed timed-assertion pattern.
  • The RouteIdTransactedTestRouteIdTransactedIT queue rename is consistent across all three occurrences (both sends and the consumer URI), and the class-scoped JmsSpringLoadBalanceFailOver.foo/.bar names remove genuine cross-test contamination on the shared Artemis broker — JmsSpringLoadBalanceFailOverIT.xml is consumed only by JmsSpringLoadBalanceFailOverJMSIT, and no assertions are weakened anywhere.
  • Repeating the readiness wait at the start of both @Order tests in RouteIdTransactedIT is right, since the Spring context persists across the ordered methods and the uptime check is cheap.

Test-only change (no docs needed), commit follows the CAMEL-XXXX: convention, and CI is green on both JDK 17 and 25 builds.

Reviewed with Claude Code (Fable 5) on behalf of oscerd. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants