Bug 578005 - Extend tests to cover all feature-based launch attributes
I.e. all attributes supported at the moment.
Change-Id: I3b702315afa9c319bff77f075732ac993c342589
Signed-off-by: Hannes Wellmann <wellmann.hannes1@gmx.net>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/189226
Tested-by: PDE Bot <pde-bot@eclipse.org>
diff --git a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
index 1d451b3..a804e85 100644
--- a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
@@ -42,6 +42,7 @@
org.eclipse.pde.genericeditor.extension,
org.eclipse.equinox.simpleconfigurator.manipulator;bundle-version="2.1.300"
Import-Package: org.assertj.core.api;version="3.14.0",
+ org.assertj.core.presentation;version="3.21.0",
org.junit.jupiter.api.function;version="5.8.1"
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/ee/ExecutionEnvironmentTests.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/ee/ExecutionEnvironmentTests.java
index 96d4aca..444eea9 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/ee/ExecutionEnvironmentTests.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/ee/ExecutionEnvironmentTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2018 IBM Corporation and others.
+ * Copyright (c) 2008, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -195,7 +195,7 @@
@Test
public void testNoEnvironment() throws Exception {
try {
- IJavaProject project = ProjectUtils.createPluginProject("no.env", null);
+ IJavaProject project = ProjectUtils.createPluginProject("no.env", (IExecutionEnvironment) null);
assertTrue("Project was not created", project.exists());
Hashtable<String, String> options = JavaCore.getOptions();
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
index 9203ea4..3599d18 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Julian Honnen and others.
+ * Copyright (c) 2019, 2022 Julian Honnen and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -16,16 +16,21 @@
*******************************************************************************/
package org.eclipse.pde.ui.tests.launcher;
+import static java.util.Comparator.comparing;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.util.Arrays;
-import java.util.NoSuchElementException;
+import java.util.*;
+import java.util.Map.Entry;
import java.util.function.Function;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.assertj.core.presentation.StandardRepresentation;
import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.*;
import org.eclipse.pde.core.plugin.*;
+import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
@@ -50,7 +55,7 @@
@Rule
public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
- protected ILaunchConfiguration getLaunchConfiguration(String name) {
+ protected static ILaunchConfiguration getLaunchConfiguration(String name) {
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
return launchManager.getLaunchConfiguration(launchConfigsProject.getFile(name));
}
@@ -78,6 +83,57 @@
Stream<IPluginModelBase> candiates = Arrays.stream(models);
return candiates.filter(model -> version.equals(Version.parseVersion(model.getPluginBase().getVersion())))
.findFirst() // always take first like BundleLaunchHelper
- .orElseThrow(() -> new NoSuchElementException("No " + type + " model " + id + "-" + version + "found"));
+ .orElseThrow(
+ () -> new NoSuchElementException("No " + type + " model " + id + "-" + version + " found"));
}
+
+ static NameVersionDescriptor bundle(String id, String version) {
+ return new NameVersionDescriptor(id, version);
+ }
+
+ static BundleLocationDescriptor workspaceBundle(String id, String version) {
+ Objects.requireNonNull(version);
+ return () -> findWorkspaceModel(id, version);
+ }
+
+ static BundleLocationDescriptor targetBundle(String id, String version) {
+ Objects.requireNonNull(version);
+ // PluginRegistry.findModel does not consider external models when
+ // workspace models are present and returns the 'last' plug-in if
+ // multiple with the same version exist
+ return () -> findTargetModel(id, version);
+ }
+
+ static interface BundleLocationDescriptor {
+ IPluginModelBase findModel();
+ }
+
+ static void assertPluginMapsEquals(String message, Map<IPluginModelBase, String> expected,
+ Map<IPluginModelBase, String> actual) {
+ // Like Assert.assertEquals() but with more expressive and easier to
+ // compare failure message
+ Assertions.assertThat(actual).withRepresentation(new StandardRepresentation() {
+ @Override
+ public String toStringOf(Object object) {
+ if (object instanceof IPluginModelBase) {
+ IPluginModelBase plugin = (IPluginModelBase) object;
+ String location = plugin.getUnderlyingResource() != null ? "w" : "e";
+ IPluginBase p = plugin.getPluginBase();
+ return p.getId() + "-" + p.getVersion() + "(" + location + ")";
+ }
+ if (object instanceof Map) {
+ @SuppressWarnings("unchecked")
+ var entries = ((Map<IPluginModelBase, String>) object).entrySet().stream();
+ return entries.sorted(PLUGIN_COMPARATOR).map(super::toStringOf)
+ .collect(Collectors.joining(",\n", "{\n", "\n}"));
+ }
+ return super.toStringOf(object);
+ }
+ }).as(message).isEqualTo(expected);
+ }
+
+ private static final Comparator<Entry<IPluginModelBase, String>> PLUGIN_COMPARATOR = comparing(Entry::getKey,
+ comparing((IPluginModelBase p) -> p.getPluginBase(),
+ comparing(IPluginBase::getId).thenComparing(IPluginBase::getVersion))
+ .thenComparing((IPluginModelBase p) -> p.getUnderlyingResource() == null));
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
index f3df502..0cc80ba 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Julian Honnen and others.
+ * Copyright (c) 2019, 2022 Julian Honnen and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,85 +11,878 @@
* Contributors:
* Julian Honnen <julian.honnen@vector.com> - initial API and implementation
* Andras Peteri <apeteri@b2international.com> - extracted common superclass
- * Hannes Wellmann - Bug 577116: Improve test utility method reusability
+ * Hannes Wellmann - Bug 577116 - Improve test utility method reusability
+ * Hannes Wellmann - Bug 578005 - Extend tests to fully cover feature-based launches
*******************************************************************************/
package org.eclipse.pde.ui.tests.launcher;
+import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.pde.internal.core.ICoreConstants.DEFAULT_VERSION;
+import static org.eclipse.pde.ui.tests.util.ProjectUtils.createPluginProject;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.stream.Stream;
+import java.util.stream.Collectors;
import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.debug.core.ILaunchConfiguration;
-import org.eclipse.pde.core.plugin.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.*;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.pde.core.plugin.IMatchRules;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.target.NameVersionDescriptor;
+import org.eclipse.pde.internal.core.FeatureModelManager;
+import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.internal.core.feature.FeatureChild;
+import org.eclipse.pde.internal.core.feature.WorkspaceFeatureModel;
+import org.eclipse.pde.internal.core.ifeature.*;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
-import org.eclipse.pde.internal.ui.wizards.feature.CreateFeatureProjectOperation;
+import org.eclipse.pde.internal.ui.wizards.feature.AbstractCreateFeatureOperation;
import org.eclipse.pde.internal.ui.wizards.feature.FeatureData;
+import org.eclipse.pde.launching.IPDELauncherConstants;
+import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
+import org.junit.rules.TemporaryFolder;
public class FeatureBasedLaunchTest extends AbstractLaunchTest {
- private static IProject featureProject;
-
- private ILaunchConfiguration fFeatureBasedWithStartLevels;
-
- @BeforeClass
- public static void createTestFeature() throws Exception {
-
- FeatureData featureData = new FeatureData();
- featureData.id = FeatureBasedLaunchTest.class.getName() + "-feature";
- featureData.version = "1.0.0";
-
- IPluginBase[] contents = Stream.of("javax.inject", "org.eclipse.core.runtime", "org.eclipse.ui") //
- .map(id -> PluginRegistry.findModel(id).getPluginBase()) //
- .toArray(IPluginBase[]::new);
-
- IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
- featureProject = workspaceRoot.getProject(featureData.id);
- IPath location = workspaceRoot.getLocation().append(featureProject.getName());
- CreateFeatureProjectOperation operation = new CreateFeatureProjectOperation(featureProject, location,
- featureData, contents, null) {
- @Override
- protected void openFeatureEditor(IFile manifestFile) {
- // don't open in headless tests
- }
- };
- operation.run(null);
- }
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+ private Path tpJarDirectory;
@Before
- public void setupLaunchConfig() throws Exception {
- fFeatureBasedWithStartLevels = getLaunchConfiguration("feature-based-with-startlevels.launch");
+ public void setup() throws Exception {
+ tpJarDirectory = folder.newFolder("TPJarDirectory").toPath();
}
+ // --- tests ---
+
@Test
- public void testOldEntryWithoutConfigurationHasDefaults() throws Exception {
- checkStartLevels("javax.inject", "default:default");
- }
+ public void testGetMergedBundleMap_autostartLevels() throws Throwable {
+ TargetPlatformUtil.setRunningPlatformAsTarget();
- @Test
- public void testUseConfiguredStartLevels() throws Exception {
- checkStartLevels("org.eclipse.core.runtime", "1:true");
- }
+ createFeatureProject(FeatureBasedLaunchTest.class.getName() + "-feature", "1.0.0", f -> {
+ addIncludedPlugin(f, "javax.inject", DEFAULT_VERSION);
+ addIncludedPlugin(f, "org.eclipse.core.runtime", DEFAULT_VERSION);
+ addIncludedPlugin(f, "org.eclipse.ui", DEFAULT_VERSION);
+ });
+ ILaunchConfiguration lc = getLaunchConfiguration("feature-based-with-startlevels.launch");
- @Test
- public void testIgnoreConfiguredStartLevelsOfUncheckedPlugin() throws Exception {
- checkStartLevels("org.eclipse.ui", "default:default");
- }
-
- private void checkStartLevels(String pluginId, String expectedStartLevels) throws CoreException {
- Map<IPluginModelBase, String> bundleMap = BundleLauncherHelper.getMergedBundleMap(fFeatureBasedWithStartLevels,
- false);
+ Map<IPluginModelBase, String> bundleMap = BundleLauncherHelper.getMergedBundleMap(lc, false);
Map<String, String> byId = new LinkedHashMap<>();
for (Entry<IPluginModelBase, String> entry : bundleMap.entrySet()) {
byId.put(entry.getKey().getPluginBase().getId(), entry.getValue());
}
- assertThat(byId).containsEntry(pluginId, expectedStartLevels);
+ assertThat(byId)//
+ .as("old entry without configuration has defaults").containsEntry("javax.inject", "default:default")
+ .as("use configured start-levels").containsEntry("org.eclipse.core.runtime", "1:true")
+ .as("ignore configured start-levels of uncheckedplugin")
+ .containsEntry("org.eclipse.ui", "default:default");
+ }
+
+ // --- defined feature selection ---
+
+ @Test
+ public void testGetMergedBundleMap_featureSelectionForLocationWorkspace_latestWorkspaceFeature() throws Throwable {
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"), //
+ bundle("plugin.d", "1.0.0"));
+
+ createFeatureProject("feature.a", "2.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ });
+ createFeatureProject("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.b", "1.0.0");
+ });
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "2.0.0", f -> {
+ addIncludedPlugin(f, "plugin.c", "1.0.0");
+ }), //
+ targetFeature("feature.z", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.d", "1.0.0");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+ wc.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_WORKSPACE);
+
+ assertGetMergedBundleMap(wc, Set.of( //
+ targetBundle("plugin.b", "1.0.0")));
+ }
+
+ @Test
+ public void testGetMergedBundleMap_featureSelectionForLocationWorkspaceButNoWorkspaceFeaturePresent_latestExternalFeature()
+ throws Throwable {
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "2.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ }), //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.b", "1.0.0");
+ }), //
+ targetFeature("feature.z", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.c", "1.0.0");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+ wc.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_WORKSPACE);
+
+ assertGetMergedBundleMap(wc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+
+ @Test
+ public void testGetMergedBundleMap_featureSelectionForLocationExternal_latestExternalFeature() throws Throwable {
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"), //
+ bundle("plugin.d", "1.0.0"));
+
+ createFeatureProject("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ });
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "2.0.0", f -> {
+ addIncludedPlugin(f, "plugin.b", "1.0.0");
+ }), //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.c", "1.0.0");
+ }), //
+ targetFeature("feature.z", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.d", "1.0.0");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+ wc.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_EXTERNAL);
+
+ assertGetMergedBundleMap(wc, Set.of( //
+ targetBundle("plugin.b", "1.0.0")));
+ }
+
+ @Test
+ public void testGetMergedBundleMap_featureSelectionForLocationExternalButNoExternalFeaturePresent_noFeature()
+ throws Throwable {
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"));
+
+ createFeatureProject("feature.a", "2.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ });
+
+ List<NameVersionDescriptor> targetFeatures = List.of();
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+ wc.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_EXTERNAL);
+
+ assertGetMergedBundleMap(wc, emptySet());
+ }
+
+ // --- included plug-ins ---
+
+ @Test
+ public void testGetMergedBundleMap_includedPluginWithDefaultVersion() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.a", "1.0.1");
+ createPluginProject("plugin.b", "1.0.0");
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "2.0.0"), //
+ bundle("plugin.a", "2.0.1"), //
+ bundle("plugin.c", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", DEFAULT_VERSION);
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.b", DEFAULT_VERSION);
+ }), //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.c", DEFAULT_VERSION);
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.1")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.a", "2.0.1")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.1")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_EXTERNAL);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default external", lc, Set.of( //
+ targetBundle("plugin.a", "2.0.1")));
+ }
+ // Plug-ins only in secondary location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.b:external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.b", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.c:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.c", "1.0.0")));
+ }
+ }
+
+ @Test
+ public void testGetMergedBundleMap_includedPluginWithSpecificVersion() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.a", "1.2.0");
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.a", "1.1.0"), //
+ bundle("plugin.z", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "2.0.0");
+ }), //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.1.0");
+ }), //
+ targetFeature("feature.d", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.2.0");
+ }), //
+ targetFeature("feature.e", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0.someQualifier");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ // Perfect version-match in primary location (while secondary location
+ // has matches too)
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_EXTERNAL);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default external", lc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+ // Unqualified version-match in primary location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.e:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.2.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.e:external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.a", "1.1.0")));
+ }
+ // no version-match at all (for included plug-ins the latest plug-in of
+ // a location is added if there is no match in the primary location)
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.b:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace no match", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.2.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.b:external"));
+
+ assertGetMergedBundleMap("pluginResolution external no match", lc, Set.of( //
+ targetBundle("plugin.a", "1.1.0")));
+ }
+ // Perfect version match only in secondary location (but another version
+ // is present in the primary too).
+ // To be able to conveniently override a specific version of a plug-in,
+ // which is actually included by a (transitive) feature from the TP, by
+ // a plug-in from the workspace (which happens frequently when
+ // one has just updated the plug-in version) the latest plug-in from the
+ // primary location is taken if one is present and none matches the
+ // specified version exactly (with or without considering qualifiers).
+ // See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=576887
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.c:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace but match is external", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.2.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.d:external"));
+
+ assertGetMergedBundleMap("pluginResolution external but match is in workspace", lc, Set.of( //
+ targetBundle("plugin.a", "1.1.0")));
+ }
+ }
+
+ // --- required/imported plug-in dependencies ---
+
+ @Test
+ public void testGetMergedBundleMap_requiredPluginWithNoVersion() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.a", "1.1.0");
+ createPluginProject("plugin.b", "1.0.0");
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "2.0.0"), //
+ bundle("plugin.a", "2.1.0"), //
+ bundle("plugin.c", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", null, IMatchRules.NONE);
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.b", null, IMatchRules.NONE);
+ }), //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.c", null, IMatchRules.NONE);
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ // explicit pluginResolution location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.1.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.a", "2.1.0")));
+ }
+ // default pluginResolution location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.1.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_EXTERNAL);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:default"));
+
+ assertGetMergedBundleMap("pluginResolution default external", lc, Set.of( //
+ targetBundle("plugin.a", "2.1.0")));
+ }
+ // Plug-ins only in secondary location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.b:external"));
+
+ assertGetMergedBundleMap("pluginResolution external but match in workspace", lc, Set.of( //
+ workspaceBundle("plugin.b", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.c:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace but match is external", lc, Set.of( //
+ targetBundle("plugin.c", "1.0.0")));
+ }
+ }
+
+ @Test
+ public void testGetMergedBundleMap_requiredPluginWithSpecificVersion1() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.a", "1.1.2");
+ createPluginProject("plugin.a", "2.0.0");
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.a", "1.2.3"), //
+ bundle("plugin.a", "3.0.0"), //
+ bundle("plugin.z", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "1.0.0", IMatchRules.NONE);
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "1.0.0", IMatchRules.COMPATIBLE);
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ // MatchRule NONE/COMPATIBLE (behave the same according to VersionUtil)
+ // and location resolution tests.
+ // explicit pluginResolution location
+ {
+ for (String feature : List.of("feature.a", "feature.b")) {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of(feature + ":workspace"));
+
+ assertGetMergedBundleMap("pluginResolution explicit workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.0")));
+ }
+ }
+ {
+ for (String feature : List.of("feature.a", "feature.b")) {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of(feature + ":external"));
+
+ assertGetMergedBundleMap("pluginResolution explicit external", lc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+ }
+ // default pluginResolution location
+ {
+ for (String feature : List.of("feature.a", "feature.b")) {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION,
+ IPDELauncherConstants.LOCATION_WORKSPACE);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of(feature + ":default"));
+
+ assertGetMergedBundleMap("pluginResolution default workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.0")));
+ }
+ }
+ {
+ for (String feature : List.of("feature.a", "feature.b")) {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION,
+ IPDELauncherConstants.LOCATION_EXTERNAL);
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of(feature + ":default"));
+
+ assertGetMergedBundleMap("pluginResolution default external", lc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+ }
+ }
+
+ @Test
+ public void testGetMergedBundleMap_requiredPluginWithSpecificVersion2() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.a", "1.0.1");
+ createPluginProject("plugin.a", "1.1.0");
+ createPluginProject("plugin.a", "1.1.2");
+ createPluginProject("plugin.a", "2.0.0");
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.a", "1.0.2"), //
+ bundle("plugin.a", "1.2.0"), //
+ bundle("plugin.a", "1.2.3"), //
+ bundle("plugin.a", "3.0.0"), //
+ bundle("plugin.z", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "1.0.0", IMatchRules.EQUIVALENT);
+ }), //
+ targetFeature("feature.d", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "1.1.0", IMatchRules.EQUIVALENT);
+ }), //
+ targetFeature("feature.e", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "1.2.0", IMatchRules.EQUIVALENT);
+ }), //
+ targetFeature("feature.f", "1.0.0", f -> {
+ addRequiredPlugin(f, "plugin.a", "8.0.0", IMatchRules.EQUIVALENT);
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ // No need to test all match-rules. Just have to check that version
+ // match rules are obeyed. For the following cases match-rule EQUIVALENT
+ // is used to check different per-location-availability scenarios.
+
+ // match in primary location (while secondary location has matches too)
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.c:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace", lc, Set.of( //
+ workspaceBundle("plugin.a", "1.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.c:external"));
+
+ assertGetMergedBundleMap("pluginResolution external", lc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+ // match only in secondary location
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.d:external"));
+
+ assertGetMergedBundleMap("pluginResolution external but match in workspace", lc, Set.of( //
+ targetBundle("plugin.a", "3.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.e:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace but match is external", lc, Set.of( //
+ workspaceBundle("plugin.a", "2.0.0")));
+ }
+ // no match at all
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.f:external"));
+
+ assertGetMergedBundleMap("pluginResolution external no match", lc, Set.of( //
+ targetBundle("plugin.a", "3.0.0")));
+ }
+ {
+ ILaunchConfigurationWorkingCopy lc = createFeatureLaunchConfig();
+ lc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.f:workspace"));
+
+ assertGetMergedBundleMap("pluginResolution workspace no match", lc, Set.of( //
+ workspaceBundle("plugin.a", "2.0.0")));
+ }
+ }
+
+ // --- miscellaneous cases ---
+
+ @Test
+ public void testGetMergedBundleMap_multipleInclusionOfPluginAndFeature() throws Throwable {
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.z", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ addRequiredPlugin(f, "plugin.a", "1.0.0", IMatchRules.PERFECT);
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.a", "1.0.0");
+ addRequiredPlugin(f, "plugin.a", "1.0.0", IMatchRules.PERFECT);
+ }), //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addIncludedFeature(f, "feature.z", "1.0.0");
+ addRequiredFeature(f, "feature.z", "1.0.0", IMatchRules.PERFECT);
+ }), //
+ targetFeature("feature.d", "1.0.0", f -> {
+ addIncludedFeature(f, "feature.z", "1.0.0");
+ addRequiredFeature(f, "feature.z", "1.0.0", IMatchRules.PERFECT);
+ }), //
+
+ targetFeature("feature.z", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.z", "1.0.0");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of( //
+ "feature.a:default", //
+ "feature.b:default", //
+ "feature.c:default", //
+ "feature.d:default"));
+
+ assertGetMergedBundleMap(wc, Set.of( //
+ targetBundle("plugin.a", "1.0.0")));
+ }
+
+ @Test
+ public void testGetMergedBundleMap_additionalPlugins() throws Throwable {
+ createPluginProject("plugin.a", "1.0.0");
+ createPluginProject("plugin.b", "1.0.0");
+ createPluginProject("plugin.d", "1.0.0");
+ createPluginProject("plugin.e", "1.0.0");
+
+ List<NameVersionDescriptor> targetBundles = List.of( //
+ bundle("plugin.a", "1.0.0"), //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"), //
+ bundle("plugin.d", "1.0.0"), //
+ bundle("plugin.e", "1.0.0"), //
+ bundle("plugin.f", "2.0.0"), //
+ bundle("plugin.z", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.d", "1.0.0");
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.e", "1.0.0");
+ }));
+
+ setTargetPlatform(targetBundles, targetFeatures);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of( //
+ "feature.a:external", //
+ "feature.b:workspace"));
+ wc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_EXTERNAL);
+ wc.setAttribute(IPDELauncherConstants.ADDITIONAL_PLUGINS, Set.of( //
+ // id:version:location:enabled:startLeval:autoStart
+ "plugin.a:1.0.0:default:true:1:true", //
+ "plugin.b:1.0.0:workspace:true:2:true", //
+ "plugin.c:1.0.0:workspace:true:3:true", //
+ "plugin.d:1.0.0:external:true:4:true", // overwrite from feature
+ "plugin.e:1.0.0:external:true:5:true", // attempted overwrite
+ "plugin.f:1.0.0:default:true:6:true", // not matching version
+ "plugin.z:1.0.0:external:false:7:true") // disabled
+ );
+ // overwriting the plug-in also included by a feature only works
+ // if the same primary location is used and both pull in the
+ // same version. Otherwise two different bundles are added
+
+ assertGetMergedBundleMap(wc, Map.of( //
+ targetBundle("plugin.a", "1.0.0"), "1:true", //
+ workspaceBundle("plugin.b", "1.0.0"), "2:true", //
+ targetBundle("plugin.c", "1.0.0"), "3:true", //
+ targetBundle("plugin.d", "1.0.0"), "4:true", //
+ targetBundle("plugin.e", "1.0.0"), "5:true", //
+ workspaceBundle("plugin.e", "1.0.0"), "default:default", //
+ targetBundle("plugin.f", "2.0.0"), "6:true"));
+ }
+
+ // --- utility methods ---
+
+ private static interface CoreConsumer<E> {
+ void accept(E e) throws CoreException;
+ }
+
+ private static void createFeatureProject(String id, String version, CoreConsumer<IFeature> featureSetup)
+ throws Throwable {
+ createFeature(id, version, id + "_" + version.replace('.', '_'), featureSetup);
+ }
+
+ private static IFeature createFeature(String id, String version, String projectName,
+ CoreConsumer<IFeature> featureSetup) throws Throwable {
+ FeatureData featureData = new FeatureData();
+ featureData.id = id;
+ featureData.version = version;
+
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+ IProject project = workspaceRoot.getProject(projectName);
+ IPath location = workspaceRoot.getLocation().append(project.getName());
+
+ IRunnableWithProgress operation = new AbstractCreateFeatureOperation(project, location, featureData, null) {
+ @Override
+ protected void configureFeature(IFeature feature, WorkspaceFeatureModel model) throws CoreException {
+ featureSetup.accept(feature);
+ }
+
+ @Override
+ protected void openFeatureEditor(IFile manifestFile) {
+ // don't open in headless tests
+ }
+ };
+ operation.run(new NullProgressMonitor());
+ FeatureModelManager featureModelManager = PDECore.getDefault().getFeatureModelManager();
+ return featureModelManager.getFeatureModel(project).getFeature();
+ }
+
+ // Created Feature-projects get reloaded shortly after their creation, in
+ // the end of the auto-build job (due to some pending resource-changed
+ // events). In the beginning of the reload the feature model is reset and
+ // all fields become null/0. So if the model is read inbetween the model
+ // state could be inconsistent. This creates a race condition, which
+ // occasionally leads to test-failure. All my attempts to consume all
+ // resource-change events immediately to resolve the race-condition failed.
+ // I also tried to await the World-Changed event fired on a FeatureModel
+ // once it was reloaded but then the test spent most of its runtime waiting.
+ // Blocking all other operations was the simplest and fastest solution.
+ @BeforeClass
+ public static void acquireWorkspaceRuleToAvoidFeatureReloadByAutobuild() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ Job.getJobManager().beginRule(root, null);
+ }
+
+ @AfterClass
+ public static void releaseWorkspaceRule() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ Job.getJobManager().endRule(root);
+ }
+
+ private static void addRequiredPlugin(IFeature feature, String id, String version, int matchRule)
+ throws CoreException {
+ addImport(feature, id, version, matchRule, IFeatureImport.PLUGIN);
+ }
+
+ private static void addRequiredFeature(IFeature feature, String id, String version, int matchRule)
+ throws CoreException {
+ addImport(feature, id, version, matchRule, IFeatureImport.FEATURE);
+ }
+
+ private static void addImport(IFeature feature, String id, String version, int matchRule, int type)
+ throws CoreException {
+ IFeatureModelFactory factory = feature.getModel().getFactory();
+ IFeatureImport featureImport = factory.createImport();
+ featureImport.setId(id);
+ featureImport.setVersion(version);
+ featureImport.setMatch(matchRule);
+ featureImport.setType(type);
+
+ feature.addImports(new IFeatureImport[] { featureImport });
+ }
+
+ private static FeatureChild addIncludedFeature(IFeature feature, String id, String version) throws CoreException {
+ FeatureChild featureChild = (FeatureChild) feature.getModel().getFactory().createChild();
+ featureChild.setId(id);
+ featureChild.setVersion(version);
+ featureChild.setOptional(false);
+ feature.addIncludedFeatures(new IFeatureChild[] { featureChild });
+ return featureChild;
+ }
+
+ private static IFeaturePlugin addIncludedPlugin(IFeature feature, String id, String version) throws CoreException {
+ IFeaturePlugin featurePlugin = feature.getModel().getFactory().createPlugin();
+ featurePlugin.setId(id);
+ featurePlugin.setVersion(version);
+ featurePlugin.setUnpack(false);
+ feature.addPlugins(new IFeaturePlugin[] { featurePlugin });
+ return featurePlugin;
+ }
+
+ private NameVersionDescriptor targetFeature(String featureId, String featureVersion,
+ CoreConsumer<IFeature> featureSetup) throws Throwable {
+
+ IFeature feature = createFeature(featureId, featureVersion, "tp-feature-temp-project", featureSetup);
+
+ WorkspaceFeatureModel model = (WorkspaceFeatureModel) feature.getModel();
+ IResource resource = model.getUnderlyingResource();
+
+ Path featureDirectory = tpJarDirectory.resolve(Path.of("features", featureId + "_" + featureVersion));
+ Files.createDirectories(featureDirectory);
+ Path featureFile = featureDirectory.resolve(resource.getProjectRelativePath().toString());
+ try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(featureFile));) {
+ model.save(writer);
+ }
+ IProject project = resource.getProject();
+ project.delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, null);
+
+ return new NameVersionDescriptor(featureId, featureVersion, NameVersionDescriptor.TYPE_FEATURE);
+ }
+
+ private void setTargetPlatform(List<NameVersionDescriptor> targetPlugins,
+ List<NameVersionDescriptor> targetFeatures) throws Exception {
+ TargetPlatformUtil.setDummyBundlesAsTarget(targetPlugins, tpJarDirectory);
+ }
+
+ private static ILaunchConfigurationWorkingCopy createFeatureLaunchConfig() throws CoreException {
+ String name = "feature-based-Eclipse-app";
+ ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType type = launchManager.getLaunchConfigurationType("org.eclipse.pde.ui.RuntimeWorkbench");
+ ILaunchConfigurationWorkingCopy wc = type.newInstance(null, name);
+ wc.setAttribute(IPDELauncherConstants.USE_CUSTOM_FEATURES, true);
+ wc.setAttribute(IPDELauncherConstants.USE_DEFAULT, false);
+ wc.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_WORKSPACE);
+ wc.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
+ return wc;
+ }
+
+ private static void assertGetMergedBundleMap(ILaunchConfiguration launchConfig,
+ Set<BundleLocationDescriptor> expectedBundles) throws Exception {
+ assertGetMergedBundleMap(null, launchConfig, expectedBundles);
+ }
+
+ private static void assertGetMergedBundleMap(String message, ILaunchConfiguration launchConfig,
+ Set<BundleLocationDescriptor> expectedBundles) throws Exception {
+
+ Map<BundleLocationDescriptor, String> expectedBundleMap = expectedBundles.stream()
+ .collect(Collectors.toMap(b -> b, b -> "default:default"));
+ assertGetMergedBundleMap(message, launchConfig, expectedBundleMap);
+ }
+
+ private static void assertGetMergedBundleMap(ILaunchConfiguration launchConfig,
+ Map<BundleLocationDescriptor, String> expectedBundleMap) throws Exception {
+ assertGetMergedBundleMap(null, launchConfig, expectedBundleMap);
+ }
+
+ private static void assertGetMergedBundleMap(String message, ILaunchConfiguration launchConfig,
+ Map<BundleLocationDescriptor, String> expectedBundleMap) throws Exception {
+
+ Map<IPluginModelBase, String> bundleMap = BundleLauncherHelper.getMergedBundleMap(launchConfig, false);
+
+ Map<IPluginModelBase, String> expectedPluginMap = new HashMap<>();
+ expectedBundleMap.forEach((pd, start) -> {
+ expectedPluginMap.put(pd.findModel(), start);
+ });
+
+ assertPluginMapsEquals(message, expectedPluginMap, bundleMap);
}
}
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 412d055..d053e17 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2021, 2021 Hannes Wellmann and others.
+ * Copyright (c) 2021, 2022 Hannes Wellmann and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -15,7 +15,6 @@
import static org.junit.Assert.assertEquals;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;
@@ -810,10 +809,6 @@
// --- utilities ---
- private static NameVersionDescriptor bundle(String id, String version) {
- return new NameVersionDescriptor(id, version);
- }
-
private void assertGetMergedBundleMap(List<NameVersionDescriptor> workspacePlugins,
List<NameVersionDescriptor> targetPlugins, Consumer<ILaunchConfigurationWorkingCopy> launchConfigPreparer,
Set<BundleLocationDescriptor> expectedBundles) throws Exception {
@@ -839,11 +834,11 @@
expectedPluginMap.put(pd.findModel(), start);
});
- assertEquals(expectedPluginMap, bundleMap);
+ assertPluginMapsEquals(null, expectedPluginMap, bundleMap);
}
private void setUpWorkspace(List<NameVersionDescriptor> workspacePlugins, List<NameVersionDescriptor> targetPlugins)
- throws CoreException, IOException, InterruptedException {
+ throws Exception {
ProjectUtils.createWorkspacePluginProjects(workspacePlugins);
TargetPlatformUtil.setDummyBundlesAsTarget(targetPlugins, tpJarDirectory);
}
@@ -857,21 +852,4 @@
wc.setAttribute(IPDELauncherConstants.USE_DEFAULT, false);
return wc;
}
-
- private static BundleLocationDescriptor workspaceBundle(String id, String version) {
- Objects.requireNonNull(version);
- return () -> findWorkspaceModel(id, version);
- }
-
- private static BundleLocationDescriptor targetBundle(String id, String version) {
- Objects.requireNonNull(version);
- // PluginRegistry.findModel does not consider external models when
- // workspace models are present and returns the 'last' plug-in if
- // multiple with the same version exist
- return () -> findTargetModel(id, version);
- }
-
- private static interface BundleLocationDescriptor {
- IPluginModelBase findModel();
- }
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
index 7ededbe..05b2b26 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2021 IBM Corporation and others.
+ * Copyright (c) 2008, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -158,15 +158,16 @@
public static List<IProject> createWorkspacePluginProjects(List<NameVersionDescriptor> workspacePlugins)
throws CoreException {
List<IProject> projects = new ArrayList<>();
- for (NameVersionDescriptor pluginDescription : workspacePlugins) {
- String bundleSymbolicName = pluginDescription.getId();
- String bundleVersion = pluginDescription.getVersion();
- String projectName = bundleSymbolicName + bundleVersion.replace('.', '_');
- projects.add(createPluginProject(projectName, bundleSymbolicName, bundleVersion));
+ for (NameVersionDescriptor plugin : workspacePlugins) {
+ projects.add(createPluginProject(plugin.getId(), plugin.getVersion()));
}
return projects;
}
+ public static IProject createPluginProject(String bundleSymbolicName, String bundleVersion) throws CoreException {
+ return createPluginProject(bundleSymbolicName + bundleVersion.replace('.', '_'), bundleSymbolicName, bundleVersion);
+ }
+
public static IProject createPluginProject(String projectName, String bundleSymbolicName, String version)
throws CoreException {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
index 759d37e..8f8fdd9 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019, 2021 Julian Honnen and others.
+ * Copyright (c) 2019, 2022 Julian Honnen and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -135,6 +135,8 @@
private static ITargetLocation createDummyBundlesLocation(List<NameVersionDescriptor> targetPlugins,
Path jarDirectory) throws IOException {
+ Path pluginsDirectory = jarDirectory.resolve("plugins");
+ Files.createDirectories(pluginsDirectory);
for (NameVersionDescriptor bundleNameVersion : targetPlugins) {
Manifest manifest = createDummyBundleManifest(bundleNameVersion.getId(), bundleNameVersion.getVersion());
@@ -143,7 +145,7 @@
String bundleSymbolicName = Objects.requireNonNull(mainAttributes.getValue(Constants.BUNDLE_SYMBOLICNAME));
String bundleVersion = Objects.requireNonNull(mainAttributes.getValue(Constants.BUNDLE_VERSION));
- Path jarPath = jarDirectory.resolve(bundleSymbolicName + "_" + bundleVersion + ".jar");
+ Path jarPath = pluginsDirectory.resolve(bundleSymbolicName + "_" + bundleVersion + ".jar");
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(jarPath));) {
out.putNextEntry(new ZipEntry(JarFile.MANIFEST_NAME));
manifest.write(out);