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

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

Merged
merged 17 commits into from
Feb 11, 2022

Conversation

nicoloboschi
Copy link
Contributor

@nicoloboschi nicoloboschi commented Feb 2, 2022

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
Contributor Author

/pulsarbot rerun-failure-checks

3 similar comments
@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
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
Copy link
Contributor

@eolivelli eolivelli left a comment

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

Copy link
Member

@lhotari lhotari left a comment

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
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
Copy link
Member

@lhotari lhotari left a comment

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

Copy link
Contributor

@eolivelli eolivelli left a comment

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
Contributor Author

/pulsarbot rerun-failure-checks

Copy link
Member

@michaeljmarshall michaeljmarshall left a comment

Choose a reason for hiding this comment

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

LGTM

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

3 similar comments
@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

1 similar comment
@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@michaeljmarshall
Copy link
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
Copy link
Contributor Author

nicoloboschi commented Feb 10, 2022

@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
Contributor Author

/pulsarbot rerun-failure-checks

2 similar comments
@nicoloboschi
Copy link
Contributor Author

/pulsarbot rerun-failure-checks

@nicoloboschi
Copy link
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