Skip to content

Commit c9454a2

Browse files
committed
Limit access to junit platform engines
Currently the testruntime is exposed to multiple engines and the check for compatibility does not work well in the case of JUnit 5/6 on the classpath. This now - limit the dynamic import to a range of the currently only supported junit 5 - remove the falsely check for compatible engines - enhance the multi-bundle classloader to not expose META-INF/services/* from bundles not strictly classloader compatible for the given service interface
1 parent e5ecc3a commit c9454a2

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

ui/org.eclipse.pde.junit.runtime/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ Export-Package: org.eclipse.pde.internal.junit.runtime;x-internal:=true
1212
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
1313
Bundle-ActivationPolicy: lazy
1414
Import-Package: org.eclipse.ui.testing;resolution:=optional
15-
DynamicImport-Package: org.junit.platform.engine
15+
DynamicImport-Package: org.junit.platform.engine;version="[1.14.0,2.0.0)"
1616
Automatic-Module-Name: org.eclipse.pde.junit.runtime

ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/MultiBundleClassLoader.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,22 @@
2222

2323
import org.eclipse.core.runtime.FileLocator;
2424
import org.osgi.framework.Bundle;
25+
import org.osgi.framework.FrameworkUtil;
2526

2627
class MultiBundleClassLoader extends ClassLoader {
28+
29+
private static final String META_INF_SERVICES = "META-INF/services/"; //$NON-NLS-1$
2730
private final List<Bundle> bundleList;
31+
private Bundle runtimeBundle;
2832

29-
public MultiBundleClassLoader(List<Bundle> platformEngineBundles) {
33+
public MultiBundleClassLoader(List<Bundle> platformEngineBundles, Bundle runtimeBundle) {
3034
super(null); // never delegate to system classloader, only load classes via given Bundles
3135
this.bundleList = platformEngineBundles;
36+
if (runtimeBundle == null) {
37+
this.runtimeBundle = FrameworkUtil.getBundle(RemotePluginTestRunner.class);
38+
} else {
39+
this.runtimeBundle = runtimeBundle;
40+
}
3241
}
3342

3443
@Override
@@ -63,12 +72,29 @@ protected URL findResource(String name) {
6372
@Override
6473
protected Enumeration<URL> findResources(String name) throws IOException {
6574
List<URL> merged = new ArrayList<>();
75+
6676
for (Bundle bundle : bundleList) {
67-
Enumeration<URL> resources = bundle.getResources(name);
68-
while (resources != null && resources.hasMoreElements()) {
69-
merged.add(FileLocator.resolve(resources.nextElement()));
77+
if (name.startsWith(META_INF_SERVICES)) {
78+
String serviceName = name.substring(META_INF_SERVICES.length());
79+
if (!isCompatible(bundle, serviceName, runtimeBundle)) {
80+
//do not expose SPI services to incompatible bundles!
81+
continue;
82+
83+
}
84+
Enumeration<URL> resources = bundle.getResources(name);
85+
while (resources != null && resources.hasMoreElements()) {
86+
merged.add(FileLocator.resolve(resources.nextElement()));
87+
}
7088
}
7189
}
7290
return Collections.enumeration(merged);
7391
}
92+
93+
private static boolean isCompatible(Bundle bundle, String serviceName, Bundle callingBundle) {
94+
try {
95+
return bundle.loadClass(serviceName) == callingBundle.loadClass(serviceName);
96+
} catch (ClassNotFoundException e) {
97+
return false;
98+
}
99+
}
74100
}

ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/RemotePluginTestRunner.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,35 +143,23 @@ private static ClassLoader createJUnit5PluginClassLoader(String testPluginName)
143143
if (junit5RuntimeBundle != null) {
144144
platformEngineBundles.add(junit5RuntimeBundle);
145145
}
146-
return new MultiBundleClassLoader(platformEngineBundles);
146+
return new MultiBundleClassLoader(platformEngineBundles, junit5RuntimeBundle);
147147
}
148148

149149
private static List<Bundle> findTestEngineBundles() {
150150
BundleContext bundleContext = FrameworkUtil.getBundle(RemotePluginTestRunner.class).getBundleContext();
151-
return Arrays.stream(bundleContext.getBundles()).filter(RemotePluginTestRunner::providesCompatibleTestEngine).collect(toCollection(ArrayList::new));
151+
return Arrays.stream(bundleContext.getBundles()).filter(RemotePluginTestRunner::providesTestEngine).collect(toCollection(ArrayList::new));
152152
}
153153

154154
/**
155155
* Checks whether the bundle provides test engines.
156-
* Ensures that test engines that can be loaded from the bundle
157-
* are compatible with the TestEngine version in current scope.
158-
* Otherwise, the JUnit platform's call to the ServiceLoader for
159-
* retrieving available engines will fail.
160-
* Incompatibilities can happen, e.g., in Tycho builds, where
161-
* the org.eclipse.tycho.surefire.osgibooter bundle is found
162-
* that may provide a different JUnit platform version than the
163-
* one available via the Eclipse target platform.
164156
*/
165-
private static boolean providesCompatibleTestEngine(Bundle bundle) {
157+
private static boolean providesTestEngine(Bundle bundle) {
166158
try {
167159
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
168160
String testEngineClass = "org.junit.platform.engine.TestEngine"; //$NON-NLS-1$
169161
Collection<String> engineProviders = bundleWiring.listResources("META-INF/services", testEngineClass, BundleWiring.LISTRESOURCES_LOCAL); //$NON-NLS-1$
170-
if (!engineProviders.isEmpty()) {
171-
Class<?> thisTestEngine = Class.forName(testEngineClass);
172-
Class<?> bundleTestEngine = bundle.loadClass(testEngineClass);
173-
return thisTestEngine == bundleTestEngine;
174-
}
162+
return !engineProviders.isEmpty();
175163
} catch (Exception e) {
176164
// skip this bundle
177165
}
@@ -204,7 +192,8 @@ public void init(String[] args) {
204192
// during initialization - see bug 520811
205193
ClassLoader currentTCCL = Thread.currentThread().getContextClassLoader();
206194
try {
207-
Thread.currentThread().setContextClassLoader(new MultiBundleClassLoader(findTestEngineBundles()));
195+
Bundle junit5RuntimeBundle = Platform.getBundle("org.eclipse.jdt.junit5.runtime"); //$NON-NLS-1$
196+
Thread.currentThread().setContextClassLoader(new MultiBundleClassLoader(findTestEngineBundles(), junit5RuntimeBundle));
208197
defaultInit(args);
209198
} finally {
210199
Thread.currentThread().setContextClassLoader(currentTCCL);

0 commit comments

Comments
 (0)