|
60 | 60 | import static org.junit.jupiter.api.Assertions.assertEquals; |
61 | 61 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
62 | 62 | import static org.junit.jupiter.api.Assertions.assertNull; |
| 63 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
63 | 64 |
|
64 | 65 | public class ShareCompletedFetchTest { |
65 | 66 | private static final String TOPIC_NAME = "test"; |
@@ -356,6 +357,63 @@ record = records.get(1); |
356 | 357 | assertEquals(0, records.size()); |
357 | 358 | } |
358 | 359 |
|
| 360 | + @Test |
| 361 | + public void testOverlappingAcquiredRecordsLogsErrorAndRetainsFirstOccurrence() { |
| 362 | + int startingOffset = 0; |
| 363 | + int numRecords = 20; // Records for 0-19 |
| 364 | + |
| 365 | + // Create overlapping acquired records: [0-9] and [5-14] |
| 366 | + // Offsets 5-9 will be duplicates |
| 367 | + List<ShareFetchResponseData.AcquiredRecords> acquiredRecords = new ArrayList<>(); |
| 368 | + acquiredRecords.add(new ShareFetchResponseData.AcquiredRecords() |
| 369 | + .setFirstOffset(0L) |
| 370 | + .setLastOffset(9L) |
| 371 | + .setDeliveryCount((short) 1)); |
| 372 | + acquiredRecords.add(new ShareFetchResponseData.AcquiredRecords() |
| 373 | + .setFirstOffset(5L) |
| 374 | + .setLastOffset(14L) |
| 375 | + .setDeliveryCount((short) 2)); |
| 376 | + |
| 377 | + ShareFetchResponseData.PartitionData partitionData = new ShareFetchResponseData.PartitionData() |
| 378 | + .setRecords(newRecords(startingOffset, numRecords)) |
| 379 | + .setAcquiredRecords(acquiredRecords); |
| 380 | + |
| 381 | + ShareCompletedFetch completedFetch = newShareCompletedFetch(partitionData); |
| 382 | + |
| 383 | + Deserializers<String, String> deserializers = newStringDeserializers(); |
| 384 | + |
| 385 | + // Fetch records and verify that only 15 unique records are returned (0-14) |
| 386 | + ShareInFlightBatch<String, String> batch = completedFetch.fetchRecords(deserializers, 20, true); |
| 387 | + List<ConsumerRecord<String, String>> records = batch.getInFlightRecords(); |
| 388 | + |
| 389 | + // Should get 15 unique records: 0-9 from first range (with deliveryCount=1) |
| 390 | + // and 10-14 from second range (with deliveryCount=2) |
| 391 | + assertEquals(15, records.size()); |
| 392 | + |
| 393 | + // Verify first occurrence (offset 5 should have deliveryCount=1 from first range) |
| 394 | + ConsumerRecord<String, String> record5 = records.stream() |
| 395 | + .filter(r -> r.offset() == 5L) |
| 396 | + .findFirst() |
| 397 | + .orElse(null); |
| 398 | + assertNotNull(record5); |
| 399 | + assertEquals(Optional.of((short) 1), record5.deliveryCount()); |
| 400 | + |
| 401 | + // Verify offset 10 has deliveryCount=2 from second range |
| 402 | + ConsumerRecord<String, String> record10 = records.stream() |
| 403 | + .filter(r -> r.offset() == 10L) |
| 404 | + .findFirst() |
| 405 | + .orElse(null); |
| 406 | + assertNotNull(record10); |
| 407 | + assertEquals(Optional.of((short) 2), record10.deliveryCount()); |
| 408 | + |
| 409 | + // Verify all offsets are unique |
| 410 | + Set<Long> offsetSet = new HashSet<>(); |
| 411 | + for (ConsumerRecord<String, String> record : records) { |
| 412 | + assertTrue(offsetSet.add(record.offset()), |
| 413 | + "Duplicate offset found in results: " + record.offset()); |
| 414 | + } |
| 415 | + } |
| 416 | + |
359 | 417 | private ShareCompletedFetch newShareCompletedFetch(ShareFetchResponseData.PartitionData partitionData) { |
360 | 418 | LogContext logContext = new LogContext(); |
361 | 419 | ShareFetchMetricsRegistry shareFetchMetricsRegistry = new ShareFetchMetricsRegistry(); |
|
0 commit comments