telekom / testerra

Testerra is an integrated framework for automating tests for (web) applications.
https://docs.testerra.io/
Apache License 2.0
27 stars 15 forks source link

Fixes bug #421 - Run Testerra as part of fat jar standalone application #422

Closed erickubenka closed 6 months ago

erickubenka commented 6 months ago

Description

Fixes bug #421 by apply a package filter to avoid implementations of com.google.inject.AbstractModule that does not fullfill package class will be instantiated.

Concrete class of the fat jar that will force this error is com.google.inject.util.Modules$OverrideModule.

Before this fix Testerra tried to invoke the following implementations of AbstractModule inside the fat jar:

After this fix Testerra tried to invoke the following implemenation like intended:

Fixes #421

Type of change

Please delete options that are not relevant.

Checklist:

martingrossmann commented 6 months ago

Hi @erickubenka, thanks for your fix! But can you explain why new ConfigurationBuilder().forPackages(...) does not filter in a JAR context?

erickubenka commented 6 months ago

Hey @martingrossmann,

to be honest, I don't get it either. When debugging the Main class with IntelliJ and investigating the scanned classes everything looks good, but in a built fat jar somehow it seems not be working as intented without that additional filter. May something is different then in how classes are loaded or the ClassLoader is built in general.

So, i just don't get it and had spent a lot hours the past days to find out if I was doing something wrong when packaging the jar. But as it happens with default skeleton project as well, I just tried to find out how I can fix it.

martingrossmann commented 6 months ago

@erickubenka I build a new snapshot version 2.8-SNAPSHOT with the latest master. Please check it out.

erickubenka commented 6 months ago

@martingrossmann

So i took the testerra-skeletons project, upgraded my dependencies to 2.8-SNAPSHOT and things worked well.

For openjdk-11, which i run in a docker container, everything worked well.

For openjdk-17, I ran into the following error, but was able to handle it by allowing deep reflections with new jvm option --add-opens

So for openjdk-17 command looks like this:

java --add-opens=java.base/java.lang=ALL-UNNAMED -jar build/libs/testerra-skeletons-2-SNAPSHOT.jar

And just for completion, the error that I ran into when executing fat jar without --add-opens flag

25.04.2024 21:29:33.700 [main][INFO]: common.Testerra - ####################################################
25.04.2024 21:29:33.715 [main][INFO]: common.Testerra - #                     .8t .                        #
25.04.2024 21:29:33.715 [main][INFO]: common.Testerra - #                    .8t ;;                        #
25.04.2024 21:29:33.715 [main][INFO]: common.Testerra - #                   :@S %S8:;                      #
25.04.2024 21:29:33.715 [main][INFO]: common.Testerra - #                   88   8   ;.                    #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #                 .X8.   SS .8 ;                   #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #                 @8.     88.  X..8                #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #       .SX.    88        %S @..S X8               #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #       .88 8.  SS          8 ;   %8@t             #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #       @8 88;ttX;.         ::     @8;@@           #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #      88.  @X:X;                   @S :@@         #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #    .88.   .XX:                    .8.. ;8@       #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #    X@                               X@ . 8S      #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #  .%@:                                X8.  ;8X    #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #  tt@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXSS%@8@8S::  #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #                                                  #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #    T    E     S     T     E    R     R     A     #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #                                                  #
25.04.2024 21:29:33.716 [main][INFO]: common.Testerra - #                   2.8-SNAPSHOT                   #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - ####################################################
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.java.version: 11                           #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.os.name:      Linux                        #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.os.arch:      amd64                        #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.os.version:   4.15.0-128-generic           #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.user.name:    root                         #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - # build.timestamp:    Thu Apr 25 12:34:31 UTC 2024 #
25.04.2024 21:29:33.717 [main][INFO]: common.Testerra - ####################################################
25.04.2024 21:29:33.819 [main][INFO]: common.Testerra - Register IoC modules: CoreHook, DriverUiHook, DriverUi_Desktop, ReportModelHook, ReportNgHook
Exception in thread "main" java.lang.ExceptionInInitializerError
        at eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider.<clinit>(WebDriverManagerProvider.java:32)
        at Main.main(Main.java:9)
