MINOR: Rewrite FetchFromFollowerIntegrationTest from Scala to Java and move to server module#22252
Conversation
and move FetchRequestTest to server module
@m1a2st Thanks for reviewing. You're right! We should delete the scala one. |
| * @param timeoutMs The duration in ms to wait for the leader | ||
| * @return The leader broker id | ||
| */ | ||
| public static int waitUntilLeaderIsKnown( |
There was a problem hiding this comment.
If this is used solely by FetchRequestTest, would you mind moving it into the test class instead?
There was a problem hiding this comment.
Done. waitUntilLeaderIsKnown has been moved into FetchRequestTest as a protected static method.
|
|
||
| @ClusterTest | ||
| @Timeout(60) | ||
| public void testFetchFromFollowerWithRoll(ClusterInstance cluster) throws Exception { |
There was a problem hiding this comment.
We should test both consumers, right?
There was a problem hiding this comment.
Yes, you are correct! testFetchFromFollowerWithRoll now creates and uses both followerConsumer and leaderConsumer.
| } | ||
|
|
||
| @ClusterTest | ||
| @Timeout(60) |
There was a problem hiding this comment.
this is redundant annotation. It is already included by ClusterTest
There was a problem hiding this comment.
Done. All @timeout annotations have been removed.
|
|
||
| @ClusterTest | ||
| @Timeout(15) | ||
| public void testFetchFromLeaderWhilePreferredReadReplicaIsUnavailable(ClusterInstance cluster) throws Exception { |
| Map<String, Uuid> topicIds; | ||
|
|
||
| @ClusterTest | ||
| @Timeout(15) |
|
|
||
| private void verifyRackAwareAssignments( | ||
| ExecutorService executor, | ||
| List<?> consumers, |
There was a problem hiding this comment.
Could you use Object or byte[] instead?
There was a problem hiding this comment.
Done. The parameter is now List<Consumer<byte[], byte[]>>.
| topics.add(topic); | ||
| topics.addAll(List.of(additionalTopics)); | ||
|
|
||
| for (Object c : consumers) { |
There was a problem hiding this comment.
consumers.forEach(Consumer::close);| for (Object c : consumers) { | ||
| recordFutures.add(executor.submit(() -> { | ||
| try { | ||
| @SuppressWarnings("unchecked") |
There was a problem hiding this comment.
@SuppressWarnings("unchecked") smells fishy to me ...
There was a problem hiding this comment.
Done. Resolved as a consequence of switching from List<?> to List<Consumer<byte[], byte[]>>. No cast or suppression is needed anymore.
m1a2st
left a comment
There was a problem hiding this comment.
Thanks for this patch, left some comments
| @Timeout(15) | ||
| public void testFollowerCompleteDelayedFetchesOnReplication(ClusterInstance cluster) throws Exception { | ||
| this.cluster = cluster; | ||
| try (Admin admin = cluster.admin()) { |
There was a problem hiding this comment.
Why is this Admin client created but never used?
There was a problem hiding this comment.
My mistake. The unused try (Admin admin = ...) block has been removed.
| verifyRackAwareAssignments(executor, consumers, producer, partitionList, topicWithAllPartitionsOnAllRacks, partitionList, topicWithSingleRackPartitions); | ||
|
|
||
| } finally { | ||
| executor.shutdown(); |
There was a problem hiding this comment.
This should be executor.shutdownNow().
There was a problem hiding this comment.
Done. Thank you for reminding me the difference between executor.shutdown() and executor.shutdownNow()!
| public static final int FOLLOWER_BROKER_ID = 1; | ||
|
|
||
| private ClusterInstance cluster; | ||
| Map<String, Uuid> topicIds; |
There was a problem hiding this comment.
This field can be a local variable since it’s only used in one method.
| List<Integer> partitionList, | ||
| String topic, | ||
| List<Integer> expectedPartitionOrder, | ||
| String... additionalTopics) throws Exception { |
There was a problem hiding this comment.
Could we use List<String> instead?
| .toList(); | ||
|
|
||
| List<Consumer<byte[], byte[]>> consumers = consumerConfigs.stream() | ||
| .map(config -> cluster.<byte[], byte[]>consumer(config)) |
There was a problem hiding this comment.
List<Consumer<byte[], byte[]>> consumers = consumerConfigs.stream()
.map(cluster::<byte[], byte[]>consumer)
.toList();There was a problem hiding this comment.
thank you for the review! updated.
| private ClusterInstance cluster; | ||
|
|
||
| @ClusterTest | ||
| public void testFollowerCompleteDelayedFetchesOnReplication(ClusterInstance cluster) throws Exception { |
There was a problem hiding this comment.
It should test both consumers, right?
There was a problem hiding this comment.
Yes! Thank you for reminding me.
|
|
||
| Supplier<Optional<Integer>> newLeaderExists = () -> { | ||
| if (expectedLeaderOpt.isPresent()) { | ||
| LOG.debug("Checking leader that has changed to {}", expectedLeaderOpt.get()); |
There was a problem hiding this comment.
I'm wondering whether we should keep these debug messages in this migration.
There was a problem hiding this comment.
We could remove them because the waitForCondition timeout message already identifies the partition and timeoutMs.
m1a2st
left a comment
There was a problem hiding this comment.
Thanks for the update, few more comments
| }); | ||
|
|
||
| String expectedTopic = version >= 13 ? null : tp.topic(); | ||
| topicIdPartitionMap = fetchRequest.fetchData(Collections.emptyMap()); |
There was a problem hiding this comment.
| topicIdPartitionMap = fetchRequest.fetchData(Collections.emptyMap()); | |
| topicIdPartitionMap = fetchRequest.fetchData(Map.of()); |
There was a problem hiding this comment.
Thank you for the review and catch the old usage part. Updated.
| Optional<Integer> currentLeaderEpoch = Optional.of(121); | ||
| FetchRequest.PartitionData partitionData = new FetchRequest.PartitionData(topicId, fetchOffset, logStartOffset, maxBytes, currentLeaderEpoch); | ||
| FetchRequest fetchRequest = createFetchRequestByVersion(version, tp, partitionData); | ||
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId, tp.topic()); |
There was a problem hiding this comment.
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId, tp.topic()); | |
| Map<Uuid, String> topicNames = Map.of(topicId, tp.topic()); |
| } else { | ||
| return FetchRequest.Builder | ||
| .forReplica(version, 0, 1, 1, 1, partitionDataMap) | ||
| .removed(Collections.singletonList(tp)) |
There was a problem hiding this comment.
| .removed(Collections.singletonList(tp)) | |
| .removed(List.of(tp)) |
| if (version >= 13) { | ||
| return FetchRequest.Builder | ||
| .forReplica(version, 0, 1, 1, 1, partitionDataMap) | ||
| .replaced(Collections.singletonList(tp)) |
There was a problem hiding this comment.
| .replaced(Collections.singletonList(tp)) | |
| .replaced(List.of(tp)) |
|
|
||
| private FetchRequest createFetchRequestByVersion(short version, TopicIdPartition tp, | ||
| FetchRequest.PartitionData partitionData) { | ||
| Map<TopicPartition, FetchRequest.PartitionData> partitionDataMap = Collections.singletonMap(tp.topicPartition(), partitionData); |
There was a problem hiding this comment.
| Map<TopicPartition, FetchRequest.PartitionData> partitionDataMap = Collections.singletonMap(tp.topicPartition(), partitionData); | |
| Map<TopicPartition, FetchRequest.PartitionData> partitionDataMap = Map.of(tp.topicPartition(), partitionData); |
| boolean fetchRequestUsesTopicIds = version >= 13; | ||
|
|
||
| FetchRequest fetchRequest = FetchRequest.parse(FetchRequest.Builder | ||
| .forReplica(version, 0, 1, 1, 1, Collections.emptyMap()) |
There was a problem hiding this comment.
| .forReplica(version, 0, 1, 1, 1, Collections.emptyMap()) | |
| .forReplica(version, 0, 1, 1, 1, Map.of()) |
| Uuid topicId0 = Uuid.randomUuid(); | ||
| Uuid topicId1 = Uuid.randomUuid(); | ||
| // Only include topic IDs for the first topic partition. | ||
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId0, topicPartition0.topic()); |
There was a problem hiding this comment.
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId0, topicPartition0.topic()); | |
| Map<Uuid, String> topicNames = Map.of(topicId0, topicPartition0.topic()); |
| .removed(Collections.emptyList()) | ||
| .replaced(Collections.emptyList()) |
There was a problem hiding this comment.
| .removed(Collections.emptyList()) | |
| .replaced(Collections.emptyList()) | |
| .removed(List.of()) | |
| .replaced(List.of()) |
| Uuid topicId1 = Uuid.randomUuid(); | ||
|
|
||
| // Only include topic IDs for the first topic partition. | ||
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId0, topicPartition0.topic()); |
There was a problem hiding this comment.
| Map<Uuid, String> topicNames = Collections.singletonMap(topicId0, topicPartition0.topic()); | |
| Map<Uuid, String> topicNames = Map.of(topicId0, topicPartition0.topic()); |
| Map<TopicPartition, FetchRequest.PartitionData> partitionData = Collections.singletonMap(tp.topicPartition(), | ||
| new FetchRequest.PartitionData(topicId, 0, 0, 0, Optional.empty())); | ||
| List<TopicIdPartition> toReplace = Collections.singletonList(tp); |
…n createPartitionMap - replaced the manual connect + serialize + send + receive block with IntegrationTestUtils.connectAndReceive
Summary
This PR consolidates
FetchRequestrelated tests into the server module by mergingFetchFromFollowerIntegrationTestinto
FetchRequestTest.Key changes include:
FetchRequestTestfrom core to the server module.FetchFromFollowerIntegrationTestin Java and subsequently merging its integration tests intoFetchRequestTest.integration tests.