Skip to content

CAMEL-23902: Fix flaky UndertowWsConsumerRouteTest#24421

Draft
gnodet wants to merge 1 commit into
apache:mainfrom
gnodet:camel-23902-fix-flaky-test-undertowwsconsumerrout
Draft

CAMEL-23902: Fix flaky UndertowWsConsumerRouteTest#24421
gnodet wants to merge 1 commit into
apache:mainfrom
gnodet:camel-23902-fix-flaky-test-undertowwsconsumerrout

Conversation

@gnodet

@gnodet gnodet commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Claude Code on behalf of Guillaume Nodet

Fix flaky WebSocket tests in UndertowWsConsumerRouteTest that fail intermittently on JDK 17.

Root cause: JDK's WebSocket.sendText() returns a CompletableFuture that must complete before the next send. When two messages are sent in rapid succession on the same connection, the second send fails silently with IllegalStateException because WebsocketTestClient.sendTextMessage() ignores the returned future.

Fix:

  • Replace CountDownLatch-based assertTrue(await(10)) + subsequent assertions with Awaitility polling (untilAsserted) in echo(), echoMulti(), sendToAll(), and connectionKeyList()
  • For tests sending multiple messages on the same connection (echo, connectionKeyList), wait for the echo of the first message before sending the next, avoiding the JDK WebSocket pending-send conflict
  • Add awaitility test dependency to camel-undertow

Test plan

  • UndertowWsConsumerRouteTest passes (all 10 tests, 0 flakes)
  • Ran echo() test 3x consecutively — all green
  • Code formatting verified (mvn formatter:format impsort:sort — no changes needed)

🤖 Generated with Claude Code

@gnodet gnodet requested review from davsclaus and oscerd July 4, 2026 17:04
@github-actions

github-actions Bot commented Jul 4, 2026

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.

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-undertow

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 37 tested, 29 compile-only — current: 37 all tested

Maveniverse Scalpel detected 66 affected modules (current approach: 37).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

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

Modules Scalpel would test (37)
  • camel-a2a
  • camel-consul
  • camel-cxf-rest
  • camel-cxf-soap
  • camel-cxf-spring-rest
  • camel-cxf-spring-soap
  • camel-cxf-spring-transport
  • camel-cxf-transport
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jsonpath
  • camel-knative-http
  • camel-launcher-container
  • camel-lra
  • camel-micrometer-observability
  • camel-micrometer-prometheus
  • camel-oauth
  • camel-observability-services
  • camel-openapi-validator
  • camel-opentelemetry
  • camel-opentelemetry2
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-rest-openapi
  • camel-slack
  • camel-soap
  • camel-telemetry
  • camel-telemetry-dev
  • camel-undertow
  • camel-undertow-spring-security
  • camel-vertx-http
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

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

Build reactor — dependencies compiled but only changed modules were tested (66 modules)
  • Camel :: AI :: A2A
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: CXF :: REST
  • Camel :: CXF :: REST :: Spring
  • Camel :: CXF :: SOAP
  • Camel :: CXF :: SOAP :: Spring
  • Camel :: CXF :: Transport
  • Camel :: CXF :: Transport :: Spring
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Common Telemetry
  • Camel :: Component DSL
  • Camel :: Consul
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JSon Path
  • Camel :: Kamelet Main
  • Camel :: Knative HTTP
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Long-Running-Action
  • Camel :: Micrometer :: Observability 2
  • Camel :: Micrometer :: Prometheus
  • Camel :: OAuth
  • Camel :: Observability Services
  • Camel :: OpenAPI :: Validator
  • Camel :: OpenTelemetry (deprecated)
  • Camel :: Opentelemetry 2
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: REST OpenApi
  • Camel :: SOAP
  • Camel :: Slack
  • Camel :: Telemetry :: Dev
  • Camel :: Undertow
  • Camel :: Undertow Spring Security
  • Camel :: Vert.x :: HTTP
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zookeeper

⚙️ View full build and test results

The WebSocket tests in UndertowWsConsumerRouteTest fail intermittently on
JDK 17 because WebSocket.sendText() returns a CompletableFuture that must
complete before the next send. When two messages are sent in rapid
succession, the second send can fail silently with IllegalStateException.

Replace CountDownLatch-based assertTrue(await(10)) with Awaitility
polling in echo(), echoMulti(), sendToAll() and connectionKeyList().
For tests that send multiple messages on the same connection (echo,
connectionKeyList), wait for the echo of the first message before
sending the next to avoid the JDK WebSocket pending-send conflict.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@davsclaus davsclaus force-pushed the camel-23902-fix-flaky-test-undertowwsconsumerrout branch from 1b2b35d to 1f0f1ed Compare July 5, 2026 06:39

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.

Pull request overview

This PR aims to stabilize UndertowWsConsumerRouteTest on JDK 17 by avoiding overlapping WebSocket.sendText() operations and by switching some latch-based waits to Awaitility-based polling.

Changes:

  • Add Awaitility to camel-undertow test dependencies.
  • In echo() and connectionKeyList(), wait for the first message delivery before sending a second message on the same WebSocket connection.
  • Replace several CountDownLatch-based await() usages with await().untilAsserted(...) assertions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
components/camel-undertow/src/test/java/org/apache/camel/component/undertow/ws/UndertowWsConsumerRouteTest.java Updates WebSocket tests to sequence sends and to use Awaitility for polling assertions.
components/camel-undertow/pom.xml Adds Awaitility as a test-scoped dependency for the updated tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 171 to +175
wsclient1.sendTextMessage("Test1");
wsclient1.sendTextMessage("Test2");

assertTrue(wsclient1.await(10));
// Wait for the first echo before sending the next message to avoid
// IllegalStateException from JDK WebSocket when a send is still pending
await().atMost(10, TimeUnit.SECONDS)
.untilAsserted(() -> assertTrue(wsclient1.getReceived(String.class).contains("Test1")));
Comment on lines +195 to +199
await().atMost(10, TimeUnit.SECONDS)
.untilAsserted(() -> {
assertEquals(List.of("Gambas"), wsclient1.getReceived(String.class));
assertEquals(List.of("Calamares"), wsclient2.getReceived(String.class));
});
Comment on lines +216 to +220
.untilAsserted(() -> {
List<String> received1 = wsclient1.getReceived(String.class);
assertEquals(2, received1.size());
assertTrue(received1.contains("Gambas"));
assertTrue(received1.contains("Calamares"));
Comment on lines +299 to +303
await().atMost(10, TimeUnit.SECONDS)
.untilAsserted(() -> assertConnected(wsclient1));
final String connectionKey1 = assertConnected(wsclient1);
assertNotNull(connectionKey1);
wsclient2.await(10);
await().atMost(10, TimeUnit.SECONDS)
Comment on lines +317 to +321
await().atMost(10, TimeUnit.SECONDS)
.untilAsserted(() -> {
assertEquals(broadcastMsg, wsclient2.getReceived(String.class).get(0));
assertEquals(broadcastMsg, wsclient3.getReceived(String.class).get(0));
});
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.

4 participants