Skip to content

[test] Replace PowerMockito#mockStatic usages with mockito-inline - #14098

Merged
lhotari merged 17 commits into
apache:masterfrom
nicoloboschi:test/replace-powermock-static
Feb 11, 2022
Merged

[test] Replace PowerMockito#mockStatic usages with mockito-inline#14098
lhotari merged 17 commits into
apache:masterfrom
nicoloboschi:test/replace-powermock-static

Conversation

@nicoloboschi

@nicoloboschi nicoloboschi commented Feb 2, 2022

Copy link
Copy Markdown
Contributor

Motivation

PowerMockito static mocks don't work well with the latest JDK class encapsulation mechanisms. The main problem is that PowerMockito, in order to mock a single static method of a class, try to setAccessible a lot of other apparently related classes. This means, starting from JDK17, you need to add --add-opens to the Java runtime options in order to avoid runtime errors.

PowerMockito development isn't much active and they don't seem to be ready for the new JDK releases.
The best replacement is to use mockito-inline (additional part of mockito-core), which uses a different algorithm in order to mock static methods - a lot less invasive.

Modifications

Documentation

  • no-need-doc

@github-actions github-actions Bot added the doc-not-needed Your PR changes do not impact docs label Feb 2, 2022
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

3 similar comments
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
nicoloboschi force-pushed the test/replace-powermock-static branch from f64c3bd to e5cd5c2 Compare February 7, 2022 16:35

@eolivelli eolivelli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great work.

I believe we have to rework that Factory class. I found it a bit unusual. I understand that it is for Mockito but we can probably organise it better

Comment thread pulsar-common/src/main/java/org/apache/pulsar/common/nar/NarClassLoader.java Outdated

@lhotari lhotari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

did you try Mockito.mockStatic(NarClassLoader.class, Mockito.CALLS_REAL_METHODS) ? does that help address the limitation that you were describing about not being able to mock static methods on a classloader class?

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

@lhotari thanks for the suggestion. Unfortunately it doesn't help. I inspected the mockito-inline codebase and I haven't found a way to by-pass this check.

https://github.com/mockito/mockito/blob/c3d0847e6caee970e2db3ef77e1d31facf090550/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java#L544-L558

@lhotari
lhotari requested a review from eolivelli February 9, 2022 11:20

@lhotari lhotari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Really good work @nicoloboschi ! Awesome

@eolivelli eolivelli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great work!

+1

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@michaeljmarshall michaeljmarshall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

Comment thread pulsar-common/src/main/java/org/apache/pulsar/common/protocol/Commands.java Outdated
Comment thread pulsar-common/src/main/java/org/apache/pulsar/common/protocol/Commands.java Outdated
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

3 similar comments
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

1 similar comment
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@michaeljmarshall

Copy link
Copy Markdown
Member

@nicoloboschi - it looks like the broker test is failing with the below stack trace. I'm wondering if it is a legitimate failure and not just a flaky test.

Error:  Tests run: 6, Failures: 3, Errors: 0, Skipped: 3, Time elapsed: 0.063 s <<< FAILURE! - in org.apache.pulsar.broker.service.persistent.PersistentSubscriptionTest
Error:  setup(org.apache.pulsar.broker.service.persistent.PersistentSubscriptionTest)  Time elapsed: 0.023 s  <<< FAILURE!
org.mockito.exceptions.base.MockitoException: Unable to create mock instance of type 'PulsarService'
	at org.apache.pulsar.broker.BrokerTestUtil.spyWithClassAndConstructorArgs(BrokerTestUtil.java:43)
	at org.apache.pulsar.broker.service.persistent.PersistentSubscriptionTest.setup(PersistentSubscriptionTest.java:116)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:132)
	at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:61)
	at org.testng.internal.ConfigInvoker.invokeConfigurationMethod(ConfigInvoker.java:366)
	at org.testng.internal.ConfigInvoker.invokeConfigurations(ConfigInvoker.java:320)
	at org.testng.internal.TestInvoker.runConfigMethods(TestInvoker.java:701)
	at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:527)
	at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:174)
	at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
	at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:822)
	at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:147)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.testng.TestRunner.privateRun(TestRunner.java:764)
	at org.testng.TestRunner.run(TestRunner.java:585)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
	at org.testng.SuiteRunner.run(SuiteRunner.java:286)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
	at org.testng.TestNG.runSuites(TestNG.java:1069)
	at org.testng.TestNG.run(TestNG.java:1037)
	at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:135)
	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeSingleClass(TestNGDirectoryTestSuite.java:112)
	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeLazy(TestNGDirectoryTestSuite.java:123)
	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:90)
	at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: org.mockito.creation.instance.InstantiationException: 
