Skip to content

Commit

Permalink
Register a config for tests in the Quarkus Classloader
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Dec 20, 2024
1 parent 77515e0 commit 13d9076
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Optional;
import java.util.Set;

import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.extension.RegisterExtension;

Expand Down Expand Up @@ -642,6 +643,16 @@ private AppMakerHelper.DumbHolder makeClassLoader(String key, Class requiredTest
QuarkusClassLoader loader = (QuarkusClassLoader) holder.startupAction()
.getClassLoader();

Class<?> configProviderResolverClass = loader.loadClass(ConfigProviderResolver.class.getName());
Object configProviderResolver = configProviderResolverClass.getMethod("instance").invoke(null);

Class<?> testConfigProviderResolverClass = loader.loadClass(QuarkusTestConfigProviderResolver.class.getName());
Object testConfigProviderResolver = testConfigProviderResolverClass.getDeclaredConstructor(ClassLoader.class)
.newInstance(loader);

configProviderResolverClass.getDeclaredMethod("setInstance", configProviderResolverClass).invoke(null,
testConfigProviderResolver);

// TODO is this a good idea?
// TODO without this, the parameter dev mode tests regress, but it feels kind of wrong - is there some use of TCCL in JUnitRunner we need to find
// TODO definitely remove this or devtools tests fail
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.test.junit.classloading;

import io.quarkus.deployment.dev.testing.TestConfig;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigProviderResolver;

public class QuarkusTestConfigProviderResolver extends SmallRyeConfigProviderResolver {
private final SmallRyeConfigProviderResolver resolver;

public QuarkusTestConfigProviderResolver(final ClassLoader classLoader) {
this.resolver = (SmallRyeConfigProviderResolver) SmallRyeConfigProviderResolver.instance();

SmallRyeConfig config = ConfigUtils.configBuilder(false, true, LaunchMode.TEST)
.withProfile(LaunchMode.TEST.getDefaultProfile())
.withMapping(TestConfig.class, "quarkus.test")
.forClassLoader(classLoader)
.build();

this.registerConfig(config, Thread.currentThread().getContextClassLoader());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public class TestConfigProviderResolver extends SmallRyeConfigProviderResolver {
private final Map<LaunchMode, SmallRyeConfig> configs;

TestConfigProviderResolver() {
new Exception().printStackTrace();
this.resolver = (SmallRyeConfigProviderResolver) SmallRyeConfigProviderResolver.instance();
this.classLoader = Thread.currentThread().getContextClassLoader();
System.out.println("HOLLY CONFIG construcing with " + this.classLoader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Collection;
Expand Down Expand Up @@ -270,26 +269,7 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con

// At this point, the TCCL is the FacadeClassLoader; trying to do getConfig with that TCCL fails with java.util.ServiceConfigurationError: io.smallrye.config.SmallRyeConfigFactory: io.quarkus.runtime.configuration.QuarkusConfigFactory not a subtype
// If we set the TCCL to be this.getClass().getClassLoader(), get config succeeds, but config.getConfigMapping(TestConfig.class) fails, because the mapping was registered when the TCCL was the FacadeClassLoader

TestConfig testConfig;
try {
Class<?> aClass = Thread.currentThread()
.getContextClassLoader()
.loadClass(SmallRyeConfig.class.getName());
Object o = ConfigProvider.getConfig()
.unwrap(aClass);
Method m = aClass.getMethod("getConfigMapping", Class.class);
testConfig = (TestConfig) m.invoke(o, TestConfig.class);

} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
TestConfig testConfig = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).getConfigMapping(TestConfig.class);

Optional<List<String>> tags = testConfig.profile().tags();
if (tags.isEmpty() || tags.get().isEmpty()) {
Expand Down

0 comments on commit 13d9076

Please sign in to comment.