| /******************************************************************************* |
| * Copyright (c) 2010 The Eclipse Foundation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * The Eclipse Foundation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.epp.mpc.tests.service; |
| |
| import static org.hamcrest.Matchers.*; |
| import static org.junit.Assume.*; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.security.cert.Certificate; |
| import java.text.MessageFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; |
| import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; |
| import org.eclipse.epp.internal.mpc.core.ServiceLocator; |
| import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; |
| import org.eclipse.epp.mpc.core.model.IIu; |
| import org.eclipse.epp.mpc.core.model.IIus; |
| import org.eclipse.epp.mpc.core.model.INode; |
| import org.eclipse.epp.mpc.core.model.ISearchResult; |
| import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller; |
| import org.eclipse.epp.mpc.core.service.QueryHelper; |
| import org.eclipse.epp.mpc.core.service.UnmarshalException; |
| import org.eclipse.epp.mpc.tests.Categories.RemoteTests; |
| import org.eclipse.epp.mpc.tests.LoggingSuite; |
| import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; |
| import org.eclipse.equinox.internal.p2.repository.Activator; |
| import org.eclipse.equinox.p2.core.IProvisioningAgent; |
| import org.eclipse.equinox.p2.core.UIServices; |
| import org.hamcrest.Matcher; |
| import org.hamcrest.MatcherAssert; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.ClassRule; |
| import org.junit.ComparisonFailure; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| import org.junit.rules.ExternalResource; |
| import org.junit.rules.TestRule; |
| import org.junit.rules.TestWatcher; |
| import org.junit.runner.Description; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameter; |
| import org.junit.runners.Parameterized.Parameters; |
| import org.junit.runners.model.Statement; |
| import org.osgi.framework.ServiceRegistration; |
| |
| @RunWith(Parameterized.class) |
| @Category(RemoteTests.class) |
| public class SolutionCompatibilityFilterTest { |
| private static final String BASE_URL = "http://marketplace-staging.eclipse.org"; |
| |
| public static enum System { |
| WIN32(Platform.OS_WIN32, Platform.WS_WIN32), // |
| LINUX(Platform.OS_LINUX, Platform.WS_GTK), // |
| MACOS(Platform.OS_MACOSX, Platform.WS_COCOA); |
| |
| private final String os; |
| |
| private final String ws; |
| |
| private System(String os, String ws) { |
| this.os = os; |
| this.ws = ws; |
| } |
| |
| public void applyTo(Map<String, String> metaParams) { |
| metaParams.put(DefaultMarketplaceService.META_PARAM_OS, os); |
| metaParams.put(DefaultMarketplaceService.META_PARAM_WS, ws); |
| } |
| } |
| |
| private static final String JAVA_PRODUCT_ID = "epp.package.java"; |
| |
| private static final String SDK_PRODUCT_ID = "org.eclipse.sdk.ide"; |
| |
| public static enum EclipseRelease { |
| UNKNOWN(null, null, null, null), // |
| INDIGO(JAVA_PRODUCT_ID, "1.4.2.20120131-1457", "3.7.0.v20110110", null), // |
| JUNO_3_8(SDK_PRODUCT_ID, "3.8.0.v201206081200", "3.8.0.v20120521-2346", null), // |
| JUNO_3_8_WITH_PLATFORM(SDK_PRODUCT_ID, JUNO_3_8.productVersion(), JUNO_3_8.runtimeVersion(), |
| "3.8.0.v201206081200"), // |
| JUNO(JAVA_PRODUCT_ID, "1.5.0.20120131-1544", "3.8.0.v20120521-2346", null), // |
| JUNO_WITH_PLATFORM(JAVA_PRODUCT_ID, JUNO.productVersion(), JUNO.runtimeVersion(), "4.2.0.v201206081400"), // |
| JUNO_SR2(JAVA_PRODUCT_ID, "1.5.2.20130110-1126", "3.8.0.v20120521-2346", "4.2.2.v201302041200"), // |
| KEPLER(JAVA_PRODUCT_ID, "2.0.0.20130613-0530", "3.9.0.v20130326-1255", "4.3.0.v20130605-2000"), // |
| KEPLER_SR2(JAVA_PRODUCT_ID, "2.0.2.20140224-0000", "3.9.100.v20131218-1515", "4.3.2.v20140221-1700"), // |
| LUNA(JAVA_PRODUCT_ID, "4.4.0.20140612-0500", "3.10.0.v20140318-2214", "4.4.0.v20140606-1215"), // |
| LUNA_SR2(JAVA_PRODUCT_ID, "4.4.2.20150219-0708", "3.10.0.v20140318-2214", "4.4.2.v20150204-1700"), // |
| MARS(JAVA_PRODUCT_ID, "4.5.0.20150326-0704", "3.10.0.v20150112-1422", "4.5.0.v20150203-1300"); |
| |
| private final String productId; |
| |
| private final String productVersion; |
| |
| private final String runtimeVersion; |
| |
| private final String platformVersion; |
| |
| private EclipseRelease(String productId, String productVersion, String runtimeVersion, String platformVersion) { |
| this.productId = productId; |
| this.productVersion = productVersion; |
| this.runtimeVersion = runtimeVersion; |
| this.platformVersion = platformVersion; |
| } |
| |
| private EclipseRelease(String productVersion, String runtimeVersion, String platformVersion) { |
| this(JAVA_PRODUCT_ID, productVersion, runtimeVersion, platformVersion); |
| } |
| |
| public String productId() { |
| return productId; |
| } |
| |
| public String productVersion() { |
| return productVersion; |
| } |
| |
| public String runtimeVersion() { |
| return runtimeVersion; |
| } |
| |
| public String platformVersion() { |
| return platformVersion; |
| } |
| |
| public void applyTo(Map<String, String> metaParams) { |
| if (productVersion == null) { |
| metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT); |
| metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION); |
| } else { |
| metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT, productId); |
| metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION, productVersion); |
| } |
| if (runtimeVersion == null) { |
| metaParams.remove(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION); |
| } else { |
| metaParams.put(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION, runtimeVersion); |
| } |
| if (platformVersion == null) { |
| metaParams.remove(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION); |
| } else { |
| metaParams.put(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION, platformVersion); |
| } |
| } |
| |
| public static EclipseRelease previous(EclipseRelease release) { |
| if (release == UNKNOWN) { |
| return null; |
| } |
| int previousOrdinal = release.ordinal() - 1; |
| return previousOrdinal > UNKNOWN.ordinal() ? values()[previousOrdinal] : null; |
| } |
| |
| public static EclipseRelease next(EclipseRelease release) { |
| if (release == UNKNOWN) { |
| return null; |
| } |
| int nextOrdinal = release.ordinal() + 1; |
| return values().length > nextOrdinal ? values()[nextOrdinal] : null; |
| } |
| } |
| |
| public static enum Solution { |
| JUNO("test-entry-juno", EclipseRelease.JUNO_3_8, EclipseRelease.JUNO_SR2), // |
| KEPLER("test-entry-kepler", EclipseRelease.KEPLER, EclipseRelease.KEPLER_SR2), // |
| LUNA("test-entry-luna", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2), // |
| MARS("test-entry-mars", EclipseRelease.MARS, EclipseRelease.MARS), // |
| JUNO_AND_EARLIER("test-entry-juno-and-earlier", null, EclipseRelease.JUNO_SR2), // |
| KEPLER_AND_EARLIER("test-entry-kepler-and-earlier", null, EclipseRelease.KEPLER_SR2), // |
| KEPLER_LUNA("test-entry-kepler-luna", EclipseRelease.KEPLER, EclipseRelease.LUNA_SR2), // |
| KEPLER_MARS("test-entry-kepler-luna-mars", EclipseRelease.KEPLER, EclipseRelease.MARS), // |
| LUNA_WIN32("test-entry-luna-win32", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.WIN32), // |
| LUNA_LINUX_MACOS("test-entry-luna-mac-linux", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.LINUX, |
| System.MACOS), // |
| MULTI_VERSION("test-entry-multi-version", null, EclipseRelease.MARS), // |
| PSEUDO_CONFLICT("test-entry-pseudo-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), // |
| CONFLICT("test-entry-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), // |
| UNINSTALLABLE(""/* TODO */, null, null, System.WIN32, System.MACOS, System.LINUX); |
| |
| private final String id; |
| |
| private final String shortName; |
| |
| private final EclipseRelease minRelease; |
| |
| private final EclipseRelease maxRelease; |
| |
| private final System[] systems; |
| |
| private Solution(String shortName, EclipseRelease minRelease, EclipseRelease maxRelease, System... systems) { |
| this.id = null; |
| this.shortName = shortName; |
| this.minRelease = minRelease; |
| this.maxRelease = maxRelease; |
| this.systems = systems; |
| } |
| |
| public String id() { |
| return id; |
| } |
| |
| public String shortName() { |
| return shortName; |
| } |
| |
| public String url() { |
| return BASE_URL + "/content/" + shortName; |
| } |
| |
| public String query() { |
| return shortName; |
| } |
| |
| public boolean installable() { |
| //TODO |
| return true; |
| } |
| |
| public EclipseRelease minRelease() { |
| return minRelease; |
| } |
| |
| public EclipseRelease maxRelease() { |
| return maxRelease; |
| } |
| |
| public System[] systems() { |
| return systems == null || systems.length == 0 ? System.values() : systems; |
| } |
| |
| public boolean isCompatible(System system) { |
| if (systems == null || system == null) { |
| return true; |
| } |
| for (System aSystem : systems()) { |
| if (aSystem == system) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean isCompatible(EclipseRelease release) { |
| if (release == EclipseRelease.UNKNOWN) { |
| return true; |
| } |
| if (minRelease() != null) { |
| if (minRelease().ordinal() > release.ordinal()) { |
| return false; |
| } |
| } |
| if (maxRelease() != null) { |
| if (maxRelease().ordinal() < release.ordinal()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| @Parameters(name = "{index}__{0}__with__{1}_{2}") |
| public static Iterable<Object[]> data() { |
| List<Object[]> data = new ArrayList<Object[]>(); |
| checkSolutionReleaseBounds(data, Solution.JUNO); |
| checkSolutionReleaseBounds(data, Solution.KEPLER); |
| checkSolutionReleaseBounds(data, Solution.LUNA); |
| checkSolutionReleaseBounds(data, Solution.MARS); |
| |
| //bug 466627 |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, |
| EclipseRelease.INDIGO, null); |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, |
| EclipseRelease.JUNO_3_8, null); |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, |
| EclipseRelease.JUNO, null); |
| |
| checkSolutionReleaseBounds(data, Solution.JUNO_AND_EARLIER); |
| checkSolutionReleaseBounds(data, Solution.KEPLER_AND_EARLIER); |
| checkSolutionReleaseBounds(data, Solution.KEPLER_LUNA); |
| |
| checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_LUNA, |
| EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler", "org.example.feature.kepler"); |
| checkSolutionData(data, "Solution should have version 1.1.0 features for Luna release", Solution.KEPLER_LUNA, |
| EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna", "org.example.feature.luna"); |
| checkSolutionReleaseBounds(data, Solution.KEPLER_MARS); |
| checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_MARS, |
| EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna", |
| "org.example.feature.kepler.luna"); |
| checkSolutionData(data, "Solution should have version 1.0.0 features for Luna release", Solution.KEPLER_MARS, |
| EclipseRelease.LUNA, System.WIN32, "1.0.0", "http://example.org/kepler-luna", |
| "org.example.feature.kepler.luna"); |
| checkSolutionData(data, "Solution should have version 1.1.0 features for Mars release", Solution.KEPLER_MARS, |
| EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/mars", "org.example.feature.mars"); |
| checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", |
| Solution.LUNA_WIN32, EclipseRelease.LUNA, System.WIN32); |
| checkSolutionWithEclipse(data, "Solution should not be installable in an incompatible os", Solution.LUNA_WIN32, |
| EclipseRelease.LUNA, System.LINUX); |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.LUNA_WIN32, |
| EclipseRelease.KEPLER, System.WIN32); |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release and incompatible os", |
| Solution.LUNA_WIN32, EclipseRelease.KEPLER, System.LINUX); |
| checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", Solution.LUNA_WIN32, |
| EclipseRelease.MARS, System.WIN32); |
| checkSolutionWithEclipse(data, "Solution should not be installable in a newer release and incompatible os", |
| Solution.LUNA_WIN32, EclipseRelease.MARS, System.LINUX); |
| checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", |
| Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.LINUX); |
| checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", |
| Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.MACOS); |
| checkSolutionWithEclipse(data, "Solution should not installable in an incompatible os", |
| Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.WIN32); |
| checkSolutionData(data, "Solution should have version 1.1.0 features for Juno release", Solution.MULTI_VERSION, |
| EclipseRelease.JUNO, System.LINUX, "1.1.0", "http://example.org/juno-kepler", |
| "org.example.feature.juno.kepler"); |
| checkSolutionData(data, "Solution should have version 1.1.0 features for Kepler release", |
| Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.MACOS, "1.1.0", "http://example.org/juno-kepler", |
| "org.example.feature.juno.kepler"); |
| checkSolutionData(data, "Solution should have version 1.1.1 features for Kepler release on Windows", |
| Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.WIN32, "1.1.1", |
| "http://example.org/juno-kepler-win32", "org.example.feature.juno.kepler.win32"); |
| checkSolutionData(data, "Solution should have version 1.2.0 features for Luna release", Solution.MULTI_VERSION, |
| EclipseRelease.LUNA, System.WIN32, "1.2.0", "http://example.org/luna", |
| "org.example.feature.luna.nolinux"); |
| checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Luna release", |
| Solution.MULTI_VERSION, EclipseRelease.LUNA, System.LINUX, false); |
| checkSolutionData(data, "Solution should have version 1.3.0 features for Mars release", Solution.MULTI_VERSION, |
| EclipseRelease.MARS, System.MACOS, "1.3.0", "http://example.org/mars", |
| "org.example.feature.mars.nolinux"); |
| checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Mars release", |
| Solution.MULTI_VERSION, EclipseRelease.MARS, System.LINUX, false); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.0.0 for Luna on Mac", |
| Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.0.0", "http://example.org/maclinux", |
| "org.example.feature.maclinux"); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.1.0 for Luna on Windows", |
| Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/win", |
| "org.example.feature.win"); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (older version)", |
| Solution.CONFLICT, EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna", |
| "org.example.feature.keplerluna"); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions (real conflict) should have latest version for overlapping release", |
| Solution.CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna-mars", |
| "org.example.feature.lunamars"); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions (real conflict) should have latest version for overlapping release", |
| Solution.CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.1.0", "http://example.org/luna-mars", |
| "org.example.feature.lunamars"); |
| checkSolutionData( |
| data, |
| "Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (newer version)", |
| Solution.CONFLICT, EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/luna-mars", |
| "org.example.feature.lunamars"); |
| // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.WIN32); |
| // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.LINUX); |
| // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.MACOS); |
| return data; |
| } |
| |
| private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution, |
| EclipseRelease release, System system, String version, String site, String... features) { |
| if (release == null) { |
| release = EclipseRelease.UNKNOWN; |
| } |
| if (system == null) { |
| system = System.WIN32; |
| } |
| |
| boolean releaseCompatible = solution.isCompatible(release); |
| boolean systemCompatible = solution.isCompatible(system); |
| boolean compatible = releaseCompatible && systemCompatible; |
| |
| checkSolutionData(data, testDescription, solution, release, system, compatible, version, site, features); |
| } |
| |
| private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution, |
| EclipseRelease release, System system, boolean compatible, String version, String site, String... features) { |
| if (release == null) { |
| release = EclipseRelease.UNKNOWN; |
| } |
| if (system == null) { |
| system = System.WIN32; |
| } |
| if (features != null && features.length == 0) { |
| features = null; |
| } |
| |
| for (Object[] objects : data) { |
| if (objects[0] == solution && objects[1] == release && objects[2] == system) { |
| if (((version == null && objects[3] == null) || (version != null && version.equals(objects[3]))) |
| && ((site == null && objects[4] == null) || (site != null && site.equals(objects[4])))) { |
| if (features == null && objects[5] == null) { |
| return; |
| } |
| Set<String> allFeatures = new HashSet<String>(Arrays.asList(features)); |
| Set<String> allDataFeatures = new HashSet<String>(Arrays.asList((String[]) objects[5])); |
| if (allFeatures.equals(allDataFeatures)) { |
| return; |
| } |
| } |
| } |
| } |
| data.add(new Object[] { solution, release, system, version, site, features, compatible, testDescription }); |
| } |
| |
| private static void checkSolutionReleaseBounds(List<Object[]> data, Solution solution) { |
| EclipseRelease minRelease = solution.minRelease(); |
| EclipseRelease maxRelease = solution.maxRelease(); |
| EclipseRelease beforeMin = minRelease == null ? null : EclipseRelease.previous(minRelease); |
| EclipseRelease afterMax = maxRelease == null ? null : EclipseRelease.next(maxRelease); |
| if (beforeMin != null) { |
| checkSolutionWithEclipse(data, "Solution should not be installable in an older release", solution, |
| beforeMin, null); |
| } |
| for (EclipseRelease release : EclipseRelease.values()) { |
| if (solution.isCompatible(release)) { |
| checkSolutionWithEclipse(data, "Solution should be installable in a compatible release", solution, |
| release, null); |
| } |
| } |
| checkSolutionWithEclipse(data, "Solution should be installable in an unknown release", solution, |
| EclipseRelease.UNKNOWN, null); |
| if (afterMax != null) { |
| checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", solution, afterMax, |
| null); |
| } |
| } |
| |
| private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution, |
| EclipseRelease release, System system) { |
| checkSolutionData(data, testDescription, solution, release, system, null, null); |
| } |
| |
| private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution, |
| EclipseRelease release, System system, boolean compatible) { |
| checkSolutionData(data, testDescription, solution, release, system, compatible, null, null); |
| } |
| |
| private static void assertTrue(String message, boolean b, Object... details) { |
| Assert.assertTrue(format(message, flatten(b, details)), b); |
| } |
| |
| private static void assertNotNull(Object value) { |
| Assert.assertNotNull(value); |
| } |
| |
| private static void assertEquals(String message, Object o1, Object o2, Object... details) { |
| Assert.assertEquals(format(message, flatten(o1, o2, details)), o1, o2); |
| } |
| |
| private static void assertNotNull(String message, Object value, Object... details) { |
| Assert.assertNotNull(format(message, flatten(value, details)), value); |
| } |
| |
| private static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher, Object... details) { |
| MatcherAssert.assertThat(format(reason, flatten(actual, details)), actual, matcher); |
| } |
| |
| private static void assertNull(String message, Object value, Object... details) { |
| Assert.assertNull(format(message, flatten(value, details)), value); |
| } |
| |
| private static String format(String message, Object... details) { |
| if (details == null || details.length == 0) { |
| return message; |
| } |
| |
| String contentPrefix = BASE_URL + "/content/"; |
| for (int i = 0; i < details.length; i++) { |
| Object detail = details[i]; |
| if (detail instanceof INode) { |
| INode node = (INode) detail; |
| String url = node.getUrl(); |
| if (url != null) { |
| if (url.startsWith(contentPrefix)) { |
| String shortName = url.substring(contentPrefix.length()); |
| detail = shortName; |
| } else { |
| detail = url; |
| } |
| } else { |
| detail = node.getId(); |
| } |
| } else if (detail instanceof Solution) { |
| Solution solution = (Solution) detail; |
| detail = solution.shortName(); |
| } |
| details[i] = detail; |
| } |
| return MessageFormat.format(message, details); |
| } |
| |
| private static Object[] flatten(Object... values) { |
| List<Object> flattened = new ArrayList<Object>(); |
| for (Object object : values) { |
| flatten(flattened, object); |
| } |
| return flattened.toArray(new Object[flattened.size()]); |
| } |
| |
| private static void flatten(List<Object> flattened, Object value) { |
| if (value instanceof Object[]) { |
| Object[] child = (Object[]) value; |
| for (Object object : child) { |
| flatten(flattened, object); |
| } |
| } else { |
| flattened.add(value); |
| } |
| } |
| |
| @ClassRule |
| public static TestRule stageCredentialsRule = new ExternalResource() { |
| private UIServices originalService; |
| |
| private UIServices credentialsService; |
| |
| @Override |
| protected void before() throws Throwable { |
| IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(), |
| IProvisioningAgent.SERVICE_NAME); |
| UIServices adminUIService = (UIServices) agent.getService(UIServices.SERVICE_NAME); |
| originalService = adminUIService; |
| credentialsService = new UIServices() { |
| @Override |
| public AuthenticationInfo getUsernamePassword(String location, AuthenticationInfo previousInfo) { |
| if (previousInfo == null) { |
| return getUsernamePassword(location); |
| } |
| return null; |
| } |
| |
| @Override |
| public AuthenticationInfo getUsernamePassword(String location) { |
| if (location != null && location.contains("marketplace-staging")) { |
| return new AuthenticationInfo("testuser", "plaintext", false); |
| } |
| throw new AssertionError("Unexpectedly required authentication for host " + location); |
| } |
| |
| @Override |
| public TrustInfo getTrustInfo(Certificate[][] untrustedChain, String[] unsignedDetail) { |
| throw new AssertionError("Unexpectedly required trustinfo"); |
| } |
| }; |
| agent.registerService(UIServices.SERVICE_NAME, credentialsService); |
| } |
| |
| @Override |
| protected void after() { |
| UIServices originalService = this.originalService; |
| UIServices credentialsService = this.credentialsService; |
| this.originalService = null; |
| this.credentialsService = null; |
| IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(), |
| IProvisioningAgent.SERVICE_NAME); |
| Object currentUIService = agent.getService(UIServices.SERVICE_NAME); |
| if (currentUIService == credentialsService && originalService != null) { |
| agent.registerService(UIServices.SERVICE_NAME, originalService); |
| } |
| } |
| }; |
| |
| @Rule |
| public final TestRule xmlDumpRule = new TestWatcher() { |
| |
| private ServiceRegistration<IMarketplaceUnmarshaller> unmarshallerRegistration; |
| |
| @Override |
| protected void starting(final Description description) { |
| final IMarketplaceUnmarshaller marketplaceUnmarshaller = org.eclipse.epp.mpc.core.service.ServiceHelper |
| .getMarketplaceUnmarshaller(); |
| unmarshallerRegistration = MarketplaceClientCorePlugin.getDefault().getServiceHelper() |
| .registerMarketplaceUnmarshaller(new IMarketplaceUnmarshaller() { |
| |
| public <T> T unmarshal(InputStream in, Class<T> type, IProgressMonitor monitor) |
| throws UnmarshalException, IOException { |
| byte[] input = capture(in); |
| in = null; |
| try { |
| return marketplaceUnmarshaller |
| .unmarshal(new ByteArrayInputStream(input), type, monitor); |
| } catch (UnmarshalException ex) { |
| dump(description, ex, input); |
| throw ex; |
| } catch (IOException ex) { |
| dump(description, ex, input); |
| throw ex; |
| } catch (RuntimeException ex) { |
| dump(description, ex, input); |
| throw ex; |
| } |
| } |
| |
| private byte[] capture(InputStream in) throws IOException { |
| try { |
| ByteArrayOutputStream dump = new ByteArrayOutputStream(32768); |
| byte[] buffer = new byte[8192]; |
| for (int read = -1; (read = in.read(buffer)) != -1;) { |
| dump.write(buffer, 0, read); |
| } |
| byte[] input = dump.toByteArray(); |
| return input; |
| } finally { |
| in.close(); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| protected void finished(Description description) { |
| if (unmarshallerRegistration != null) { |
| unmarshallerRegistration.unregister(); |
| } |
| } |
| |
| void dump(Description description, Throwable ex, byte[] input) { |
| String fileName = description.getDisplayName() + "_" |
| + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()); |
| fileName = safeFileName(fileName); |
| File outputDir = findOutputDir(); |
| File dumpFile = new File(outputDir, fileName + "-response.dump"); |
| for (int i = 1; dumpFile.exists(); i++) { |
| dumpFile = new File(outputDir, fileName + "_" + i + "-response.dump"); |
| } |
| failed(new AssertionError("Dumping XML stream to " + dumpFile.getAbsolutePath()), description); |
| FileOutputStream os = null; |
| try { |
| os = new FileOutputStream(dumpFile); |
| os.write(input); |
| } catch (Exception e) { |
| failed(e, description); |
| } finally { |
| if (os != null) { |
| try { |
| os.close(); |
| } catch (IOException e) { |
| failed(e, description); |
| } |
| } |
| } |
| } |
| |
| private File findOutputDir() { |
| File targetDir = new File("target"); |
| if (targetDir.isDirectory()) { |
| File sureFireDir = new File(targetDir, "surefire-reports"); |
| if (sureFireDir.isDirectory()) { |
| return sureFireDir.getAbsoluteFile(); |
| } |
| return targetDir.getAbsoluteFile(); |
| } |
| URL resource = SolutionCompatibilityFilterTest.class.getResource("SolutionCompatibilityFilterTest.class"); |
| if (resource != null) { |
| try { |
| resource = FileLocator.resolve(resource); |
| if ("file".equalsIgnoreCase(resource.getProtocol())) { |
| for (File file = new File(resource.toURI()); file != null && file.exists(); file = file |
| .getParentFile()) { |
| targetDir = new File(file, "target"); |
| if (targetDir.isDirectory()) { |
| File sureFireDir = new File(targetDir, "surefire-reports"); |
| if (sureFireDir.isDirectory()) { |
| return sureFireDir.getAbsoluteFile(); |
| } |
| return targetDir.getAbsoluteFile(); |
| } |
| } |
| } |
| } catch (Exception e) { |
| } |
| } |
| return new File(java.lang.System.getProperty("user.dir")); |
| } |
| |
| private String safeFileName(String text) { |
| char[] fileName = text.toCharArray(); |
| for (int i = 0; i < fileName.length; i++) { |
| char c = fileName[i]; |
| if (!((c >= 48 && c <= 57 /* [0-9] */) || (c >= 65 && c <= 90 /* [A-Z] */) |
| || (c >= 97 && c <= 122 /* [a-z] */) || c == 45 /* - */|| c == 46 /* . */|| c == 95 /* _ */)) { |
| fileName[i] = '_'; |
| } |
| } |
| return new String(fileName); |
| } |
| }; |
| |
| @Rule |
| public TestRule logRule = new TestRule() { |
| |
| public Statement apply(final Statement base, final Description description) { |
| return LoggingSuite.isLogging() ? base : new Statement() { |
| @Override |
| public void evaluate() throws Throwable { |
| try { |
| log("Starting test " + description.getDisplayName()); |
| base.evaluate(); |
| } finally { |
| log("Finished test " + description.getDisplayName()); |
| } |
| } |
| |
| private void log(String message) { |
| MarketplaceClientCore.error(message, null); |
| java.lang.System.out.println(message); |
| } |
| }; |
| } |
| }; |
| |
| @Rule |
| public TestRule requestInfoRule = new TestRule() { |
| public Statement apply(final Statement base, final Description description) { |
| String methodName = description.getMethodName(); |
| if (methodName.contains("SearchResult")) { |
| return new Statement() { |
| @Override |
| public void evaluate() throws Throwable { |
| try { |
| base.evaluate(); |
| } catch (AssertionError t) { |
| failedSearchQuery(t, description); |
| } |
| } |
| }; |
| } else { |
| return new Statement() { |
| @Override |
| public void evaluate() throws Throwable { |
| try { |
| base.evaluate(); |
| } catch (AssertionError t) { |
| failedNodeQuery(t, description); |
| } |
| } |
| }; |
| } |
| } |
| |
| protected void failedSearchQuery(AssertionError error, Description description) { |
| String request = marketplaceService.addMetaParameters(BASE_URL + "/" |
| + DefaultMarketplaceService.API_SEARCH_URI_FULL + solution.query()); |
| String queryDetail = "Unexpected result in search for node " + solution.shortName() + "\n " + request; |
| failedWithDetails(error, queryDetail); |
| } |
| |
| protected void failedNodeQuery(AssertionError error, Description description) { |
| String queryDetail = "Unexpected result in query for node " + solution.shortName() + "\n " |
| + marketplaceService.addMetaParameters(solution.url() + "/api/p"); |
| failedWithDetails(error, queryDetail); |
| } |
| |
| protected void failedWithDetails(AssertionError error, String queryDetail) throws AssertionError { |
| String message = error.getMessage() == null ? queryDetail : queryDetail + "\n\n" + error.getMessage(); |
| |
| String testDescription = SolutionCompatibilityFilterTest.this.testDescription; |
| if (testDescription != null) { |
| message = testDescription + "\n\n" + message; |
| } |
| throw adaptAssertionError(error, message); |
| } |
| |
| protected AssertionError adaptAssertionError(AssertionError error, String message) { |
| if (message == null || message.equals(error.getMessage())) { |
| return error; |
| } |
| |
| AssertionError newError; |
| if (error.getClass() == AssertionError.class) { |
| newError = new AssertionError(message); |
| } else if (error.getClass() == ComparisonFailure.class) { |
| ComparisonFailure comparisonFailure = (ComparisonFailure) error; |
| newError = new ComparisonFailure(message, comparisonFailure.getExpected(), comparisonFailure |
| .getActual()); |
| } else { |
| newError = new AssertionError(message); |
| newError.initCause(error); |
| } |
| newError.setStackTrace(error.getStackTrace()); |
| return newError; |
| } |
| }; |
| |
| @Parameter(0) |
| public Solution solution; |
| |
| @Parameter(1) |
| public EclipseRelease eclipseRelease; |
| |
| @Parameter(2) |
| public System system; |
| |
| @Parameter(3) |
| public String version; |
| |
| @Parameter(4) |
| public String site; |
| |
| @Parameter(5) |
| public String[] features; |
| |
| @Parameter(6) |
| public boolean compatible; |
| |
| @Parameter(7) |
| public String testDescription; |
| |
| private DefaultMarketplaceService marketplaceService; |
| |
| @Before |
| public void setupMarketplaceService() throws Exception { |
| marketplaceService = new DefaultMarketplaceService(new URL(BASE_URL)); |
| marketplaceService.setRequestMetaParameters(computeRequestMetaParameters(system, eclipseRelease)); |
| } |
| |
| protected Map<String, String> computeRequestMetaParameters(System system, EclipseRelease eclipseRelease) { |
| Map<String, String> requestMetaParameters = ServiceLocator.computeDefaultRequestMetaParameters(); |
| system.applyTo(requestMetaParameters); |
| eclipseRelease.applyTo(requestMetaParameters); |
| return requestMetaParameters; |
| } |
| |
| protected INode queryNode() throws CoreException { |
| INode node = marketplaceService.getNode(QueryHelper.nodeByUrl(solution.url()), new NullProgressMonitor()); |
| assertNotNull("Node {0} not found", node); |
| if (solution.id() != null) { |
| assertEquals("Node {2} returned with wrong id {1}", solution.id(), node.getId(), solution); |
| } |
| if (solution.url() != null) { |
| assertEquals("Node {2} returned with wrong url {1}", solution.url(), node.getUrl(), solution); |
| } |
| return node; |
| } |
| |
| protected INode searchForNode() throws CoreException { |
| ISearchResult searchResult = marketplaceService.search(null, null, solution.query(), new NullProgressMonitor()); |
| assertSearchResultSanity(searchResult); |
| List<? extends INode> nodes = searchResult.getNodes(); |
| INode foundNode = null; |
| for (INode node : nodes) { |
| if ((solution.id() != null && solution.id().equals(node.getId())) |
| || (solution.url() != null && solution.url().equals(node.getUrl()))) { |
| foundNode = node; |
| break; |
| } |
| } |
| return foundNode; |
| } |
| |
| protected void assertSearchResultSanity(ISearchResult result) { |
| assertNotNull("Search result is null", result); |
| assertNotNull("Result node list is null (internal error)", result.getNodes()); |
| assertNotNull("Result match count is null ('count' attribute missing)", result.getMatchCount()); |
| assertTrue("Total search result count {1} has to be at least the number of returned nodes {2}", result |
| .getMatchCount() >= result.getNodes().size(), result.getMatchCount(), result.getNodes().size()); |
| |
| Set<String> ids = new HashSet<String>(); |
| for (INode node : result.getNodes()) { |
| assertNotNull("Search result node {1} without id", node.getId(), node); |
| assertTrue("Duplicate search result node {1}", ids.add(node.getId()), node); |
| } |
| } |
| |
| @Test |
| public void testNodeQuery() throws CoreException { |
| if (compatible) { |
| if (solution.installable()) { |
| testCompatibleInstallableNode(); |
| } else { |
| testCompatibleNonInstallableNode(); |
| } |
| } else { |
| testIncompatibleNode(); |
| } |
| } |
| |
| public void testCompatibleInstallableNode() throws CoreException { |
| assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); |
| assumeTrue("Skipping test - this solution is not installable", solution.installable()); |
| INode node = queryNode(); |
| String updateurl = node.getUpdateurl(); |
| assertThat("Node {1} has no update url", updateurl, not(isEmptyOrNullString()), node); |
| IIus ius = node.getIus(); |
| assertNotNull("Node {1} is missing <ius> element", ius, node); |
| List<IIu> iuElements = ius.getIuElements(); |
| assertNotNull(iuElements); |
| assertThat("Node {1} has no IUs", iuElements, not(empty()), node); |
| |
| if (version != null) { |
| assertEquals("Node {2} has wrong version", version, node.getVersion(), node); |
| } |
| if (site != null) { |
| assertEquals("Node {2} has wrong update site", site, node.getUpdateurl(), node); |
| } |
| if (features != null) { |
| Set<String> allIUs = new HashSet<String>(); |
| for (IIu iu : iuElements) { |
| allIUs.add(iu.getId()); |
| } |
| assertThat("Node {1} is missing some features", allIUs, hasItems(features), node); |
| assertThat("Node {1} has some unexpected features", allIUs, hasSize(features.length), node); |
| } |
| } |
| |
| public void testCompatibleNonInstallableNode() throws CoreException { |
| assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); |
| assumeFalse("Skipping test - this solution is installable", solution.installable()); |
| INode node = queryNode(); |
| String updateurl = node.getUpdateurl(); |
| assertNull("Uninstallable node {1} should not have an update url, but has {0}", updateurl, node); |
| IIus ius = node.getIus(); |
| assertNull("Uninstallable node {1} should not have an <ius> element", ius, node); |
| } |
| |
| public void testIncompatibleNode() throws CoreException { |
| assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible); |
| INode node = queryNode(); |
| String updateurl = node.getUpdateurl(); |
| assertNull("Incompatible node {1} should not have an update url, but has {0}", updateurl, node); |
| IIus ius = node.getIus(); |
| assertNull("Incompatible node {1} should not have an <ius> element", ius, node); |
| } |
| |
| @Test |
| public void testSearchResult() throws CoreException { |
| if (compatible) { |
| testCompatibleSearchResult(); |
| } else { |
| testIncompatibleSearchResult(); |
| } |
| } |
| |
| public void testCompatibleSearchResult() throws CoreException { |
| assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); |
| INode foundNode = searchForNode(); |
| assertNotNull("Compatible node {1} not found in search", foundNode, solution); |
| } |
| |
| public void testIncompatibleSearchResult() throws CoreException { |
| assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible); |
| INode foundNode = searchForNode(); |
| assertNull("Incompatible node {0} found in search", foundNode); |
| } |
| } |