Unable to create instance of 'PulsarService'.
Please ensure the target class has a constructor that matches these argument types: [org.apache.pulsar.broker.ServiceConfiguration] and executes cleanly.
	... 36 more
Caused by: java.lang.reflect.InvocationTargetException
	at org.mockito.internal.util.reflection.InstrumentationMemberAccessor.newInstance(InstrumentationMemberAccessor.java:198)
	at org.mockito.internal.util.reflection.InstrumentationMemberAccessor.newInstance(InstrumentationMemberAccessor.java:161)
	at org.mockito.internal.util.reflection.ModuleMemberAccessor.newInstance(ModuleMemberAccessor.java:42)
	at org.mockito.internal.creation.instance.ConstructorInstantiator.invokeConstructor(ConstructorInstantiator.java:70)
	at org.mockito.internal.creation.instance.ConstructorInstantiator.withParams(ConstructorInstantiator.java:53)
	at org.mockito.internal.creation.instance.ConstructorInstantiator.newInstance(ConstructorInstantiator.java:39)
	at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.doCreateMock(InlineDelegateByteBuddyMockMaker.java:360)
	at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMock(InlineDelegateByteBuddyMockMaker.java:330)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:58)
	at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:53)
	at org.mockito.internal.MockitoCore.mock(MockitoCore.java:84)
	at org.mockito.Mockito.mock(Mockito.java:1964)
	at org.apache.pulsar.broker.BrokerTestUtil.spyWithClassAndConstructorArgs(BrokerTestUtil.java:43)
	at org.apache.pulsar.broker.service.persistent.PersistentSubscriptionTest.setup(PersistentSubscriptionTest.java:116)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	... 34 more
Caused by: java.lang.IllegalArgumentException: Required clusterName is null
	at org.apache.pulsar.common.configuration.PulsarConfigurationLoader.isComplete(PulsarConfigurationLoader.java:153)
	at org.apache.pulsar.broker.PulsarService.<init>(PulsarService.java:295)
	at org.apache.pulsar.broker.PulsarService.<init>(PulsarService.java:285)
	at org.apache.pulsar.broker.PulsarService.<init>(PulsarService.java:277)
	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710)
	at org.mockito.internal.util.reflection.InstrumentationMemberAccessor$Dispatcher$ByteBuddy$6w1xGzlj.invokeWithArguments(Unknown Source)
	at org.mockito.internal.util.reflection.InstrumentationMemberAccessor.lambda$newInstance$0(InstrumentationMemberAccessor.java:191)
	at org.mockito.internal.util.reflection.InstrumentationMemberAccessor.newInstance(InstrumentationMemberAccessor.java:188)
	... 51 more

@nicoloboschi

nicoloboschi commented Feb 10, 2022

Copy link
Copy Markdown
Contributor Author

@michaeljmarshall yes you're right. I've found a couple of other tests that can't simply pass for the same reason (Required clusterName is null). I can't explain to myself how they can be green on current master. Maybe enabling `mockito-inline´ Mockito itself is more stable.

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

2 similar comments
@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@lhotari
lhotari merged commit ca64c67 into apache:master Feb 11, 2022
Nicklee007 pushed a commit to Nicklee007/pulsar that referenced this pull request Apr 20, 2022
…ache#14098)

* introduce NarClassLoaderBuilder since Mockito Inline cannot mock classloader classes
* fix spyWithClassAndConstructorArgs(PulsarService.class, svcConfig) tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-not-needed Your PR changes do not impact docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants