Skip to content
Draft
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
7 changes: 7 additions & 0 deletions platform/org.eclipse.platform.testing/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
34 changes: 34 additions & 0 deletions platform/org.eclipse.platform.testing/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.platform.testing</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
</natures>
</projectDescription>
11 changes: 11 additions & 0 deletions platform/org.eclipse.platform.testing/.settings/.api_filters
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.platform.testing" version="2">
<resource path="src/org/eclipse/platform/testing/EclipseApplicationLauncher.java" type="org.eclipse.platform.testing.EclipseApplicationLauncher">
<filter id="574619656">
<message_arguments>
<message_argument value="ApplicationLauncher"/>
<message_argument value="EclipseApplicationLauncher"/>
</message_arguments>
</filter>
</resource>
</component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=21
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
eclipse.preferences.version=1
pluginProject.equinox=false
pluginProject.extensions=false
resolve.requirebundle=false
17 changes: 17 additions & 0 deletions platform/org.eclipse.platform.testing/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Testing Support for Eclipse Applications
Bundle-SymbolicName: org.eclipse.platform.testing
Bundle-Version: 1.0.0.qualifier
Automatic-Module-Name: org.eclipse.platform.testing
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-21
Import-Package: org.eclipse.osgi.service.runnable;version="[1.1.0,2.0.0)",
org.junit.jupiter.api.extension;version="[5.14.0,6.0.0)",
org.junit.platform.launcher;version="[1.14.0,2.0.0)",
org.osgi.framework;version="[1.10.0,2.0.0)",
org.osgi.util.tracker;version="[1.5.0,2.0.0)"
Require-Bundle: org.eclipse.equinox.common;bundle-version="3.20.300",
org.eclipse.e4.ui.workbench3,
org.eclipse.equinox.app
Export-Package: org.eclipse.platform.testing
5 changes: 5 additions & 0 deletions platform/org.eclipse.platform.testing/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
tycho.pomless.parent = ../../
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.platform.testing.EclipseInvocationInterceptor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.platform.testing.EclipseLauncherSessionListener
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.platform.testing;

import org.eclipse.osgi.service.runnable.ApplicationLauncher;
import org.eclipse.osgi.service.runnable.ParameterizedRunnable;

