diff --git a/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/Issue2082LaunchTest.java b/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/Issue2082LaunchTest.java new file mode 100644 index 00000000000..f02a224c3cf --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/Issue2082LaunchTest.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * 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: + * See git history + *******************************************************************************/ +package org.eclipse.pde.junit.runtime.tests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; + +import java.net.URL; +import java.util.Collections; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.junit.model.ITestElement.Result; +import org.eclipse.jdt.junit.model.ITestRunSession; +import org.eclipse.pde.ui.tests.util.ProjectUtils; +import org.eclipse.pde.ui.tests.util.TargetPlatformUtil; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * Test for issue #2082: Host bundles (even org.eclipse.osgi) leak into test + * launch config + *

+ * This test verifies that when launching a JUnit plugin test without + * org.eclipse.pde.feature.group in the target platform, the system bundle + * (org.eclipse.osgi) from the host is not exposed to avoid conflicts with the + * target platform's system bundle. + */ +public class Issue2082LaunchTest { + + @ClassRule + public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER; + + @BeforeClass + public static void setupProjects() throws Exception { + // Set up a target platform similar to issue #2082 scenario: + // - Include Eclipse platform bundles + // - Exclude org.eclipse.pde.feature.group to reproduce the issue scenario + // - Filter out PDE bundles (except core bundles needed for the test to run) + Pattern pdeIDs = Pattern.compile("org\\.eclipse\\.pde\\.(ui|build|launching|junit).*"); + TargetPlatformUtil.setRunningPlatformSubSetAsTarget("Issue2082_target", b -> { + // Exclude PDE UI/build/launching bundles but keep PDE core and test infrastructure + return !pdeIDs.matcher(b.getSymbolicName()).find(); + }); + + Bundle bundle = FrameworkUtil.getBundle(Issue2082LaunchTest.class); + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + for (URL resource : Collections.list(bundle.findEntries("test-bundles", "verification.tests.issue2082", false))) { + ProjectUtils.importTestProject(FileLocator.toFileURL(resource)); + } + workspaceRoot.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null); + } + + @Test + public void testIssue2082_systemBundleNotDuplicated() throws Exception { + // Test for https://github.com/eclipse-pde/eclipse.pde/issues/2082 + // Verify that launching a JUnit plugin test without org.eclipse.pde.feature.group + // in the target platform does not cause the host's org.eclipse.osgi to leak + // into the launch configuration, which would result in duplicate system bundles + // and launch errors. + + IJavaProject project = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject("verification.tests.issue2082")); + IType testClass = project.findType("verification.tests", "Test"); + assertNotNull("Test class should exist", testClass); + Assert.assertTrue("Test class should be valid", testClass.exists()); + + // Launch the test - this should succeed without errors + ITestRunSession session = TestExecutionUtil.runTest(testClass); + + // The test is expected to fail (as per the test code), but the important + // part is that the launch itself succeeds without duplicate bundle errors + assertThat(session.getChildren()).hasSize(1); + Result testResult = session.getTestResult(true); + // We expect FAILURE because the test code calls fail(), but we do NOT + // expect ERROR which would indicate a launch problem + assertThat(testResult).isIn(Result.FAILURE, Result.OK); + } +} diff --git a/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/JUnitRuntimeTests.java b/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/JUnitRuntimeTests.java index ba9ba65f00c..0cb0d2a52e9 100644 --- a/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/JUnitRuntimeTests.java +++ b/ui/org.eclipse.pde.junit.runtime.tests/src/org/eclipse/pde/junit/runtime/tests/JUnitRuntimeTests.java @@ -18,7 +18,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({ JUnitExecutionTest.class, JUnit5SuiteExecutionTest.class }) +@SuiteClasses({ JUnitExecutionTest.class, JUnit5SuiteExecutionTest.class, Issue2082LaunchTest.class }) public class JUnitRuntimeTests { } diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.classpath b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.classpath new file mode 100644 index 00000000000..3e5654f17eb --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.project b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.project new file mode 100644 index 00000000000..7c51ec082bd --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.project @@ -0,0 +1,28 @@ + + + verification.tests.issue2082 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..0c68a61dca8 --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..57dc8f132ce --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Issue 2082 Test +Bundle-SymbolicName: verification.tests.issue2082 +Bundle-Version: 1.0.0.qualifier +Automatic-Module-Name: verification.tests.issue2082 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: junit-jupiter-api;bundle-version="[5.4.0,6.0.0)" +Export-Package: verification.tests diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/build.properties b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/src/verification/tests/Test.java b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/src/verification/tests/Test.java new file mode 100644 index 00000000000..f3206fbd8ec --- /dev/null +++ b/ui/org.eclipse.pde.junit.runtime.tests/test-bundles/verification.tests.issue2082/src/verification/tests/Test.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * 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: + * See git history + *******************************************************************************/ +package verification.tests; + +import static org.junit.jupiter.api.Assertions.*; + +class Test { + + @org.junit.jupiter.api.Test + void test() { + fail("Not yet implemented"); + } + +} diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java index ea71155c92f..08396d3eb59 100644 --- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java +++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java @@ -1058,6 +1058,36 @@ public void testWriteBundleEntry_startLevelAndAutoStart() throws Exception { assertEquals("plugin.a*1.0.0@:false", BundleLauncherHelper.formatBundleEntry(plugin, null, "false")); } + // --- test cases for system bundle exclusion (issue #2082) --- + + @Test + public void testGetMergedBundleMap_systemBundleNotExposedFromHost() throws Exception { + // Test for https://github.com/eclipse-pde/eclipse.pde/issues/2082 + // When launching a JUnit plugin test without org.eclipse.pde.feature.group + // in the target platform, the system bundle (org.eclipse.osgi) from the + // host should NOT be exposed to avoid conflicts with the target platform's + // system bundle. Before the fix, this would cause duplicate system bundles + // and result in launch errors. + var workspacePlugins = ofEntries( // + bundle("plugin.a", "1.0.0", // + entry(REQUIRE_BUNDLE, IPDEBuildConstants.BUNDLE_OSGI))); + var targetPlatformBundles = ofEntries( // + bundle(IPDEBuildConstants.BUNDLE_OSGI, "3.18.0")); + + Consumer launchConfigSetup = wc -> { + wc.setAttribute(IPDELauncherConstants.SELECTED_WORKSPACE_BUNDLES, Set.of("plugin.a*1.0.0")); + wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, true); + }; + + // Expected: Only the system bundle from the target platform should be included. + // The system bundle from the host must NOT be included to avoid conflicts. + Set expectedBundles = Set.of( // + workspaceBundle("plugin.a", "1.0.0"), // + targetBundle(IPDEBuildConstants.BUNDLE_OSGI, "3.18.0")); + + assertGetMergedBundleMap(workspacePlugins, targetPlatformBundles, launchConfigSetup, expectedBundles); + } + // --- utilities --- private void assertGetMergedBundleMap(Map> workspacePlugins,