Skip to content

feat(server): Add integration test for message deduplicatpr#2879

Open
tomighita wants to merge 3 commits intoapache:masterfrom
tomighita:tomighita/feat/message-dedup-int-test
Open

feat(server): Add integration test for message deduplicatpr#2879
tomighita wants to merge 3 commits intoapache:masterfrom
tomighita:tomighita/feat/message-dedup-int-test

Conversation

@tomighita
Copy link

@tomighita tomighita commented Mar 5, 2026

Which issue does this PR close?

Closes #2872

Rationale

As stated in the issue description, the message deduplicator was lacking integration tests. This change adds one based on existing test harness.

What changed?

The message deduplicator is only tested through unit tests, which means it lacks end to end verification. This PR adds one integration test, covering common scenarios like:

  • Add messages with new ids
  • Add messages with existing ids
  • Add messages where some of the ids exist
  • Add messages after the TTL expired and ensure we can insert duplicate ids

This change also fixed two minor bugs where sending a batch with all ids duplicated panicked and one where the deduplicator was not instantiated and None was always set.

Local Execution

  • Passed
  • Pre-commit hooks ran

AI Usage

  1. Which tools: copilot cli
  2. Scope of usage: repo onboarding, explaining concepts and architecture and generating test scaffold
  3. How did you verify the generated code works correctly: ran the test
  4. Can you explain every line of the code if asked: yes

Comment on lines +359 to +362
if batch.count() == 0 {
return Ok(());
}

Copy link
Author

Choose a reason for hiding this comment

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

[note] This was causing a bug when all the messages were with duplicate IDs because the batch was empty and we unwraped on first

Comment on lines +284 to +292
let message_deduplicator = create_message_deduplicator(&self.config.system).map(Arc::new);

let partition = LocalPartition::with_log(
loaded_log,
stats,
std::sync::Arc::new(std::sync::atomic::AtomicU64::new(current_offset)),
consumer_offsets,
consumer_group_offsets,
None,
message_deduplicator,
Copy link
Author

Choose a reason for hiding this comment

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

[note] I've added this here since the message_deduplicator was always None

@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.42%. Comparing base (6735eea) to head (1111a99).
⚠️ Report is 15 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #2879      +/-   ##
============================================
+ Coverage     68.33%   68.42%   +0.09%     
  Complexity      739      739              
============================================
  Files          1052     1052              
  Lines         84745    84749       +4     
  Branches      61281    61293      +12     
============================================
+ Hits          57910    57992      +82     
+ Misses        24463    24376      -87     
- Partials       2372     2381       +9     
Flag Coverage Δ
csharp 67.43% <ø> (-0.19%) ⬇️
go 6.27% <ø> (ø)
java 54.83% <ø> (ø)
node 92.26% <ø> (-0.03%) ⬇️
python 81.57% <ø> (ø)
rust 70.18% <100.00%> (+0.14%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
core/server/src/shard/system/messages.rs 89.25% <100.00%> (+0.07%) ⬆️
core/server/src/shard/system/partitions.rs 84.61% <100.00%> (+0.06%) ⬆️

... and 17 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tomighita tomighita changed the title Add integration test for message deduplicatpr feat(server): Add integration test for message deduplicatpr Mar 5, 2026
Copy link
Contributor

@atharvalade atharvalade left a comment

Choose a reason for hiding this comment

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

I found no critical issues in this PR

Copy link
Contributor

@atharvalade atharvalade left a comment

Choose a reason for hiding this comment

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

lgtm

Copy link
Contributor

@hubcio hubcio left a comment

Choose a reason for hiding this comment

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

overall, good direction - please just test more edge-cases, not happy paths :) also please fix typo in the PR title

Copy link
Contributor

Choose a reason for hiding this comment

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

you never test id 0 (auto-generated ids). the server replaces 0 with a uuid before the dedup check (messages_batch_mut.rs:164-166), so sending multiple messages with id 0 should all pass through. without this, you could silently break the default send path and never know. after that, please also poll the messages to check whether they have unique message id.

Comment on lines +359 to +361
if batch.count() == 0 {
return Ok(());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

i get that it's a fix, but you didn't test it. nothing in this test actually exercises it. you'd need a step that sends a batch where every message is a duplicate (e.g. resend ids 1-10 a third time without any new ids mixed in) and verify the server doesn't blow up and the message count stays the same.

Copy link
Author

Choose a reason for hiding this comment

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

Isn’t this exactly what the step does where all ids are overlapping?

Comment on lines +111 to +116
let polled = poll_all(&client, MESSAGES_PER_BATCH * 4).await;
assert_eq!(
polled.messages.len() as u32,
total_after_step3,
"Only new IDs from the mixed batch should have been accepted"
);
Copy link
Contributor

Choose a reason for hiding this comment

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

steps 3 and 4 only check message counts but never verify payloads. step 1 does this correctly (checks for "original" prefix), but step 3 doesn't verify the 5 surviving messages are actually the new ones (ids 21-25 with "mixed" payload) andnot some other combination. same for step 4 -- should check "after-ttl" payloads. count-only assertions can pass even if the wrong messages are kept.

Comment on lines +57 to +62
let polled = poll_all(&client, MESSAGES_PER_BATCH * 2).await;
assert_eq!(
polled.messages.len() as u32,
MESSAGES_PER_BATCH,
"Duplicate messages should have been dropped"
);
Copy link
Contributor

Choose a reason for hiding this comment

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

after dedup removes messages mid-batch, offsets and indexes get rebuilt via remove_messages(). you never verify that the polled messages actually have correct, contiguous offsets. a bug in the offset recalculation would be a silent data corruption issue and this test wouldn't catch it.

Comment on lines +96 to +99
let overlap_id_start = 16;
let total_after_step3 = MESSAGES_PER_BATCH + overlap_id_start - 1;
// Ensure the `overlap_id_start` is between two batches.
assert!(overlap_id_start > MESSAGES_PER_BATCH && overlap_id_start < 2 * MESSAGES_PER_BATCH);
Copy link
Contributor

Choose a reason for hiding this comment

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

overlap_id_start = 16 is a magic number and the formula total_after_step3 = MESSAGES_PER_BATCH + overlap_id_start - 1 only works because ids happen to be contiguous from 1. consider deriving it from the actual unique id range, e.g. let new_ids_in_mixed = (overlap_id_start + MESSAGES_PER_BATCH) - (2 * MESSAGES_PER_BATCH + 1) or just computing the set difference explicitly. also build_messages uses 0-based i in the payload instead of the actual message id, which makes correlating payloads to ids harder than it needs to be.

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.

Add integration test for message deduplication

3 participants