Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KAFKA-14132: Replace Easymock & Powermock with Mockito in KafkaBasedLogTest #14153

Merged
merged 12 commits into from Aug 11, 2023

Conversation

bachmanity1
Copy link
Contributor

Replaced Easymock & Powermock with Mockito in KafkaBasedLogTest.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@bachmanity1
Copy link
Contributor Author

@C0urante @mjsax @cadonna could you please review this?

@divijvaidya divijvaidya added the tests Test fixes (including flaky tests) label Aug 7, 2023
Copy link
Contributor

@divijvaidya divijvaidya left a comment

Choose a reason for hiding this comment

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

Hey @bachmanity1

We are tracking migration of this file at https://issues.apache.org/jira/browse/KAFKA-14132 and currently @mdedetrich has volunteered to work on KafkaBasedLogTest. Can you please add a comment on the JIRA and ask @mdedetrich if they have an open PR yet? If they don't, feel assign this test to yourself so that we don't end up duplicating effort across the community.

Thanks!

@bachmanity1 bachmanity1 changed the title KAFKA-7438: Replace Easymock & Powermock with Mockito in KafkaBasedLogTest KAFKA-14132: Replace Easymock & Powermock with Mockito in KafkaBasedLogTest Aug 7, 2023
@bachmanity1
Copy link
Contributor Author

Hi @divijvaidya

Thanks for letting me know about ticket KAFKA-14132. It turns out that @mdedetrich has already begun working on this issue and has submitted a PR, but he said he doesn't have enough time to complete it and agreed to close it. Thus, I think we can handle this issue in this PR. When you have time could you please review this PR?

@bachmanity1
Copy link
Contributor Author

bachmanity1 commented Aug 8, 2023

I don't know why checks result in This commit cannot be built. It looks like the built failure is not related to this PR or to the connect module, I would appreciate it if anybody could help me resolve it or explain me why it occurs.

@divijvaidya
Copy link
Contributor

When you have time could you please review this PR?

I am sorry, I won't have time to review this any time soon. Will circle back in a couple of weeks perhaps. I am tagging a few folks who might be interested in reviewing this: @clolov @yashmayya @shekhar-rajak

Copy link
Contributor

@yashmayya yashmayya left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @bachmanity1! I've left a few comments.

@Before
public void setUp() {
store = PowerMock.createPartialMock(KafkaBasedLog.class, new String[]{"createConsumer", "createProducer"},
TOPIC, PRODUCER_PROPS, CONSUMER_PROPS, consumedCallback, time, initializer);
store = spy(new KafkaBasedLog<>(TOPIC, PRODUCER_PROPS, CONSUMER_PROPS, topicAdminSupplier, consumedCallback, time, initializer));
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the only reason we need a partial mock here is to stub in the mock producer / consumer. Since the KafkaBasedLog::createProducer and KafkaBasedLog::createConsumer methods are now protected (looks like they were private when this test was originally written), could we just override those methods to return the mock clients and use a regular instance instead of using a spy / partial mock? I'd prefer it if we could avoid the use of spies / partial mocks as far as possible, since they aren't very OOP-y.

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.StrictStubs.class)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should also remove this test from the list here so that it isn't skipped on Java 16 and newer -

kafka/build.gradle

Lines 413 to 423 in 8dec3e6

// Exclude PowerMock tests when running with Java 16 or newer until a version of PowerMock that supports the relevant versions is released
// The relevant issues are https://github.com/powermock/powermock/issues/1094 and https://github.com/powermock/powermock/issues/1099
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
testsToExclude.addAll([
// connect tests
"**/DistributedHerderTest.*",
"**/KafkaConfigBackingStoreTest.*",
"**/KafkaBasedLogTest.*", "**/StandaloneHerderTest.*",
"**/WorkerSinkTaskTest.*", "**/WorkerSinkTaskThreadedTest.*"
])
}

