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

Fix wrong TestInfo test method in @Before/AfterEach #19751

Merged
merged 1 commit into from
Aug 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
Expand All @@ -22,11 +27,29 @@
@QuarkusTest
public class QuarkusTestCallbacksTestCase {

@BeforeEach
void beforeEachWithTestInfo(TestInfo testInfo) throws NoSuchMethodException {
checkBeforeOrAfterEachTestInfo(testInfo, "beforeEachWithTestInfo");
}

@AfterEach
void afterEachWithTestInfo(TestInfo testInfo) throws NoSuchMethodException {
checkBeforeOrAfterEachTestInfo(testInfo, "afterEachWithTestInfo");
}

private void checkBeforeOrAfterEachTestInfo(TestInfo testInfo, String unexpectedMethodName) throws NoSuchMethodException {
assertNotNull(testInfo);
String testMethodName = testInfo.getTestMethod().get().getName();
assertNotEquals(testMethodName,
QuarkusTestCallbacksTestCase.class.getDeclaredMethod(unexpectedMethodName, TestInfo.class));
assertTrue(testMethodName.startsWith("test"));
}

@Test
@TestAnnotation
@Order(1)
public void testTestMethodHasAnnotation() {

assertTrue(SimpleAnnotationCheckerBeforeEachCallback.testAnnotationChecked);
}

@Test
Expand All @@ -36,11 +59,13 @@ public void testBeforeClass() {
}

@Test
@TestAnnotation
@Order(3)
public void testInfoTestCase(TestInfo testInfo) throws NoSuchMethodException {
Assertions.assertEquals(testInfo.getTestClass().get(), QuarkusTestCallbacksTestCase.class);
Assertions.assertEquals(testInfo.getTestMethod().get(),
QuarkusTestCallbacksTestCase.class.getDeclaredMethod("testInfoTestCase", TestInfo.class));
assertEquals(testInfo.getTestClass().get(), QuarkusTestCallbacksTestCase.class);
Method testMethod = testInfo.getTestMethod().get();
assertEquals(testMethod, QuarkusTestCallbacksTestCase.class.getDeclaredMethod("testInfoTestCase", TestInfo.class));
assertEquals(1, testMethod.getAnnotationsByType(TestAnnotation.class).length);
}

@Target({ METHOD })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

public class SimpleAnnotationCheckerBeforeEachCallback implements QuarkusTestBeforeEachCallback {

static boolean testAnnotationChecked;

@Override
public void beforeEach(QuarkusTestMethodContext context) {
// make sure that this comes into play only for the test we care about
Expand All @@ -26,5 +28,6 @@ public void beforeEach(QuarkusTestMethodContext context) {
throw new IllegalStateException(
"Expected to find annotation @TestAnnotation on method test method testTestMethodHasAnnotation");
}
testAnnotationChecked = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -196,6 +197,8 @@ public void run() {
}
};

private final IdentityHashMap<Method, Method> tcclMethodCache = new IdentityHashMap<>();
famod marked this conversation as resolved.
Show resolved Hide resolved

static {
ClassLoader classLoader = QuarkusTestExtension.class.getClassLoader();
if (classLoader instanceof QuarkusClassLoader) {
Expand Down Expand Up @@ -430,6 +433,7 @@ public void close() throws IOException {
}
tm.close();
} finally {
tcclMethodCache.clear();
GroovyCacheCleaner.clearGroovyCache();
if (hangTaskKey != null) {
hangTaskKey.cancel(true);
Expand Down Expand Up @@ -988,13 +992,13 @@ private Object runExtensionMethod(ReflectiveInvocationContext<Method> invocation
try {
Class<?> testClassFromTCCL = Class.forName(extensionContext.getRequiredTestClass().getName(), true,
Thread.currentThread().getContextClassLoader());
Method newMethod = determineTCCLExtensionMethod(invocationContext, testClassFromTCCL);
Method newMethod = determineTCCLExtensionMethod(invocationContext.getExecutable(), testClassFromTCCL);
boolean methodFromEnclosing = false;
// this is needed to support before*** and after*** methods that are part of class that encloses the test class
// (the test class is in this case a @Nested test)
if ((newMethod == null) && (testClassFromTCCL.getEnclosingClass() != null)) {
testClassFromTCCL = testClassFromTCCL.getEnclosingClass();
newMethod = determineTCCLExtensionMethod(invocationContext, testClassFromTCCL);
newMethod = determineTCCLExtensionMethod(invocationContext.getExecutable(), testClassFromTCCL);
methodFromEnclosing = true;
}
if (newMethod == null) {
Expand Down Expand Up @@ -1035,8 +1039,9 @@ private Object runExtensionMethod(ReflectiveInvocationContext<Method> invocation
cloneRequired = false;
} else if (TestInfo.class.isAssignableFrom(theclass)) {
TestInfo info = (TestInfo) arg;
Method newTestMethod = determineTCCLExtensionMethod(info.getTestMethod().get(), testClassFromTCCL);
replacement = new TestInfoImpl(info.getDisplayName(), info.getTags(), Optional.of(testClassFromTCCL),
Optional.of(newMethod));
Optional.of(newTestMethod));
} else if (clonePattern.matcher(className).matches()) {
cloneRequired = true;
} else {
Expand Down Expand Up @@ -1089,13 +1094,16 @@ private Object runExtensionMethod(ReflectiveInvocationContext<Method> invocation
}
}

private Method determineTCCLExtensionMethod(ReflectiveInvocationContext<Method> invocationContext, Class<?> c)
private Method determineTCCLExtensionMethod(Method originalMethod, Class<?> c)
throws ClassNotFoundException {
Method newMethod = null;
Method newMethod = tcclMethodCache.get(originalMethod);
if (newMethod != null) {
return newMethod;
}
while (c != Object.class) {
if (c.getName().equals(invocationContext.getExecutable().getDeclaringClass().getName())) {
if (c.getName().equals(originalMethod.getDeclaringClass().getName())) {
try {
Class<?>[] originalParameterTypes = invocationContext.getExecutable().getParameterTypes();
Class<?>[] originalParameterTypes = originalMethod.getParameterTypes();
List<Class<?>> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length);
for (Class<?> type : originalParameterTypes) {
if (type.isPrimitive()) {
Expand All @@ -1106,7 +1114,7 @@ private Method determineTCCLExtensionMethod(ReflectiveInvocationContext<Method>
Thread.currentThread().getContextClassLoader()));
}
}
newMethod = c.getDeclaredMethod(invocationContext.getExecutable().getName(),
newMethod = c.getDeclaredMethod(originalMethod.getName(),
parameterTypesFromTccl.toArray(new Class[0]));
break;
} catch (NoSuchMethodException ignored) {
Expand All @@ -1115,6 +1123,7 @@ private Method determineTCCLExtensionMethod(ReflectiveInvocationContext<Method>
}
c = c.getSuperclass();
}
tcclMethodCache.put(originalMethod, newMethod);
return newMethod;
}

Expand Down