Skip to content

Commit

Permalink
Merge pull request #44279 from snazy/reproducer-44235
Browse files Browse the repository at this point in the history
Limit `MATCHING_RESOURCES` TestResources to the test that declares them
  • Loading branch information
geoand authored Nov 5, 2024
2 parents c90e362 + 54f8235 commit 4a41afc
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.quarkus.it.extension.testresources;

import static java.util.Objects.requireNonNull;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

public class SharedResource implements QuarkusTestResourceLifecycleManager {
private String argument;

@Override
public void init(Map<String, String> initArgs) {
this.argument = requireNonNull(initArgs.get("resource.arg"));
}

@Override
public Map<String, String> start() {
System.err.println(getClass().getSimpleName() + " start with arg '" + argument + "'");
return Map.of();
}

@Override
public void stop() {
System.err.println(getClass().getSimpleName() + " stop");
}

@Override
public void inject(TestInjector testInjector) {
testInjector.injectIntoFields(argument,
new TestInjector.AnnotatedAndMatchesType(SharedResourceAnnotation.class, String.class));
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SharedResourceAnnotation {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.it.extension.testresources;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

public class SomeResource1 implements QuarkusTestResourceLifecycleManager {
@Override
public Map<String, String> start() {
System.err.println(getClass().getSimpleName() + " start");
return Map.of();
}

@Override
public void stop() {
System.err.println(getClass().getSimpleName() + " stop");
}

@Override
public void inject(TestInjector testInjector) {
testInjector.injectIntoFields(getClass().getSimpleName(),
new TestInjector.AnnotatedAndMatchesType(Resource1Annotation.class, String.class));
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resource1Annotation {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.it.extension.testresources;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

public class SomeResource2 implements QuarkusTestResourceLifecycleManager {
@Override
public Map<String, String> start() {
System.err.println(getClass().getSimpleName() + " start");
return Map.of();
}

@Override
public void stop() {
System.err.println(getClass().getSimpleName() + " stop");
}

@Override
public void inject(TestInjector testInjector) {
testInjector.injectIntoFields(getClass().getSimpleName(),
new TestInjector.AnnotatedAndMatchesType(Resource2Annotation.class, String.class));
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resource2Annotation {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.it.extension.testresources;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;

import org.junit.jupiter.api.Test;

import io.quarkus.test.common.ResourceArg;
import io.quarkus.test.common.TestResourceScope;
import io.quarkus.test.common.WithTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@WithTestResource(value = SomeResource1.class, scope = TestResourceScope.MATCHING_RESOURCES)
@WithTestResource(value = SharedResource.class, scope = TestResourceScope.MATCHING_RESOURCES, initArgs = {
@ResourceArg(name = "resource.arg", value = "test-one") })
public class WithResourcesPoliciesFirstTest {
@SomeResource1.Resource1Annotation
String resource1;
@SomeResource2.Resource2Annotation
String resource2;
@SharedResource.SharedResourceAnnotation
String sharedResource;

@Test
public void checkOnlyResource1started() {
assertThat(Arrays.asList(resource1, resource2, sharedResource)).isEqualTo(
Arrays.asList("SomeResource1", null, "test-one"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.it.extension.testresources;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;

import org.junit.jupiter.api.Test;

import io.quarkus.test.common.ResourceArg;
import io.quarkus.test.common.TestResourceScope;
import io.quarkus.test.common.WithTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@WithTestResource(value = SomeResource2.class, scope = TestResourceScope.MATCHING_RESOURCES)
@WithTestResource(value = SharedResource.class, scope = TestResourceScope.MATCHING_RESOURCES, initArgs = {
@ResourceArg(name = "resource.arg", value = "test-two") })
public class WithResourcesPoliciesSecondTest {
@SomeResource1.Resource1Annotation
String resource1;
@SomeResource2.Resource2Annotation
String resource2;
@SharedResource.SharedResourceAnnotation
String sharedResource;

@Test
public void checkOnlyResource1started() {
assertThat(Arrays.asList(resource1, resource2, sharedResource)).isEqualTo(
Arrays.asList(null, "SomeResource2", "test-two"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public TestResourceManager(Class<?> testClass,
this.testResourceComparisonInfo = new HashSet<>();
for (TestResourceClassEntry uniqueEntry : uniqueEntries) {
testResourceComparisonInfo.add(new TestResourceComparisonInfo(
uniqueEntry.testResourceLifecycleManagerClass().getName(), uniqueEntry.getScope()));
uniqueEntry.testResourceLifecycleManagerClass().getName(), uniqueEntry.getScope(), uniqueEntry.args));
}

Set<TestResourceClassEntry> remainingUniqueEntries = initParallelTestResources(uniqueEntries);
Expand Down Expand Up @@ -326,7 +326,8 @@ public static Set<TestResourceManager.TestResourceComparisonInfo> testResourceCo
}
Set<TestResourceManager.TestResourceComparisonInfo> result = new HashSet<>(uniqueEntries.size());
for (TestResourceClassEntry entry : uniqueEntries) {
result.add(new TestResourceComparisonInfo(entry.testResourceLifecycleManagerClass().getName(), entry.getScope()));
result.add(new TestResourceComparisonInfo(entry.testResourceLifecycleManagerClass().getName(), entry.getScope(),
entry.args));
}
return result;
}
Expand Down Expand Up @@ -439,23 +440,23 @@ private static void addTestResourceEntry(QuarkusTestResource quarkusTestResource

private static Collection<AnnotationInstance> findTestResourceInstancesOfClass(Class<?> testClass, IndexView index) {
// collect all test supertypes for matching per-test targets
Set<String> testClasses = new HashSet<>();
Set<String> currentTestClassHierarchy = new HashSet<>();
Class<?> current = testClass;
while (current != Object.class) {
testClasses.add(current.getName());
currentTestClassHierarchy.add(current.getName());
current = current.getSuperclass();
}
current = testClass.getEnclosingClass();
while (current != null) {
testClasses.add(current.getName());
currentTestClassHierarchy.add(current.getName());
current = current.getEnclosingClass();
}

Set<AnnotationInstance> testResourceAnnotations = new LinkedHashSet<>();

for (DotName testResourceClasses : List.of(WITH_TEST_RESOURCE, QUARKUS_TEST_RESOURCE)) {
for (AnnotationInstance annotation : index.getAnnotations(testResourceClasses)) {
if (keepTestResourceAnnotation(annotation, annotation.target().asClass(), testClasses)) {
if (keepTestResourceAnnotation(annotation, annotation.target().asClass(), currentTestClassHierarchy)) {
testResourceAnnotations.add(annotation);
}
}
Expand All @@ -466,7 +467,8 @@ private static Collection<AnnotationInstance> findTestResourceInstancesOfClass(C
for (AnnotationInstance annotation : index.getAnnotations(testResourceListClasses)) {
for (AnnotationInstance nestedAnnotation : annotation.value().asNestedArray()) {
// keep the list target
if (keepTestResourceAnnotation(nestedAnnotation, annotation.target().asClass(), testClasses)) {
if (keepTestResourceAnnotation(nestedAnnotation, annotation.target().asClass(),
currentTestClassHierarchy)) {
testResourceAnnotations.add(nestedAnnotation);
}
}
Expand All @@ -477,21 +479,22 @@ private static Collection<AnnotationInstance> findTestResourceInstancesOfClass(C
}

private static boolean keepTestResourceAnnotation(AnnotationInstance annotation, ClassInfo targetClass,
Set<String> testClasses) {
Set<String> currentTestClassHierarchy) {
if (targetClass.isAnnotation()) {
// meta-annotations have already been handled in collectMetaAnnotations
return false;
}

if (restrictToAnnotatedClass(annotation)) {
return testClasses.contains(targetClass.name().toString('.'));
return currentTestClassHierarchy.contains(targetClass.name().toString('.'));
}

return true;
}

private static boolean restrictToAnnotatedClass(AnnotationInstance annotation) {
return TestResourceClassEntryHandler.determineScope(annotation) == RESTRICTED_TO_CLASS;
return TestResourceClassEntryHandler.determineScope(annotation) == RESTRICTED_TO_CLASS
|| TestResourceClassEntryHandler.determineScope(annotation) == MATCHING_RESOURCES;
}

/**
Expand All @@ -516,7 +519,7 @@ public static boolean testResourcesRequireReload(Set<TestResourceComparisonInfo>
return false;
}

if (hasRestrictedToClassScope(existing) || hasRestrictedToClassScope(next)) {
if (anyResourceRestrictedToClass(existing) || anyResourceRestrictedToClass(next)) {
return true;
}

Expand All @@ -538,8 +541,8 @@ public static boolean testResourcesRequireReload(Set<TestResourceComparisonInfo>
return false;
}

private static boolean hasRestrictedToClassScope(Set<TestResourceComparisonInfo> existing) {
for (TestResourceComparisonInfo info : existing) {
private static boolean anyResourceRestrictedToClass(Set<TestResourceComparisonInfo> testResources) {
for (TestResourceComparisonInfo info : testResources) {
if (info.scope == RESTRICTED_TO_CLASS) {
return true;
}
Expand Down Expand Up @@ -603,7 +606,8 @@ public TestResourceScope getScope() {
}
}

public record TestResourceComparisonInfo(String testResourceLifecycleManagerClass, TestResourceScope scope) {
public record TestResourceComparisonInfo(String testResourceLifecycleManagerClass, TestResourceScope scope,
Map<String, String> args) {

}

Expand Down
Loading

0 comments on commit 4a41afc

Please sign in to comment.