From 69eb1b7bcf20d6316a6d164c28de7fdbe083877e Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Fri, 12 Jan 2024 18:51:41 +0100 Subject: [PATCH] Provide only compatible JUnit 5 test engines in RemotePluginTestRunner Currently, it is possible that the RemotePluginTestRunner loads bundles with "incompatible" test engines. This means, the engine is version-incompatible with the TestEngine interface. In such a case, the execution will fail, because the ServiceLoader tries to load this engine as a provider for the TestEngine service but fails because it cannot assign the engine to the TestEngine interface. One such case is the execution of tests with Tycho, which can use a different JUnit version than the one used in the JDT test bundles. This change ensures that bundles providing incompatible engines are not added to the class loader used for executing the test to ensure that service loading for the engines does not fail. --- .../META-INF/MANIFEST.MF | 1 + .../junit/runtime/RemotePluginTestRunner.java | 40 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ui/org.eclipse.pde.junit.runtime/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.junit.runtime/META-INF/MANIFEST.MF index 9881e7736a..35cbed4063 100644 --- a/ui/org.eclipse.pde.junit.runtime/META-INF/MANIFEST.MF +++ b/ui/org.eclipse.pde.junit.runtime/META-INF/MANIFEST.MF @@ -12,4 +12,5 @@ Export-Package: org.eclipse.pde.internal.junit.runtime;x-internal:=true Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.ui.testing;resolution:=optional +DynamicImport-Package: org.junit.platform.engine Automatic-Module-Name: org.eclipse.pde.junit.runtime diff --git a/ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/RemotePluginTestRunner.java b/ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/RemotePluginTestRunner.java index fd223765a9..ab87c59cd6 100644 --- a/ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/RemotePluginTestRunner.java +++ b/ui/org.eclipse.pde.junit.runtime/src/org/eclipse/pde/internal/junit/runtime/RemotePluginTestRunner.java @@ -14,9 +14,12 @@ *******************************************************************************/ package org.eclipse.pde.internal.junit.runtime; +import static java.util.stream.Collectors.toCollection; + import java.io.IOException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.List; @@ -99,19 +102,34 @@ private static ClassLoader createJUnit5PluginClassLoader(String testPluginName) private static List findTestEngineBundles() { BundleContext bundleContext = FrameworkUtil.getBundle(RemotePluginTestRunner.class).getBundleContext(); - List engineBundles = new ArrayList<>(); - for (Bundle bundle : bundleContext.getBundles()) { - try { - BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); - Collection listResources = bundleWiring.listResources("META-INF/services", "org.junit.platform.engine.TestEngine", BundleWiring.LISTRESOURCES_LOCAL); //$NON-NLS-1$//$NON-NLS-2$ - if (!listResources.isEmpty()) { - engineBundles.add(bundle); - } - } catch (Exception e) { - // check the next bundle + return Arrays.stream(bundleContext.getBundles()).filter(RemotePluginTestRunner::providesCompatibleTestEngine).collect(toCollection(ArrayList::new)); + } + + /** + * Checks whether the bundle provides test engines. + * Ensures that test engines that can be loaded from the bundle + * are compatible with the TestEngine version in current scope. + * Otherwise, the JUnit platform's call to the ServiceLoader for + * retrieving available engines will fail. + * Incompatibilities can happen, e.g., in Tycho builds, where + * the org.eclipse.tycho.surefire.osgibooter bundle is found + * that may provide a different JUnit platform version than the + * one available via the Eclipse target platform. + */ + private static boolean providesCompatibleTestEngine(Bundle bundle) { + try { + BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); + String testEngineClass = "org.junit.platform.engine.TestEngine"; //$NON-NLS-1$ + Collection engineProviders = bundleWiring.listResources("META-INF/services", testEngineClass, BundleWiring.LISTRESOURCES_LOCAL); //$NON-NLS-1$ + if (!engineProviders.isEmpty()) { + Class thisTestEngine = Class.forName(testEngineClass); + Class bundleTestEngine = bundle.loadClass(testEngineClass); + return thisTestEngine == bundleTestEngine; } + } catch (Exception e) { + // skip this bundle } - return engineBundles; + return false; } /**