Repository navigation
CAMEL-26948: camel-aws2-kinesis - a DST fake world for the Kinesis consumer - #29993
Conversation
gnodet
left a comment
There was a problem hiding this comment.
Review: Kinesis Consumer DST Harness
APPROVE — Comprehensive, well-designed DST (deterministic simulation testing) harness for the Kinesis consumer. The FakeKinesis API model is faithful to the AWS reference, the invariant checker is sound across all investigated edge cases (epoch boundaries, LATEST skip accumulation, checkpoint resume, listing pagination), and the single-event-loop model eliminates concurrency concerns in the fake.
Two low-severity documentation suggestions:
1. FakeKinesis.java — "Not modelled" Javadoc omits AT_TIMESTAMP
The "Not modelled" paragraph at lines 63–67 lists many excluded behaviours but does not mention AT_TIMESTAMP, which is modelled (handled in the getShardIterator switch at line 279). The comment as written implies AT_TIMESTAMP is excluded along with the rest.
Suggest adding a note such as:
* (AT_TIMESTAMP is modelled in getShardIterator but not exercised by KinesisWorld)
2. KinesisWorld.java line 548 — comparator style
// current
keys.sort((a, b) -> a.toString().compareTo(b.toString()));
// more idiomatic
keys.sort(Comparator.comparing(Object::toString));Both suggestions are nits; they do not affect correctness. The core test logic is solid.
Category: test | Labels: [test] | Backport: not applicable | LTS candidate: no
davsclaus
left a comment
There was a problem hiding this comment.
Thanks @allthingssecurity, a careful world. The fake cites GetShardIterator, GetRecords and ListShards for each rule, reads take effect after their round trip, the seed picks the configuration, the drain is a finisher with a deadline, and the pom change is test scope only, as in aws2-sqs. The self-check against 043ac9e (CAMEL-25569) and 847ee9a (CAMEL-25942) is the right kind of evidence. I agree with gnodet's notes and won't repeat them.
Two things I'd like changed before merge:
- The invariant names do not match. KinesisWorld.java:103 lists "every record is routed once the faults cleared, apart from records skipped by a LATEST iterator", but
dst.checkat KinesisWorld.java:202 names it "every record is routed once the faults cleared". The guide (step 10) asks for the names used indst.check(...), and as it stands the catalog JSON shows a name that never appears in a failure report. Please use one string in both places and regenerateaws2-kinesis.jsonand its catalog copy. - Please link the LATEST excuse to CAMEL-26968. The default set excuses the records a new LATEST iterator skips after an expiry (KinesisWorld.java:76-80, FakeKinesis.java:256-265); the PR body says no JIRA was opened, but CAMEL-26968 now tracks exactly this. Please name it in the Javadoc and the comment at FakeKinesis.java:256, add it to
issuesof@DstWorld(as the SQS world does with CAMEL-25737), and update the PR body. I do think it is a real bug: records stored while a route is suspended for more than 5 minutes are lost.
Smaller, optional:
- KinesisWorld.java:226-227 excuses a second routing whenever
r.completed == 0. The guide asks that only the injected fault excuses a violation, so keying it on a recorded failure (afailedcount onRec, as the Kafka world has) would be tighter. - The Javadoc of
finisher(KinesisWorld.java:320-323) says it "stops the route", but the code only setsfinishedand leaves the stop tocontext.stop()(see the comment at :359). - The "Running the tests" section of test-dst.adoc could list
components/camel-aws/camel-aws2-kinesisin-pland the commits 043ac9e / 847ee9a, to keep the self-check repeatable.
Note: GitHub has not started any CI run on this PR yet; it needs one before merge (the author built against an older AWS SDK and KCL than main has).
Claude Code on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
1891a2a to
f017322
Compare
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔁 3 tests passed only after a retry on JDK 21 (3 retried attempts) Recovered flaky tests on JDK 21 (3)
🔬 Scalpel shadow comparison — Scalpel: 20 of 726 tested, 3 compile-only — current: 20 all testedMaveniverse Scalpel detected 20 affected modules (current approach: 20). Skip-tests mode would test 20 modules (3 direct + 0 downstream), skip tests for 3 (generated code, meta-modules) Modules Scalpel would test (20)
Modules with tests skipped (3)
All tested modules (47 modules, 9m 51s total)Total reactor time: 9m 51s
Top 20 slowest modules:
|
|
Thanks @davsclaus (and gnodet for the two notes). Pushed d106111 on top of your rebase:
Optional points:
From gnodet's review: the "Not modelled" paragraph of Tests on the new head:
Claude Code on behalf of allthingssecurity |
davsclaus
left a comment
There was a problem hiding this comment.
Thanks @allthingssecurity, d106111 covers both requested changes and the optional points:
dst.checkand@DstWorldnow use the same invariant name: "every record is routed once the faults cleared, apart from records skipped by a LATEST iterator".- CAMEL-26968 is named in the world Javadoc, in the comment in
FakeKinesis.getShardIteratorand inissuesof@DstWorld, and the JSON and test-dst.adoc copies are regenerated.
The excuse for routing a record a second time after the checkpoint now needs r.failed > 0 && r.completed == 0, and failed counts only where the injected processing failure is thrown. That is tighter, and the self-check numbers did not change (305 and 710 of 2000), so it hid nothing. The finisher Javadoc and the "Running the tests" section are fixed too, and gnodet's two nits are in. Looks good to me.
Claude Code on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
…nsumer Adds a camel-test-dst world for the camel-aws2-kinesis consumer, in the dst package of its tests: KinesisConsumerDstTest (1000 seeds), KinesisWorld and FakeKinesis. The real consumer runs against a fake Kinesis data stream bound as amazonKinesisClient, written from the API reference of GetShardIterator, GetRecords, ListShards, SplitShard and MergeShards: shard iterators that are positions valid for five minutes, the iterator types, answers with fewer records than the limit, a closed shard whose last GetRecords returns no next iterator and its child shards, paginated ListShards. The seed picks the iterator type (TRIM_HORIZON, LATEST), whether the route checkpoints with the resumable EIP and KinesisResumeStrategy (the resume cache outlives the consumer), the number of shards, maxResultsPerRequest, the poll delay, the shard monitor interval and shardClosed, and injects failed GetRecords, GetShardIterator and ListShards calls, slow answers, slow and failed processing (now and then longer than an iterator is valid), route restarts, suspensions of up to eight minutes (the cached iterators expire) and splits and merges of shards. Invariants: a consumer routes each record at most once (apart from a failed record after its checkpoint, which the resume strategy reads again); a restarted route resumes after its checkpoint; once the faults cleared every record is routed (a record stored before a consumer started a shard of its first shard list with LATEST, and without a checkpoint, is skipped by design) and the checkpoint of each open shard reaches its last record; the consumer uses the API as documented. A route stop while a poll runs is not driven: on the one stack the graceful shutdown cannot see such a poll end, so the operator stops and suspends between polls. With LATEST, when the iterator of a shard from which the consumer has not routed a record yet expires, the consumer asks for LATEST again, which skips the records stored meanwhile. The default set accepts this right after an expiry; -Ddst.kinesis.strictLatest=true counts those records as missing (44 of 2000 seeds). Self-check: on the code before CAMEL-25569 (043ac9e reverted) 305 of 2000 seeds fail (expired iterators and child shards), on the code before CAMEL-25942 (847ee9a reverted) 710 of 2000 seeds fail, all of them seeds with checkpoints; main passes 5000 of 5000 seeds. The module's pom loads the byte code agent of camel-test-dst, the test log is capped, and the catalog lists the world. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…6968 for the LATEST excuse Review of davsclaus (and gnodet): - dst.check uses the same invariant name as @DstWorld. - The excused LATEST skip after an expiry is CAMEL-26968: named in the world Javadoc, the comment in FakeKinesis.getShardIterator and the issues of @DstWorld (component JSON, catalog copy and the table of the camel-test-dst page regenerated). - A second routing after the checkpoint is excused only for a record whose processing failed (a failed count on Rec, as in the Kafka world). - The finisher Javadoc says it does not stop the route. - test-dst.adoc, Running the tests: the Kinesis module, its self-check commits and dst.kinesis.strictLatest. - FakeKinesis: AT_TIMESTAMP is modelled but not configured by the world; Comparator.comparing for the resume cache keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d106111 to
b60828b
Compare
gnodet-bot
left a comment
There was a problem hiding this comment.
Previous findings are all addressed. LGTM.
What the new commit covers:
FakeKinesis.java— "Not modelled" Javadoc now explicitly notes that AT_TIMESTAMP is modelled ingetShardIteratorbut not configured byKinesisWorld(gnodet's nit addressed)MapResumeCache.forEach—Comparator.comparing(Object::toString)replaces the hand-written lambda (gnodet's nit addressed)KinesisWorld.java— invariant name indst.checknow matches@DstWorldexactly; CAMEL-26968 named in Javadoc, comment, andissues=; second-routing excuse tightened tor.failed > 0 && r.completed == 0; finisher Javadoc corrected;test-dst.adocupdated with Kinesis module and self-check commits (all davsclaus items)
Category: test | Backport: not applicable | LTS candidate: no
This review was generated by an AI agent, Hermès on behalf of @gnodet.
Description
CAMEL-26948, part of CAMEL-26610.
A deterministic simulation test (camel-test-dst) of the camel-aws2-kinesis consumer, in the
dstpackage of its tests, in the same form as the SQS world:KinesisConsumerDstTest(1000 seeds),KinesisWorldandFakeKinesis. Test only; no main code changes.What the world models: the real consumer (
Kinesis2Consumer, its shard monitor and the resume strategy) and Camel's routing run on the virtual-time loop; only Kinesis is faked, as aKinesisClientbound asamazonKinesisClient. The fake is written from the API reference of GetShardIterator, GetRecords, ListShards, SplitShard and MergeShards and cites it: shard iterators are positions valid for five minutes (ExpiredIteratorExceptionafter that), the iterator types, answers with fewer records than the limit, a closed shard whose last GetRecords returns no next iterator and lists its child shards, and paginated ListShards.The seed picks the iterator type (TRIM_HORIZON, LATEST), whether the route checkpoints with the resumable EIP and
KinesisResumeStrategy(the resume cache outlives the consumer, so a restarted route resumes from it), the number of shards,maxResultsPerRequest, the poll delay, the shard monitor interval andshardClosed(ignore, silent), and injects failed GetRecords, GetShardIterator and ListShards calls, slow answers, slow and failed processing (now and then longer than an iterator is valid), route restarts, suspensions of up to eight minutes (the cached iterators expire) and splits and merges of shards.Invariants: a consumer routes each record at most once (apart from a record after its checkpoint whose processing failed, which the resume strategy reads again); a restarted route resumes after its checkpoint; once the faults cleared every record is routed and the checkpoint of each open shard reaches its last record; the consumer uses the API as documented. A record stored before the consumer started a shard of its first shard list with LATEST, and without a checkpoint, is skipped by design.
With LATEST, when the iterator of a shard from which the consumer has not routed a record yet expires, the consumer asks for LATEST again, which skips the records stored meanwhile. The default set accepts this only right after such an expiry;
-Ddst.kinesis.strictLatest=truecounts those records as missing, and then 44 of 2000 seeds on main fail. This is CAMEL-26968 (records stored while a route is suspended for more than five minutes are lost); the world names it in its Javadoc, in the comment ofFakeKinesis.getShardIteratorand in theissuesof@DstWorld.Limits, written in the world's Javadoc: the JIRA item "a stop while a poll runs" is not driven. On the one stack of the harness a graceful shutdown cannot see a poll below it finish, so the operator suspends the consumer first (as the shutdown strategy does) and stops or suspends the route only between polls; that item of CAMEL-26948 stays open. Not explored: the KCL consumer, the asynchronous client, a configured shardId, and AT_SEQUENCE_NUMBER, AFTER_SEQUENCE_NUMBER and AT_TIMESTAMP as the configured iterator type. Not modelled: retention, hash key ranges, enhanced fan-out, read limits beyond the injected throttling, the expiry of a NextToken, shards that close between two pages of a listing, and a stream deleted and created again.
Other changes:
camel-test-dstas a test dependency of camel-aws2-kinesis, and its byte code agent on the surefire command line, as for the other worlds.dst.kinesis.strictLatest.@DstWorldannotation lists the world in the component JSON (and its catalog copy) and in the table of the camel-test-dst page (and its catalog copy, byte-identical).Tests:
org.apache.camel.component.aws2.kinesis): 1063 run (63, plus 1000 seeds), 0 failures, 0 errors, 0 skipped. The Firehose tests of the same module were not run.What was not run locally: the ITs (they need Docker) and the full root build. I built and tested offline with the versions cached on my machine: AWS SDK 2.55.15 and the Kinesis client library 3.5.3 (main has 2.57.11 and 3.5.4), commons-lang3 3.21.0 and Guava 33.7.2 (main has 3.22.0 and 33.8.0-jre).
Target
mainbranch)Tracking
Apache Camel coding standards and style
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.(I built and tested camel-test-dst, camel-aws-common and camel-aws2-kinesis, including the formatter and import-sort plugins. The generated files touched are the component JSON with its catalog copy, and the table of the camel-test-dst page with its catalog copy, which is byte-identical to the page. I did not run the full root build.)
AI-assisted contributions
Co-authored-bytrailers) and the PR description identifies the AI tool used.This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a
Co-Authored-Bytrailer.Claude Code on behalf of allthingssecurity
🤖 Generated with Claude Code