private static ByteBuffer buffer(String v) {
return ByteBuffer.wrap(v.getBytes());
private void verifyStartAndStop() {
verify(initializer).accept(any());
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that we're moving to the newer non-deprecated KafkaBasedLog constructor in this test class, could we enhance this verification to also verify that the initializer is called with the admin client from the supplier -

admin = topicAdminSupplier.get(); // may be null
if (admin == null && requireAdminForOffsets) {
throw new ConnectException(
"Must provide a TopicAdmin to KafkaBasedLog when consumer is configured with "
+ ConsumerConfig.ISOLATION_LEVEL_CONFIG + " set to "
+ IsolationLevel.READ_COMMITTED.name().toLowerCase(Locale.ROOT)
);
}
initializer.accept(admin);

@@ -160,18 +156,12 @@ public void testStartStop() throws Exception {
assertEquals(CONSUMER_ASSIGNMENT, consumer.assignment());

store.stop();

assertFalse(Whitebox.<Thread>getInternalState(store, "thread").isAlive());
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we losing this test coverage? Can we bump up the visibility of the thread instance variable to package-private (with a comment stating that it is being made visible for testing) and retain this coverage?

Capture<org.apache.kafka.clients.producer.Callback> callback1 = EasyMock.newCapture();
EasyMock.expect(producer.send(EasyMock.eq(tp1Record), EasyMock.capture(callback1))).andReturn(tp1Future);

// Producer flushes when read to log end is called
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we retain this clarifying comment (we can add it above the producer flush verification)?

EasyMock.expectLastCall().times(1);

expectProducerAndConsumerCreate();
store = spy(new KafkaBasedLog<>(TOPIC, PRODUCER_PROPS, CONSUMER_PROPS, adminSupplier, consumedCallback, time, initializer));
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we still need this separate setupWithAdmin method now that we're setting up the KafkaBasedLog store with a topic admin supplier even in the regular setUp method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, I think we can merge setupWithAdmin into setUp.

Comment on lines +443 to +444
when(admin.retryEndOffsets(eq(tps), any(), anyLong())).thenReturn(endOffsets);
when(admin.endOffsets(eq(tps))).thenReturn(endOffsets);
Copy link
Contributor

Choose a reason for hiding this comment

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

We're losing out on the existing coverage here since we're no longer ensuring that these methods are called one time only. Can we add an explicit verification for this at the end of the test?

@yashmayya
Copy link
Contributor

I don't know why checks result in This commit cannot be built. It looks like the built failure is not related to this PR or to the connect module, I would appreciate it if anybody could help me resolve it or explain me why it occurs.

I checked the build and the failures are from unrelated tests that are known to be flaky so you can just ignore them.

@bachmanity1
Copy link
Contributor Author

Hi @yashmayya, thank you for your review! I've addressed the questions raised by you. Can you have one more look?

Copy link
Contributor

@yashmayya yashmayya left a comment

Choose a reason for hiding this comment

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

Thanks @bachmanity1, this is looking really good. I just had a few more comments.

@@ -103,7 +103,7 @@ public class KafkaBasedLog<K, V> {
private Optional<Producer<K, V>> producer;
private TopicAdmin admin;

private Thread thread;
Thread thread;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Thread thread;
// Visible for testing
Thread thread;

nit

Comment on lines 134 to 154
private class MockedKafkaBasedLog extends KafkaBasedLog<String, String> {
public MockedKafkaBasedLog(String topic,
Map<String, Object> producerConfigs,
Map<String, Object> consumerConfigs,
Supplier<TopicAdmin> topicAdminSupplier,
Callback<ConsumerRecord<String, String>> consumedCallback,
Time time,
Consumer<TopicAdmin> initializer) {
super(topic, producerConfigs, consumerConfigs, topicAdminSupplier, consumedCallback, time, initializer);
}

@Override
protected KafkaProducer<String, String> createProducer() {
return producer;
}

@Override
protected MockConsumer<String, String> createConsumer() {
return consumer;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use an anonymous inner class in the setUp method instead? I think that'll look a lot cleaner.

@Mock
private KafkaProducer<String, String> producer;
private MockConsumer<String, String> consumer;
@Mock
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious, why was this change required - 2c7d2e3?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

admin field needs to be mocked only in methods where previously setupWithAdmin was used, if we mock it everywhere then some tests don't pass because they expect that admin is null.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah yeah, that makes sense, the other methods are expecting the consumer to be used to retrieve the end offsets instead of the admin.

}

@Test
public void testGetOffsetsConsumerErrorOnReadToEnd() throws Exception {
expectStart();

// Producer flushes when read to log end is called
Copy link
Contributor

Choose a reason for hiding this comment

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

@bachmanity1
Copy link
Contributor Author

@yashmayya I've applied your suggestions.

Copy link
Contributor

@yashmayya yashmayya left a comment

Choose a reason for hiding this comment

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

Thanks @bachmanity1, LGTM!

@divijvaidya
Copy link
Contributor

Thank you for reviewing @yashmayya. The CI is still flaky with large number of failures and I am restarting it.

@bachmanity1
Copy link
Contributor Author

It looks like test failures are not related to this PR.

Build / JDK 17 and Scala 2.13 / testBalancePartitionLeaders() – org.apache.kafka.controller.QuorumControllerTest
Build / JDK 11 and Scala 2.13 / testSecondaryRefreshAfterElapsedDelay() – org.apache.kafka.common.security.oauthbearer.internals.secured.RefreshingHttpsJwksTest
Build / JDK 11 and Scala 2.13 / testBalancePartitionLeaders() – org.apache.kafka.controller.QuorumControllerTest
Build / JDK 8 and Scala 2.12 / testSyncTopicConfigs() – org.apache.kafka.connect.mirror.integration.MirrorConnectorsIntegrationBaseTest
Build / JDK 8 and Scala 2.12 / testCreatePartitionsUseProvidedForwardingAdmin() – org.apache.kafka.connect.mirror.integration.MirrorConnectorsWithCustomForwardingAdminIntegrationTest
Build / JDK 8 and Scala 2.12 / testRackAwareRangeAssignor() – integration.kafka.server.FetchFromFollowerIntegrationTest
Build / JDK 8 and Scala 2.12 / testBalancePartitionLeaders() – org.apache.kafka.controller.QuorumControllerTest
Build / JDK 8 and Scala 2.12 / testHighAvailabilityTaskAssignorLargeNumConsumers – org.apache.kafka.streams.processor.internals.StreamsAssignmentScaleTest
Build / JDK 11 and Scala 2.13 / testOffsetTranslationBehindReplicationFlow() – org.apache.kafka.connect.mirror.integration.MirrorConnectorsIntegrationExactlyOnceTest
Build / JDK 8 and Scala 2.12 / testOffsetTranslationBehindReplicationFlow() – org.apache.kafka.connect.mirror.integration.MirrorConnectorsIntegrationExactlyOnceTest
Build / JDK 8 and Scala 2.12 / testOffsetTranslationBehindReplicationFlow() – org.apache.kafka.connect.mirror.integration.MirrorConnectorsIntegrationExactlyOnceTest

@divijvaidya divijvaidya merged commit f137da0 into apache:trunk Aug 11, 2023
1 check failed
@bachmanity1 bachmanity1 deleted the replace-easymock-powermock branch August 11, 2023 08:54
jeqo pushed a commit to aiven/kafka that referenced this pull request Aug 15, 2023
…ogTest (apache#14153)

Reviewers: Yash Mayya <yash.mayya@gmail.com>, Divij Vaidya <diviv@amazon.com>
jeqo pushed a commit to jeqo/kafka that referenced this pull request Aug 15, 2023
…ogTest (apache#14153)

Reviewers: Yash Mayya <yash.mayya@gmail.com>, Divij Vaidya <diviv@amazon.com>
jeqo pushed a commit to jeqo/kafka that referenced this pull request Aug 15, 2023
…ogTest (apache#14153)

Reviewers: Yash Mayya <yash.mayya@gmail.com>, Divij Vaidya <diviv@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
connect tests Test fixes (including flaky tests)
Projects
None yet
4 participants