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

v1.4 lib class preload causes MissingMethodException with lib var step accepting lib class argument #224

Open
brianeray opened this issue May 27, 2020 · 2 comments

Comments

@brianeray
Copy link
Contributor

This is probably best explained by first looking at PR #223. Note the test resources at the bottom of the PR. The Monster1 lib class and monster1 lib custom step are a common pattern in our pipeline code base.

Prior to 1.4 the JPU framework had no problem matching the lib step's call method signature with a caller passing an instance of the lib class to it. With all the logging from the PR in place and the class preload logic commented out the call to the step will be successful, and my diagnostic logging looks something like this.

Loading shared library test_cross_class_usage with version master
DEBUG_ARGTYPE LibraryLoader.doLoadLibrary lib class preload disabled

DEBUG_ARGTYPE PTH.setGlobalVars monster1.call.nativeParameterTypes=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.setGlobalVars nativeParameterTypes*.hashCode()=[1169712890]
DEBUG_ARGTYPE PTH.setGlobalVars cachedParamClasses=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.setGlobalVars cachedParamClasses*.hashCode()=[1169712890]

DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses*.hashCode()=[1169712890]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes*.hashCode()=[1169712890]

DEBUG_ARGTYPE MethodSignature.equals thisClazz=class org.test.Monster1; thatClazz=class org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.canonicalName=org.test.Monster1; thatClazz.canonicalName=org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.hashCode()=1169712890; thatClazz.hashCode()=1169712890
DEBUG_ARGTYPE MethodSignature.equals Signatures are compatible
Dracula makes quite a scary monster

If the lib class preload logic is restored then the diagnostic logging reveals a fatal arg type mismatch.

Loading shared library test_cross_class_usage with version master

DEBUG_ARGTYPE GCL.loadClass source=file:/C:/src/JenkinsPipelineUnit/origin/vars-with-cross-class-args/build/resources/test/libs/test_cross_class_usage/src/org/test/Monster1.groovy
DEBUG_ARGTYPE GCL.loadClass cls=class org.test.Monster1
DEBUG_ARGTYPE GCL.loadClass cls.hashCode()=63214977

DEBUG_ARGTYPE PTH.setGlobalVars monster1.call.nativeParameterTypes=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.setGlobalVars nativeParameterTypes*.hashCode()=[857059753]
DEBUG_ARGTYPE PTH.setGlobalVars cachedParamClasses=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.setGlobalVars cachedParamClasses*.hashCode()=[63214977]

DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses*.hashCode()=[63214977]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes*.hashCode()=[63214977]

DEBUG_ARGTYPE MethodSignature.equals thisClazz=class org.test.Monster1; thatClazz=class org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.canonicalName=org.test.Monster1; thatClazz.canonicalName=org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.hashCode()=857059753; thatClazz.hashCode()=63214977

DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry argsClasses*.hashCode()=[63214977]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes=[class org.test.Monster1]
DEBUG_ARGTYPE PTH.getAllowedMethodEntry casted to paramTypes*.hashCode()=[63214977]

DEBUG_ARGTYPE MethodSignature.equals thisClazz=class org.test.Monster1; thatClazz=class org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.canonicalName=org.test.Monster1; thatClazz.canonicalName=org.test.Monster1
DEBUG_ARGTYPE MethodSignature.equals thisClazz.hashCode()=857059753; thatClazz.hashCode()=63214977

DEBUG_ARGTYPE TestInterceptingGCL class groovy.lang.MissingMethodException
DEBUG_ARGTYPE TestInterceptingGCL No signature of method: test_var_with_lib_class_arg_annotation.monster1() is applicable for argument types: (org.test.Monster1) values: [org.test.Monster1@45f50182]

DEBUG_ARGTYPE TestInterceptingGCL Arg 0 type/type hash: class org.test.Monster1/63214977

This is the hardest JPU problem I've encountered. I tried replacing the method registration in PipelineTestHelper.setGlobalVars(Binding) as follows.

-                    this.registerAllowedMethod(method(e.value.class.name, m.getNativeParameterTypes()),
+                    final nativeParamTypes = m.nativeParameterTypes
+                    final cachedParamClasses = nativeParamTypes*.name.collect {
+                        libLoader.groovyClassLoader.getClassCacheEntry(it) ?: it
+                    } as Class[]
+                    this.registerAllowedMethod(method(e.value.class.name, cachedParamClasses),
                                     { args -> m.doMethodInvoke(e.value, args) })

But if my memory is correct the arg types at runtime were still incompatible.

@stchar stchar added the bug label Jun 17, 2020
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 1, 2020
FILL IN THE BLANKS. This is a preliminary commit just to ship WIP from
the abandoned `support-lazy-lib-class-load` branch.
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 1, 2020
Preload lib classes prior to lib vars so that vars can use lib classes
as method argument types without spurious type mismatches and
`MissingMethodException`s. This was an odd side effect of the
class preload logic in 1.4's 5c90975 and 6f2639f, which caused the
classes to be loaded twice, confusing the method interceptor's
matching logic.
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 8, 2020
Troubleshooting debugging and related only, because the fix is not
working. But maybe this can be useful down the road.
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 9, 2020
TEMP COMMIT: Rebase all WIP on `master`.
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 9, 2020
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 9, 2020
brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 9, 2020
v1.4 introduced the preload of shared library classes alongside the
existing preload of vars (ie custom steps).

In most use cases this is ideal. However in some use cases library
steps that use library classes in their call arguments are subject
to mistaken `MissingMethodException` errors when those classes are
preloaded. The method interceptor becomes confused because at some
point the same types are loaded more that once, and the argument
passed to the interceptor appears to be of a different type than
the type registered in the interceptor.

In those use cases the pre-v1.4 behavior of lazy loading the library
classes is helpful. The new `LibraryLoader.preloadLibraryClasses`
property can be set by the test to disable the class preload.
@brianeray
Copy link
Contributor Author

PR #244

brianeray added a commit to brianeray/JenkinsPipelineUnit that referenced this issue Jul 10, 2020
stchar added a commit that referenced this issue Jul 13, 2020
@sotona-
Copy link

sotona- commented Jan 13, 2021

Found very strange behavior:
setting helper.libLoader.preloadLibraryClasses = true breaks tests throwing MissingMethodException, but only on RedHat based systems(tested on Amazon Linux 2 with 4.14 and 5.4 kernels, CentOS 8.3 with 4.18, CentOS 7 with 3.10).
On Ubuntu and macOS tests work with any value of preloadLibraryClasses.

@nre-ableton nre-ableton removed the bug label Jan 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants