CAMEL-19545: Replace sleep-based synchronization in camel-stream tests - #24304
Conversation
Use flushes and Awaitility-driven waiting in the automated stream tests, and replace the disabled manual test's fixed sleep with a timed latch wait. This removes flaky timing assumptions from the camel-stream test suite. Signed-off-by: Ravi <13908473+rkdfx@users.noreply.github.com>
|
I'm running the mvn clean install -DskipTests locally but it's failing, it's unrelated to my changes. I'll try to clean and test again - |
gnodet
left a comment
There was a problem hiding this comment.
The goal of removing Thread.sleep() from these tests is sound, but the execution needs work — only one of the four changes actually replaces sleep with proper event-based synchronization. The others just delete sleeps and add fos.flush(), which trades one kind of fragility for another.
ScanStreamFileManualTest — drop this change
// Before:
Thread.sleep(60000);
// After:
new CountDownLatch(1).await(60, TimeUnit.SECONDS);This test is @Disabled("For manual testing") — the 60-second pause is intentional so a human can interact with the file while the route runs. A CountDownLatch(1) that is never counted down is just Thread.sleep with extra steps: less readable, and not Awaitility. This file should be left unchanged.
ScanStreamFileTest.testScanRefreshedFile() — good ✅
await().atMost(10, TimeUnit.SECONDS).until(() -> mock.getReceivedCounter() >= 2);This is exactly the right pattern — event-based, deterministic, no flaky timing assumption. This is the model the other tests should follow.
ScanStreamFileTest.testScanFile() / testScanFileAlreadyWritten() — incomplete
These simply remove the sleeps and add fos.flush(). They now rely entirely on MockEndpoint.assertIsSatisfied() having an implicit 10-second internal latch timeout (MockEndpoint.waitForCompleteLatch defaults to 10s when resultWaitTime is 0). That works in practice, but it's implicit and not obvious to any reader of the test.
fos.flush() pushes bytes from Java's buffer to the OS — it does not guarantee the consumer's BufferedReader.readLine() sees the data on the very next poll cycle. The consumer polls every 200ms (scanStreamDelay=200). Without any explicit wait, these tests silently depend on the mock's internal timeout to absorb that latency. This should use Awaitility like testScanRefreshedFile does, for consistency and clarity.
ScanStreamFileWithFilterTest — correct in effect, but inconsistent
Removing the interleaved sleeps between writes is fine here (the filter only matches "Hello Boy", so processing order doesn't matter, and moving fos.close() before assertIsSatisfied is actually better). But again, no Awaitility — it silently relies on MockEndpoint's 10s timeout.
Suggestions
- Drop the
ScanStreamFileManualTestchange — the sleep is intentional in a disabled manual test. - Keep the
testScanRefreshedFile()Awaitility change as-is. - Add Awaitility to
testScanFile(),testScanFileAlreadyWritten(), andScanStreamFileWithFilterTestinstead of just removing sleeps — e.g.await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> MockEndpoint.assertIsSatisfied(context)). This makes the synchronization explicit and consistent with the good pattern already in the PR.
Signed-off-by: Ravi <13908473+rkdfx@users.noreply.github.com>
gnodet
left a comment
There was a problem hiding this comment.
Thanks for addressing the previous feedback — dropping the ManualTest change and adding Awaitility everywhere is a step in the right direction.
However, MockEndpoint already has a built-in timed assertion that does exactly what the Awaitility wrapping does here:
// Current (Awaitility polling around a latch-based wait — redundant):
await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> MockEndpoint.assertIsSatisfied(context));
// Better (native, latch-based, no external dependency needed):
MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS);MockEndpoint.assertIsSatisfied(CamelContext, long, TimeUnit) sets resultWaitTime on every mock in the context and uses the internal CountDownLatch to wait — it returns as soon as expectations are met or fails after the timeout. Wrapping it with Awaitility is redundant: you're polling a mechanism that already waits internally.
This applies to testScanFile(), testScanFileAlreadyWritten() in ScanStreamFileTest, and testScanFile() in ScanStreamFileWithFilterTest.
The one place where Awaitility remains the right choice is the mid-test synchronization in testScanRefreshedFile():
await().atMost(10, TimeUnit.SECONDS).until(() -> mock.getReceivedCounter() >= 2);MockEndpoint doesn't have a "wait until N received without asserting" API, so Awaitility is genuinely useful there. That part is good as-is.
Also, testScanRefreshedFile() still uses plain MockEndpoint.assertIsSatisfied(context) for its final assertion (no timeout override) — it should use the timed variant too, for consistency with the other tests.
Signed-off-by: Ravi <13908473+rkdfx@users.noreply.github.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 1 tested, 0 compile-only — current: 9 all testedMaveniverse Scalpel detected 1 affected modules (current approach: 9). Modules only in current approach (8)
Skip-tests mode would test 1 modules (1 direct + 0 downstream), skip tests for 0 (generated code, meta-modules) Modules Scalpel would test (1)
All tested modules (9 modules)
|
oscerd
left a comment
There was a problem hiding this comment.
Thanks Ravi. Re-reviewing after the latest commit: both rounds of @gnodet's requested changes now look addressed, so the outstanding changes-requested appears stale.
- All
Thread.sleep(...)calls are removed from the two modified test files, replaced either with the native timed assertionMockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS)or, for the mid-test pre-rollover wait,await().atMost(10, TimeUnit.SECONDS).until(() -> mock.getReceivedCounter() >= 2)— both with explicitatMosttimeouts and no busy-wait. ScanStreamFileManualTestis correctly left untouched (its 60s sleep is an intentional@Disabledmanual test).- CI is green.
LGTM from me. @gnodet — would you mind re-reviewing, since your comments are addressed? A squash of the "addressed comments" commits at merge would be a nice-to-have.
Reviewed with Claude Code on behalf of Andrea Cosentino. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
Used our gnodet review's submitted_at (2026-07-07T12:17:54Z) instead of the PR's updatedAt (2026-07-08T10:15:37Z) which reflected oscerd's later approval. The author pushed a fix 3 hours after our review that we missed. Root cause: when seeding prior-session PRs, we used updatedAt instead of our review's submitted_at, masking post-review author commits. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gnodet
left a comment
There was a problem hiding this comment.
Re-review after fix commit 4a57804: all prior findings have been fully addressed.
Prior findings status:
- ✅
ScanStreamFileManualTestchanges correctly dropped (the 60s sleep is intentional in a@Disabledmanual test) - ✅
testScanFile/testScanFileAlreadyWritten/ScanStreamFileWithFilterTest.testScanFile: now use nativeMockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS)instead of redundant Awaitility wrapper - ✅
testScanRefreshedFile: final assertion updated to timed variant; mid-test Awaitility sync point correctly retained (no native alternative for that pattern) - ✅ Awaitility import properly cleaned up in
ScanStreamFileWithFilterTest(no longer needed) and retained inScanStreamFileTest(still used)
CI is green. Clean implementation.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Description
Use flushes and Awaitility-driven waiting in the automated stream tests, and replace the disabled manual test's fixed sleep with a timed latch wait. This removes flaky timing assumptions from the camel-stream test suite.
Target
mainbranch)Tracking
Apache Camel coding standards and style
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.AI-assisted contributions
Co-authored-bytrailers) and the PR description identifies the AI tool used.