Caused by: com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2087)
        at com.google.common.cache.LocalCache.get(LocalCache.java:4036)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4059)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5041)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:5048)
        at com.google.inject.internal.FailableCache.get(FailableCache.java:51)
        at com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore.java:48)
        at com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:155)
        at com.google.inject.internal.InjectorImpl.initializeJitBinding(InjectorImpl.java:595)
        at com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:932)
        at com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:852)
        at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:291)
        at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:222)
        at com.google.inject.internal.InjectorImpl.getInternalFactory(InjectorImpl.java:938)
        at com.google.inject.internal.FactoryProxy.notify(FactoryProxy.java:48)
        at com.google.inject.internal.ProcessedBindingData.runCreationListeners(ProcessedBindingData.java:60)
        at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:133)
        at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
        at com.google.inject.Guice.createInjector(Guice.java:87)
        at com.google.inject.Guice.createInjector(Guice.java:69)
        at com.google.inject.Guice.createInjector(Guice.java:59)
        at eu.tsystems.mms.tic.testframework.common.Testerra.initIoc(Testerra.java:206)
        at eu.tsystems.mms.tic.testframework.common.Testerra.<clinit>(Testerra.java:143)
        ... 2 more
Caused by: java.lang.IllegalStateException: Unable to load cache item
        at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:79)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache.get(LoadingCache.java:34)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:291)
        at com.google.inject.internal.cglib.reflect.$FastClass$Generator.create(FastClass.java:65)
        at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:258)
        at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:207)
        at com.google.inject.internal.DefaultConstructionProxyFactory.create(DefaultConstructionProxyFactory.java:49)
        at com.google.inject.internal.ProxyFactory.create(ProxyFactory.java:156)
        at com.google.inject.internal.ConstructorInjectorStore.createConstructor(ConstructorInjectorStore.java:92)
        at com.google.inject.internal.ConstructorInjectorStore.access$000(ConstructorInjectorStore.java:29)
        at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:37)
        at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:33)
        at com.google.inject.internal.FailableCache$1.load(FailableCache.java:40)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3589)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2328)
        at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2187)
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2081)
        ... 24 more
Caused by: java.lang.ExceptionInInitializerError
        at com.google.inject.internal.cglib.core.$DuplicatesPredicate.evaluate(DuplicatesPredicate.java:104)
        at com.google.inject.internal.cglib.core.$CollectionUtils.filter(CollectionUtils.java:52)
        at com.google.inject.internal.cglib.reflect.$FastClassEmitter.<init>(FastClassEmitter.java:69)
        at com.google.inject.internal.cglib.reflect.$FastClass$Generator.generateClass(FastClass.java:77)
        at com.google.inject.internal.cglib.core.$DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator.generate(AbstractClassGenerator.java:329)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache$2.call(LoadingCache.java:54)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:61)
        ... 41 more
Caused by: com.google.inject.internal.cglib.core.$CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @45c8abff
        at com.google.inject.internal.cglib.core.$ReflectUtils.defineClass(ReflectUtils.java:464)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator.generate(AbstractClassGenerator.java:336)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache$2.call(LoadingCache.java:54)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:61)
        at com.google.inject.internal.cglib.core.internal.$LoadingCache.get(LoadingCache.java:34)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
        at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:291)
        at com.google.inject.internal.cglib.core.$KeyFactory$Generator.create(KeyFactory.java:221)
        at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:174)
        at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:157)
        at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:149)
        at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:145)
        at com.google.inject.internal.cglib.core.$MethodWrapper.<clinit>(MethodWrapper.java:23)
        ... 52 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @45c8abff
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
        at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
        at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
        at com.google.inject.internal.cglib.core.$ReflectUtils$1.run(ReflectUtils.java:61)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
        at com.google.inject.internal.cglib.core.$ReflectUtils.<clinit>(ReflectUtils.java:52)
        at com.google.inject.internal.cglib.reflect.$FastClassEmitter.<init>(FastClassEmitter.java:67)
        ... 49 more

So thanks for the fast update and the provided SNAPSHOT version.