class EclipseApplicationLauncher implements ApplicationLauncher {

@Override
public void launch(ParameterizedRunnable runnable, Object context) {

}

@Override
public void shutdown() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.platform.testing;

import java.lang.reflect.Method;

import org.eclipse.pde.api.tools.annotations.NoInstantiate;
import org.eclipse.pde.api.tools.annotations.NoReference;
import org.eclipse.ui.testing.TestableObject;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.util.tracker.ServiceTracker;

/**
* An {@link InvocationInterceptor} that executes all tests inside the
* {@link TestableObject#runTest(Runnable)} method.
*/
@NoInstantiate
public class EclipseInvocationInterceptor implements InvocationInterceptor {

private final ServiceTracker<TestableObject, TestableObject> testableObjectTracker;
private final TestableObject testableObject;

/**
* Creates the extension, will be called by JUnit
*/
public EclipseInvocationInterceptor() {
Bundle bundle = FrameworkUtil.getBundle(EclipseLauncherSessionListener.class);
if (bundle == null) {
throw new IllegalStateException("Not running inside an OSGi Framework");
}
BundleContext bundleContext = bundle.getBundleContext();
if (bundleContext == null) {
throw new IllegalStateException("Extension Bundle not started");
}
testableObjectTracker = new ServiceTracker<>(bundleContext, TestableObject.class, null);
testableObjectTracker.open();
testableObject = testableObjectTracker.getService();
if (testableObject == null) {
throw new IllegalStateException("Testable Object not found!");
}
}

@Override
@NoReference
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) throws Throwable {
Throwable[] throwable = new Throwable[1];
TestableObject service = testableObjectTracker.getService();
if (service != null) {
service.runTest(() -> {
try {
invocation.proceed();
} catch (Throwable e) {
throwable[0] = e;
}
});
Throwable t = throwable[0];
if (t == null) {
return;
}
throw t;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.eclipse.platform.testing;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.osgi.service.runnable.ApplicationLauncher;
import org.eclipse.osgi.service.runnable.ParameterizedRunnable;
import org.eclipse.pde.api.tools.annotations.NoInstantiate;
import org.eclipse.pde.api.tools.annotations.NoReference;
import org.eclipse.ui.testing.ITestHarness;
import org.eclipse.ui.testing.TestableObject;
import org.junit.platform.launcher.LauncherSession;
import org.junit.platform.launcher.LauncherSessionListener;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.application.ApplicationDescriptor;
import org.osgi.service.application.ApplicationException;
import org.osgi.service.application.ApplicationHandle;
import org.osgi.util.tracker.ServiceTracker;

/**
*
*/
@NoInstantiate
public class EclipseLauncherSessionListener implements LauncherSessionListener {

private TestableObject testableObject;
private ApplicationHandle applicationHandle;
private ServiceTracker<TestableObject, TestableObject> testableObjectTracker;
private ServiceTracker<ApplicationDescriptor, ApplicationDescriptor> applicationDescriptorTracker;
private ServiceRegistration<?> applicationService;
private Thread applicationThread;


@Override
@NoReference
public void launcherSessionOpened(LauncherSession session) {
Bundle bundle = FrameworkUtil.getBundle(EclipseLauncherSessionListener.class);
if (bundle == null) {
System.err.println("Not running inside OSGi!");
return;
}
BundleContext bundleContext = bundle.getBundleContext();
if (bundleContext == null) {
System.err.println("Not started/resolved?");
return;
}
EclipseApplicationLauncher launcher = new EclipseApplicationLauncher();
applicationService = bundleContext.registerService(ApplicationLauncher.class, launcher, null);
testableObjectTracker = new ServiceTracker<>(bundleContext, TestableObject.class, null);
applicationDescriptorTracker = new ServiceTracker<>(bundleContext, ApplicationDescriptor.class, null);
applicationDescriptorTracker.open();
testableObjectTracker.open();
String testApplication = "org.eclipse.ui.ide.workbench"; // TODO how to access the JUnit config of the
// session?!?
Map<String, ApplicationDescriptor> tracked = applicationDescriptorTracker.getTracked().entrySet().stream()
.collect(Collectors.toMap(e -> (String) e.getKey().getProperty(ApplicationDescriptor.APPLICATION_PID),
e -> e.getValue()));
ApplicationDescriptor applicationDescriptor = tracked.get(testApplication);
if (applicationDescriptor == null) {
System.err.println("Test application '" + testApplication + "' was not found available applications are:");
for (String appId : tracked.keySet()) {
System.err.println("\t- " + appId);
}
return;
}
testableObject = testableObjectTracker.getService();
if (testableObject == null) {
System.err.println("No TestableObject found!");
return;
}
CountDownLatch latch = new CountDownLatch(1);
testableObject.setTestHarness(new ITestHarness() {

@Override
public void runTests() {
latch.countDown();
}
});
HashMap<String, Object> launchArgs = new HashMap<>(1);
String[] args = new String[0];
launchArgs.put(IApplicationContext.APPLICATION_ARGS, args);
try {
applicationHandle = applicationDescriptor.launch(launchArgs);
} catch (ApplicationException e) {
e.printStackTrace();
return;
}
if (applicationHandle instanceof ParameterizedRunnable runable) {
applicationThread = new Thread(new Runnable() {

@Override
public void run() {
try {
runable.run(args);
} catch (Exception e) {
e.printStackTrace();
}
}
});
applicationThread.setName("Eclipse-Test-Application [" + testApplication + "]");
applicationThread.setDaemon(true);
applicationThread.start();
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

@Override
@NoReference
public void launcherSessionClosed(LauncherSession session) {
if (testableObject != null) {
testableObject.testingFinished();
}
if (testableObjectTracker != null) {
testableObjectTracker.close();
}
if (applicationDescriptorTracker != null) {
applicationDescriptorTracker.close();
}
if (applicationService != null) {
applicationService.unregister();
}
if (applicationThread != null) {
try {
applicationThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

}
4 changes: 3 additions & 1 deletion team/tests/org.eclipse.compare.tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ Require-Bundle: org.eclipse.compare,
org.eclipse.core.tests.resources,
org.eclipse.core.tests.harness,
org.eclipse.core.filesystem,
org.eclipse.team.ui
org.eclipse.team.ui,
org.eclipse.platform.testing,
org.eclipse.ui.ide.application;bundle-version="1.5.900"
Comment on lines +17 to +18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those really necessary? Couldn't they be added as requirements in build.properties or pom.xml instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently a bit work in progress and I just wanted it to run, the first is likely not required and the second would better be an additional requirement in the target platform.

Import-Package: org.assertj.core.api,
org.assertj.core.api.iterable,
org.junit.jupiter.api;version="[5.14.0,6.0.0)",
Expand Down
2 changes: 1 addition & 1 deletion team/tests/org.eclipse.compare.tests/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ output.. = bin/

# Maven/Tycho pom model adjustments
pom.model.property.testClass = org.eclipse.compare.tests.AllCompareTests
pom.model.property.tycho.surefire.useUIHarness = true
pom.model.property.tycho.surefire.useUIHarness = false
Loading
Loading