This is an automated email from the ASF dual-hosted git repository.
lianetm pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 7c010c75839 KAFKA-20733: Fix
fetchResponseWithUnexpectedPartitionIsIgnored passing for wrong reason with
CONSUMER protocol (#22651)
7c010c75839 is described below
commit 7c010c75839dd71ff1d7b1f1f2c7434cbee47e91
Author: Park Jiwon <[email protected]>
AuthorDate: Tue Jun 30 01:16:14 2026 +0900
KAFKA-20733: Fix fetchResponseWithUnexpectedPartitionIsIgnored passing for
wrong reason with CONSUMER protocol (#22651)
## Summary
`KafkaConsumerTest.fetchResponseWithUnexpectedPartitionIsIgnored` was
annotated with `@EnumSource(GroupProtocol.class)`, but the CONSUMER
protocol case passed for the wrong reason.
The CONSUMER protocol uses `FetchRequestManager` and relies on
`ConsumerGroupHeartbeat` for rebalancing. Since the test does not set up
heartbeat-based rebalancing, partition assignment never completes and 0
records are returned — not because `FetchSessionHandler` correctly
rejected the response.
## Analysis
While writing the CONSUMER protocol test, we first attempted to use
`AsyncKafkaConsumerTest` as a reference. However, it was not suitable
because `fetchCollector` is replaced with a Mock, meaning
`FetchSessionHandler`'s actual rejection logic is never exercised.
We also found that naively adding the CONSUMER case to
`KafkaConsumerTest` does not work either. The test uses
`prepareResponse()` for the Join and Sync group requests, but these
responses were never consumed — because the CONSUMER protocol does not
go through the classic Join/Sync rebalance flow. As a result, the fetch
phase was never reached. `FetchRequestManagerTest` is the correct
location for this test, as it directly runs `FetchSessionHandler`
without mocking.
## Changes
- **`KafkaConsumerTest`**: Restrict
`fetchResponseWithUnexpectedPartitionIsIgnored` to `CLASSIC` protocol
only, where the existing setup correctly exercises
`FetchSessionHandler`'s unexpected partition rejection logic.
- **`FetchRequestManagerTest`**: Add
`testFetchResponseWithUnexpectedPartitionIsIgnored` to properly cover
the CONSUMER protocol path. The test verifies that when a
`FetchResponse` contains a partition not included in the `FetchRequest`,
`FetchSessionHandler` rejects the entire response and no records are
returned to the consumer.
- +**`KafkaConsumerTest`**: Rename
`fetchResponseWithUnexpectedPartitionIsIgnored`to
`testFetchResponseWithUnexpectedPartitionIsIgnored` to align with the
existing test naming convention in the class.
Reviewers: Lianet Magrans <[email protected]>
---
I'm happy to make any adjustments based on your feedback. Thank you to
the maintainers for taking the time to review this contribution!
---
.../kafka/clients/consumer/KafkaConsumerTest.java | 6 +++--
.../internals/FetchRequestManagerTest.java | 31 ++++++++++++++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git
a/clients/src/test/java/org/apache/kafka/clients/consumer/KafkaConsumerTest.java
b/clients/src/test/java/org/apache/kafka/clients/consumer/KafkaConsumerTest.java
index 2104ff42b7b..b0358baebfd 100644
---
a/clients/src/test/java/org/apache/kafka/clients/consumer/KafkaConsumerTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/consumer/KafkaConsumerTest.java
@@ -1659,9 +1659,11 @@ public class KafkaConsumerTest {
}
}
+ // NOTE: the CONSUMER protocol path is tested separately in
+ //
FetchRequestManagerTest.testFetchResponseWithUnexpectedPartitionIsIgnored.
@ParameterizedTest
- @EnumSource(GroupProtocol.class)
- public void fetchResponseWithUnexpectedPartitionIsIgnored(GroupProtocol
groupProtocol) {
+ @EnumSource(value = GroupProtocol.class, names = "CLASSIC")
+ public void
testFetchResponseWithUnexpectedPartitionIsIgnored(GroupProtocol groupProtocol) {
ConsumerMetadata metadata = createMetadata(subscription);
MockClient client = new MockClient(time, metadata);
diff --git
a/clients/src/test/java/org/apache/kafka/clients/consumer/internals/FetchRequestManagerTest.java
b/clients/src/test/java/org/apache/kafka/clients/consumer/internals/FetchRequestManagerTest.java
index 8182eee6f16..4a5dafaaeb8 100644
---
a/clients/src/test/java/org/apache/kafka/clients/consumer/internals/FetchRequestManagerTest.java
+++
b/clients/src/test/java/org/apache/kafka/clients/consumer/internals/FetchRequestManagerTest.java
@@ -1760,6 +1760,37 @@ public class FetchRequestManagerTest {
fetchedRecords.values().forEach(allFetchedRecords::addAll);
}
+ @Test
+ public void testFetchResponseWithUnexpectedPartitionIsIgnored() {
+ buildFetcher();
+
+ // Only tp0 is assigned and seeked; tp1 is not part of this fetch
session.
+ // When the response includes an unexpected partition (tp1),
FetchSessionHandler
+ // rejects the entire response, so tp0 records are also not returned.
+ assignFromUser(singleton(tp0));
+ subscriptions.seek(tp0, 0);
+
+ assertEquals(1, sendFetches());
+
+ Map<TopicIdPartition, FetchResponseData.PartitionData> partitions =
new LinkedHashMap<>();
+ partitions.put(tidp0, new FetchResponseData.PartitionData()
+ .setPartitionIndex(tp0.partition())
+ .setHighWatermark(100L)
+ .setLogStartOffset(0)
+ .setRecords(records));
+ partitions.put(tidp1, new FetchResponseData.PartitionData()
+ .setPartitionIndex(tp1.partition())
+ .setHighWatermark(100L)
+ .setLogStartOffset(0)
+ .setRecords(records));
+ client.prepareResponse(FetchResponse.of(Errors.NONE, 0,
INVALID_SESSION_ID, new LinkedHashMap<>(partitions), List.of()));
+ networkClientDelegate.poll(time.timer(0));
+
+ assertEquals(0, client.inFlightRequestCount());
+ assertFalse(fetcher.hasCompletedFetches());
+ assertTrue(fetchRecords().isEmpty());
+ }
+
@Test
public void testCompletedFetchRemoval() {
// Ensure the removal of completed fetches that cause an Exception if
and only if they contain empty records.