Skip to content

Commit

Permalink
QuarkusComponentTest: another fix for continuous testing integration
Browse files Browse the repository at this point in the history
- it seems that classloading in the continuous testing environment has
changed recently; this commit should fix the problem
- also add a test so that we can catch similar problems in the CI
  • Loading branch information
mkouba committed Aug 8, 2023
1 parent bc75d66 commit 9b7a8fe
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 10 deletions.
5 changes: 5 additions & 0 deletions integration-tests/devmode/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-component</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.quarkus.test.component;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.ContinuousTestingTestUtils;
import io.quarkus.test.ContinuousTestingTestUtils.TestStatus;
import io.quarkus.test.QuarkusDevModeTest;

public class ComponentContinuousTestingTest {

@RegisterExtension
static final QuarkusDevModeTest config = new QuarkusDevModeTest()
.withApplicationRoot(
root -> root.addClass(ComponentFoo.class).add(new StringAsset(ContinuousTestingTestUtils.appProperties()),
"application.properties"))
.setTestArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(ComponentUT.class));

@Test
public void test() {
ContinuousTestingTestUtils utils = new ContinuousTestingTestUtils();
TestStatus ts = utils.waitForNextCompletion();
assertEquals(0L, ts.getTestsFailed());
assertEquals(1L, ts.getTestsPassed());
assertEquals(0L, ts.getTestsSkipped());

config.modifySourceFile(ComponentFoo.class, s -> s.replace("return bar;", "return bar + bar;"));

ts = utils.waitForNextCompletion();
assertEquals(1L, ts.getTestsFailed());
assertEquals(0L, ts.getTestsPassed());
assertEquals(0L, ts.getTestsSkipped());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.test.component;

import jakarta.inject.Singleton;

import org.eclipse.microprofile.config.inject.ConfigProperty;

@Singleton
public class ComponentFoo {

@ConfigProperty(name = "bar", defaultValue = "baz")
String bar;

String ping() {
return bar;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.test.component;

import static org.junit.jupiter.api.Assertions.assertEquals;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Test;

@QuarkusComponentTest
@TestConfigProperty(key = "bar", value = "qux")
public class ComponentUT {

@Inject
ComponentFoo foo;

@Test
public void test() {
assertEquals("qux", foo.ping());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ private ClassLoader initArcContainer(ExtensionContext extensionContext, Collecti
throw new IllegalStateException("Failed to create index", e);
}

ClassLoader testClassClassLoader = testClass.getClassLoader();
// The test class is loaded by the QuarkusClassLoader in continuous testing environment
boolean isContinuousTesting = testClassClassLoader instanceof QuarkusClassLoader;
ClassLoader oldTccl = Thread.currentThread().getContextClassLoader();

IndexView computingIndex = BeanArchives.buildComputingBeanArchiveIndex(oldTccl,
Expand Down Expand Up @@ -541,11 +544,13 @@ private ClassLoader initArcContainer(ExtensionContext extensionContext, Collecti

// We need collect all generated resources so that we can remove them after the test
// NOTE: previously we kept the generated framework classes (to speedup subsequent test runs) but that breaks the existing @QuarkusTests
Set<Path> generatedResources = new HashSet<>();
Set<Path> generatedResources;

// E.g. target/generated-arc-sources/org/acme/ComponentsProvider
File componentsProviderFile = getComponentsProviderFile(testClass);
if (testClass.getClassLoader() instanceof QuarkusClassLoader) {
//continuous testing environment

if (isContinuousTesting) {
generatedResources = Set.of();
Map<String, byte[]> classes = new HashMap<>();
builder.setOutput(new ResourceOutput() {
@Override
Expand All @@ -566,11 +571,12 @@ public void writeResource(Resource resource) throws IOException {
}
break;
default:
throw new IllegalArgumentException();
throw new IllegalArgumentException("Unsupported resource type: " + resource.getType());
}
}
});
} else {
generatedResources = new HashSet<>();
File testOutputDirectory = getTestOutputDirectory(testClass);
builder.setOutput(new ResourceOutput() {
@Override
Expand All @@ -590,7 +596,7 @@ public void writeResource(Resource resource) throws IOException {
}
break;
default:
throw new IllegalArgumentException();
throw new IllegalArgumentException("Unsupported resource type: " + resource.getType());
}
}
});
Expand Down Expand Up @@ -748,7 +754,9 @@ public void accept(BytecodeTransformer transformer) {
}

// Use a custom ClassLoader to load the generated ComponentsProvider file
QuarkusComponentTestClassLoader testClassLoader = new QuarkusComponentTestClassLoader(oldTccl,
// In continuous testing the CL that loaded the test class must be used as the parent CL
QuarkusComponentTestClassLoader testClassLoader = new QuarkusComponentTestClassLoader(
isContinuousTesting ? testClassClassLoader : oldTccl,
componentsProviderFile,
null);
Thread.currentThread().setContextClassLoader(testClassLoader);
Expand Down Expand Up @@ -1077,18 +1085,18 @@ private File getComponentsProviderFile(Class<?> testClass) {
File targetDir = new File("target");
if (targetDir.canWrite()) {
// maven build
generatedSourcesDirectory = new File("target/generated-arc-sources");
generatedSourcesDirectory = new File(targetDir, "generated-arc-sources");
} else {
File buildDir = new File("build");
if (buildDir.canWrite()) {
// gradle build
generatedSourcesDirectory = new File("build/generated-arc-sources");
generatedSourcesDirectory = new File(buildDir, "generated-arc-sources");
} else {
generatedSourcesDirectory = new File("quarkus-component-test/generated-arc-sources");
}
}
return new File(generatedSourcesDirectory,
nameToPath(testClass.getPackage().getName()) + File.pathSeparator + ComponentsProvider.class.getSimpleName());
return new File(new File(generatedSourcesDirectory, nameToPath(testClass.getPackage().getName())),
ComponentsProvider.class.getSimpleName());
}

}

0 comments on commit 9b7a8fe

Please sign in to comment.