Skip to content

Commit a08c827

Browse files
committed
Revert "Revert #40601 and disable tests enabled by #40749"
This reverts commit fc3988b. It has some additional changes which re-revert part of #40601, to reintroduce removed guards to avoid cloning things like Quarkus runtime classes. Otherwise we get test failures.
1 parent c20fa84 commit a08c827

File tree

13 files changed

+128
-352
lines changed

13 files changed

+128
-352
lines changed

bom/application/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,6 +4848,11 @@
48484848
<type>pom</type>
48494849
</dependency>
48504850

4851+
<dependency>
4852+
<groupId>org.jboss.marshalling</groupId>
4853+
<artifactId>jboss-marshalling</artifactId>
4854+
<version>${jboss-marshalling.version}</version>
4855+
</dependency>
48514856
<dependency>
48524857
<groupId>org.jboss.threads</groupId>
48534858
<artifactId>jboss-threads</artifactId>

integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/it/TestParameterDevModeIT.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import org.apache.maven.shared.invoker.MavenInvocationException;
99
import org.junit.jupiter.api.Assertions;
10-
import org.junit.jupiter.api.Disabled;
1110
import org.junit.jupiter.api.Test;
1211
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
1312

@@ -22,7 +21,6 @@
2221
* mvn install -Dit.test=DevMojoIT#methodName
2322
*/
2423
@DisabledIfSystemProperty(named = "quarkus.test.native", matches = "true")
25-
@Disabled("Needs https://github.com/junit-team/junit5/pull/3820 and #40601")
2624
public class TestParameterDevModeIT extends RunAndCheckMojoTestBase {
2725

2826
protected int getPort() {

test-framework/junit5/pom.xml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@
4949
<artifactId>quarkus-core</artifactId>
5050
</dependency>
5151
<dependency>
52-
<groupId>com.thoughtworks.xstream</groupId>
53-
<artifactId>xstream</artifactId>
54-
<!-- Avoid adding this to the BOM -->
55-
<version>1.4.20</version>
52+
<groupId>org.jboss.marshalling</groupId>
53+
<artifactId>jboss-marshalling</artifactId>
5654
</dependency>
5755

5856
<dependency>

test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@
106106
import io.quarkus.test.junit.callback.QuarkusTestContext;
107107
import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
108108
import io.quarkus.test.junit.internal.DeepClone;
109-
import io.quarkus.test.junit.internal.SerializationWithXStreamFallbackDeepClone;
109+
import io.quarkus.test.junit.internal.NewSerializingDeepClone;
110+
import io.quarkus.test.junit.internal.TestInfoImpl;
110111

111112
public class QuarkusTestExtension extends AbstractJvmQuarkusTestExtension
112113
implements BeforeEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterEachCallback,
@@ -351,7 +352,7 @@ private void shutdownHangDetection() {
351352
}
352353

353354
private void populateDeepCloneField(StartupAction startupAction) {
354-
deepClone = new SerializationWithXStreamFallbackDeepClone(startupAction.getClassLoader());
355+
deepClone = new NewSerializingDeepClone(originalCl, startupAction.getClassLoader());
355356
}
356357

357358
private void populateTestMethodInvokers(ClassLoader quarkusClassLoader) {
@@ -979,6 +980,7 @@ private Object runExtensionMethod(ReflectiveInvocationContext<Method> invocation
979980
} else if (clonePattern.matcher(theclass.getName()).matches()) {
980981
cloneRequired = true;
981982
} else {
983+
// Don't clone things which are already loaded by the quarkus application's classloader side of the tree
982984
try {
983985
cloneRequired = runningQuarkusApplication.getClassLoader()
984986
.loadClass(theclass.getName()) != theclass;
@@ -1002,6 +1004,7 @@ private Object runExtensionMethod(ReflectiveInvocationContext<Method> invocation
10021004
} else {
10031005
argumentsFromTccl.add(arg);
10041006
}
1007+
10051008
}
10061009

10071010
if (testMethodInvokerToUse != null) {

test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomListConverter.java

Lines changed: 0 additions & 63 deletions
This file was deleted.

test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapConverter.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapEntryConverter.java

Lines changed: 0 additions & 55 deletions
This file was deleted.

test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomSetConverter.java

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.quarkus.test.junit.internal;
2+
3+
import java.io.IOException;
4+
import java.io.Serializable;
5+
import java.io.UncheckedIOException;
6+
import java.lang.reflect.Method;
7+
import java.util.Set;
8+
import java.util.function.Supplier;
9+
10+
import org.jboss.marshalling.cloner.ClassCloner;
11+
import org.jboss.marshalling.cloner.ClonerConfiguration;
12+
import org.jboss.marshalling.cloner.ObjectCloner;
13+
import org.jboss.marshalling.cloner.ObjectCloners;
14+
import org.junit.jupiter.api.TestInfo;
15+
16+
/**
17+
* A deep-clone implementation using JBoss Marshalling's fast object cloner.
18+
*/
19+
public final class NewSerializingDeepClone implements DeepClone {
20+
private final ObjectCloner cloner;
21+
22+
public NewSerializingDeepClone(final ClassLoader sourceLoader, final ClassLoader targetLoader) {
23+
ClonerConfiguration cc = new ClonerConfiguration();
24+
cc.setSerializabilityChecker(clazz -> clazz != Object.class);
25+
cc.setClassCloner(new ClassCloner() {
26+
public Class<?> clone(final Class<?> original) {
27+
if (isUncloneable(original)) {
28+
return original;
29+
}
30+
try {
31+
return targetLoader.loadClass(original.getName());
32+
} catch (ClassNotFoundException ignored) {
33+
return original;
34+
}
35+
}
36+
37+
public Class<?> cloneProxy(final Class<?> proxyClass) {
38+
// not really supported
39+
return proxyClass;
40+
}
41+
});
42+
cc.setCloneTable(
43+
(original, objectCloner, classCloner) -> {
44+
if (EXTRA_IDENTITY_CLASSES.contains(original.getClass())) {
45+
// avoid copying things that do not need to be copied
46+
return original;
47+
} else if (isUncloneable(original.getClass())) {
48+
if (original instanceof Supplier<?> s) {
49+
// sneaky
50+
return (Supplier<?>) () -> clone(s.get());
51+
} else {
52+
return original;
53+
}
54+
} else if (original instanceof TestInfo info) {
55+
// copy the test info correctly
56+
return new TestInfoImpl(info.getDisplayName(), info.getTags(),
57+
info.getTestClass().map(this::cloneClass),
58+
info.getTestMethod().map(this::cloneMethod));
59+
} else if (original == sourceLoader) {
60+
return targetLoader;
61+
}
62+
// let the default cloner handle it
63+
return null;
64+
});
65+
cloner = ObjectCloners.getSerializingObjectClonerFactory().createCloner(cc);
66+
}
67+
68+
private static boolean isUncloneable(Class<?> clazz) {
69+
return clazz.isHidden() && !Serializable.class.isAssignableFrom(clazz);
70+
}
71+
72+
private Class<?> cloneClass(Class<?> clazz) {
73+
try {
74+
return (Class<?>) cloner.clone(clazz);
75+
} catch (IOException | ClassNotFoundException e) {
76+
return null;
77+
}
78+
}
79+
80+
private Method cloneMethod(Method method) {
81+
try {
82+
Class<?> declaring = (Class<?>) cloner.clone(method.getDeclaringClass());
83+
Class<?>[] argTypes = (Class<?>[]) cloner.clone(method.getParameterTypes());
84+
return declaring.getDeclaredMethod(method.getName(), argTypes);
85+
} catch (Exception e) {
86+
return null;
87+
}
88+
}
89+
90+
public Object clone(final Object objectToClone) {
91+
try {
92+
return cloner.clone(objectToClone);
93+
} catch (IOException e) {
94+
throw new UncheckedIOException(e);
95+
} catch (ClassNotFoundException e) {
96+
throw new IllegalStateException(e);
97+
}
98+
}
99+
100+
/**
101+
* Classes which do not need to be cloned.
102+
*/
103+
private static final Set<Class<?>> EXTRA_IDENTITY_CLASSES = Set.of(
104+
Object.class,
105+
byte[].class,
106+
short[].class,
107+
int[].class,
108+
long[].class,
109+
char[].class,
110+
boolean[].class,
111+
float[].class,
112+
double[].class);
113+
}

0 commit comments

Comments
 (0)