| /******************************************************************************* |
| * Copyright (c) 2011, 2014 Tasktop Technologies and others. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * https://www.eclipse.org/legal/epl-2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Tasktop Technologies - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.commons.sdk.util; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.io.UnsupportedEncodingException; |
| import java.io.Writer; |
| import java.net.Proxy; |
| import java.net.ProxySelector; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| import java.nio.charset.Charset; |
| import java.util.Enumeration; |
| import java.util.Map.Entry; |
| import java.util.Properties; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| |
| import org.apache.commons.lang.reflect.MethodUtils; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.mylyn.commons.core.CoreUtil; |
| import org.eclipse.mylyn.commons.core.net.NetUtil; |
| import org.eclipse.mylyn.commons.net.WebUtil; |
| import org.eclipse.mylyn.commons.repositories.core.auth.CertificateCredentials; |
| import org.eclipse.mylyn.commons.repositories.core.auth.UserCredentials; |
| import org.eclipse.mylyn.internal.commons.net.CommonsNetPlugin; |
| import org.eclipse.osgi.service.resolver.VersionRange; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.Bundle; |
| |
| import junit.framework.AssertionFailedError; |
| |
| /** |
| * @author Steffen Pingel |
| */ |
| @SuppressWarnings("restriction") |
| public class CommonTestUtil { |
| |
| public enum PrivilegeLevel { |
| ADMIN, ANONYMOUS, GUEST, READ_ONLY, USER |
| } |
| |
| public static final String KEY_CREDENTIALS_FILE = "mylyn.credentials"; |
| |
| private static final String KEY_IGNORE_LOCAL_SERVICES = "org.eclipse.mylyn.tests.ignore.local.services"; |
| |
| private final static int MAX_RETRY = 5; |
| |
| /** |
| * Returns the given file path with its separator character changed from the given old separator to the given new |
| * separator. |
| * |
| * @param path |
| * a file path |
| * @param oldSeparator |
| * a path separator character |
| * @param newSeparator |
| * a path separator character |
| * @return the file path with its separator character changed from the given old separator to the given new |
| * separator |
| */ |
| public static String changeSeparator(String path, char oldSeparator, char newSeparator) { |
| return path.replace(oldSeparator, newSeparator); |
| } |
| |
| /** |
| * Copies the given source file to the given destination file. |
| */ |
| public static void copy(File source, File dest) throws IOException { |
| try (InputStream in = new FileInputStream(source); |
| OutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) { |
| transferData(in, out); |
| } |
| } |
| |
| /** |
| * Copies all files in the current data directory to the specified folder. Will overwrite. |
| */ |
| public static void copyFolder(File sourceFolder, File targetFolder) throws IOException { |
| for (File sourceFile : sourceFolder.listFiles()) { |
| if (sourceFile.isFile()) { |
| File destFile = new File(targetFolder, sourceFile.getName()); |
| copy(sourceFile, destFile); |
| } |
| } |
| } |
| |
| /** |
| * Copies all files in the current data directory to the specified folder. Will overwrite. |
| */ |
| public static void copyFolderRecursively(File sourceFolder, File targetFolder) throws IOException { |
| for (File sourceFile : sourceFolder.listFiles()) { |
| if (sourceFile.isFile()) { |
| File destFile = new File(targetFolder, sourceFile.getName()); |
| copy(sourceFile, destFile); |
| } else if (sourceFile.isDirectory()) { |
| File destDir = new File(targetFolder, sourceFile.getName()); |
| if (!destDir.exists()) { |
| if (!destDir.mkdir()) { |
| throw new IOException("Unable to create destination folder: " + destDir.getAbsolutePath()); |
| } |
| } |
| copyFolderRecursively(sourceFile, destDir); |
| } |
| } |
| } |
| |
| public static File createTempFileInPlugin(Plugin plugin, IPath path) { |
| IPath stateLocation = plugin.getStateLocation(); |
| stateLocation = stateLocation.append(path); |
| return stateLocation.toFile(); |
| } |
| |
| public static File createTempFolder(String prefix) throws IOException { |
| File location = File.createTempFile(prefix, null); |
| location.delete(); |
| location.mkdirs(); |
| return location; |
| } |
| |
| public static void delete(File file) { |
| if (file.exists()) { |
| for (int i = 0; i < MAX_RETRY; i++) { |
| if (file.delete()) { |
| i = MAX_RETRY; |
| } else { |
| try { |
| Thread.sleep(1000); // sleep a second |
| } catch (InterruptedException e) { |
| // don't need to catch this |
| } |
| } |
| } |
| } |
| } |
| |
| public static void deleteFolder(File path) { |
| if (path.isDirectory()) { |
| for (File file : path.listFiles()) { |
| file.delete(); |
| } |
| path.delete(); |
| } |
| } |
| |
| public static void deleteFolderRecursively(File path) { |
| File[] files = path.listFiles(); |
| if (files != null) { |
| for (File file : files) { |
| if (file.isDirectory()) { |
| deleteFolderRecursively(file); |
| } else { |
| file.delete(); |
| } |
| } |
| } |
| path.delete(); |
| } |
| |
| public static CertificateCredentials getCertificateCredentials() { |
| File keyStoreFile; |
| try { |
| keyStoreFile = CommonTestUtil.getFile(CommonTestUtil.class, "testdata/keystore"); |
| String password = CommonTestUtil.getUserCredentials().getPassword(); |
| return new CertificateCredentials(keyStoreFile.getAbsolutePath(), password, null); |
| } catch (IOException cause) { |
| AssertionFailedError e = new AssertionFailedError("Failed to load keystore file"); |
| e.initCause(cause); |
| throw e; |
| } |
| } |
| |
| public static boolean hasCredentials(PrivilegeLevel level) { |
| try { |
| CommonTestUtil.getCredentials(level); |
| return true; |
| } catch (AssertionFailedError error) { |
| return false; |
| } |
| } |
| |
| public static UserCredentials getCredentials(PrivilegeLevel level) { |
| return getCredentials(level, null); |
| } |
| |
| public static UserCredentials getCredentials(PrivilegeLevel level, String realm) { |
| Properties properties = new Properties(); |
| try { |
| File file; |
| String filename = System.getProperty(KEY_CREDENTIALS_FILE); |
| if (filename != null) { |
| // 1. use user specified file |
| file = new File(filename); |
| } else { |
| // 2. check in home directory |
| file = new File(new File(System.getProperty("user.home"), ".mylyn"), "credentials.properties"); |
| if (!file.exists()) { |
| // 3. fall back to included credentials file |
| file = getFile(CommonTestUtil.class, "testdata/credentials.properties"); |
| } |
| } |
| properties.load(new FileInputStream(file)); |
| } catch (Exception e) { |
| AssertionFailedError error = new AssertionFailedError( |
| "must define credentials in $HOME/.mylyn/credentials.properties"); |
| error.initCause(e); |
| throw error; |
| } |
| |
| String defaultPassword = properties.getProperty("pass"); |
| |
| realm = (realm != null) ? realm + "." : ""; |
| switch (level) { |
| case ANONYMOUS: |
| return createCredentials(properties, realm + "anon.", "", ""); |
| case GUEST: |
| return createCredentials(properties, realm + "guest.", "guest@mylyn.eclipse.org", defaultPassword); |
| case USER: |
| return createCredentials(properties, realm, "tests@mylyn.eclipse.org", defaultPassword); |
| case READ_ONLY: |
| return createCredentials(properties, realm, "read-only@mylyn.eclipse.org", defaultPassword); |
| case ADMIN: |
| return createCredentials(properties, realm + "admin.", "admin@mylyn.eclipse.org", null); |
| } |
| |
| throw new AssertionFailedError("invalid privilege level"); |
| } |
| |
| private static boolean isOsgiVersion310orNewer(ClassLoader classLoader) { |
| return classLoader.getClass().getName().equals("org.eclipse.osgi.internal.loader.ModuleClassLoader") // user before 4.4M4 |
| || classLoader.getClass().getName().equals("org.eclipse.osgi.internal.loader.EquinoxClassLoader"); |
| } |
| |
| public static File getFile(Object source, String filename) throws IOException { |
| Class<?> clazz = (source instanceof Class<?>) ? (Class<?>) source : source.getClass(); |
| if (Platform.isRunning()) { |
| ClassLoader classLoader = clazz.getClassLoader(); |
| try { |
| if (isOsgiVersion310orNewer(classLoader)) { |
| return checkNotNull(getFileFromClassLoader4Luna(filename, classLoader)); |
| } else { |
| return checkNotNull(getFileFromClassLoaderBeforeLuna(filename, classLoader)); |
| } |
| } catch (Exception e) { |
| AssertionFailedError exception = new AssertionFailedError( |
| NLS.bind("Could not locate {0} using classloader for {1}", filename, clazz)); |
| exception.initCause(e); |
| throw exception; |
| } |
| } else { |
| return getFileFromNotRunningPlatform(filename, clazz); |
| } |
| } |
| |
| private static File getFileFromNotRunningPlatform(String filename, Class<?> clazz) |
| throws UnsupportedEncodingException, IOException { |
| URL localURL = clazz.getResource(""); |
| String path = URLDecoder.decode(localURL.getFile(), Charset.defaultCharset().name()); |
| int i = path.indexOf("!"); |
| if (i != -1) { |
| int j = path.lastIndexOf(File.separatorChar, i); |
| if (j != -1) { |
| path = path.substring(0, j) + File.separator; |
| } else { |
| throw new AssertionFailedError("Unable to determine location for '" + filename + "' at '" + path + "'"); |
| } |
| // class file is nested in jar, use jar path as base |
| if (path.startsWith("file:")) { |
| path = path.substring(5); |
| } |
| return new File(path + filename); |
| } else { |
| // remove all package segments from name |
| String directory = clazz.getName().replaceAll("[^.]", ""); |
| directory = directory.replaceAll(".", "../"); |
| if (path.contains("/bin/")) { |
| // account for bin/ when running from Eclipse workspace |
| directory += "../"; |
| } else if (path.contains("/target/classes/")) { |
| // account for bin/ when running from Eclipse workspace |
| directory += "../../"; |
| } |
| filename = path + (directory + filename).replaceAll("/", Matcher.quoteReplacement(File.separator)); |
| return new File(filename).getCanonicalFile(); |
| } |
| } |
| |
| private static File getFileFromClassLoaderBeforeLuna(String filename, ClassLoader classLoader) throws Exception { |
| Object classpathManager = MethodUtils.invokeExactMethod(classLoader, "getClasspathManager", null); |
| Object baseData = MethodUtils.invokeExactMethod(classpathManager, "getBaseData", null); |
| Bundle bundle = (Bundle) MethodUtils.invokeExactMethod(baseData, "getBundle", null); |
| URL localURL = FileLocator.toFileURL(bundle.getEntry(filename)); |
| return new File(localURL.getFile()); |
| } |
| |
| private static File getFileFromClassLoader4Luna(String filename, ClassLoader classLoader) throws Exception { |
| Object classpathManager = MethodUtils.invokeExactMethod(classLoader, "getClasspathManager", null); |
| Object generation = MethodUtils.invokeExactMethod(classpathManager, "getGeneration", null); |
| Object bundleFile = MethodUtils.invokeExactMethod(generation, "getBundleFile", null); |
| File file = (File) MethodUtils.invokeExactMethod(bundleFile, "getFile", new Object[] { filename, true }, |
| new Class[] { String.class, boolean.class }); |
| return file; |
| } |
| |
| public static InputStream getResource(Object source, String filename) throws IOException { |
| Class<?> clazz = (source instanceof Class<?>) ? (Class<?>) source : source.getClass(); |
| ClassLoader classLoader = clazz.getClassLoader(); |
| InputStream in = classLoader.getResourceAsStream(filename); |
| if (in == null) { |
| File file = getFile(source, filename); |
| if (file != null) { |
| return new FileInputStream(file); |
| } |
| } |
| if (in == null) { |
| throw new IOException(NLS.bind("Failed to locate ''{0}'' for ''{1}''", filename, clazz.getName())); |
| } |
| return in; |
| } |
| |
| public static UserCredentials getUserCredentials() { |
| return getCredentials(PrivilegeLevel.USER, null); |
| } |
| |
| public static String read(File source) throws IOException { |
| InputStream in = new FileInputStream(source); |
| try { |
| StringBuilder sb = new StringBuilder(); |
| byte[] buf = new byte[1024]; |
| int len; |
| while ((len = in.read(buf)) > 0) { |
| sb.append(new String(buf, 0, len)); |
| } |
| return sb.toString(); |
| } finally { |
| in.close(); |
| } |
| } |
| |
| /** |
| * Returns whether to run a limited suite of tests. Returns true, unless a system property has been set to force |
| * running of all tests. |
| */ |
| public static boolean runHeartbeatTestsOnly() { |
| return !Boolean.parseBoolean(System.getProperty("org.eclipse.mylyn.tests.all")); |
| } |
| |
| /** |
| * Unzips the given zip file to the given destination directory extracting only those entries the pass through the |
| * given filter. |
| * |
| * @param zipFile |
| * the zip file to unzip |
| * @param dstDir |
| * the destination directory |
| * @throws IOException |
| * in case of problem |
| */ |
| public static void unzip(ZipFile zipFile, File dstDir) throws IOException { |
| unzip(zipFile, dstDir, dstDir, 0); |
| } |
| |
| public static void write(String fileName, StringBuffer content) throws IOException { |
| Writer writer = new FileWriter(fileName); |
| try { |
| writer.write(content.toString()); |
| } finally { |
| try { |
| writer.close(); |
| } catch (IOException e) { |
| // don't need to catch this |
| } |
| } |
| } |
| |
| private static UserCredentials createCredentials(Properties properties, String prefix, String defaultUsername, |
| String defaultPassword) { |
| String username = properties.getProperty(prefix + "user"); |
| String password = properties.getProperty(prefix + "pass"); |
| |
| if (username == null) { |
| username = defaultUsername; |
| } |
| |
| if (password == null) { |
| password = defaultPassword; |
| } |
| |
| if (username == null || password == null) { |
| throw new AssertionFailedError("username or password not found for " + prefix |
| + " in <plug-in dir>/credentials.properties, make sure file is valid"); |
| } |
| |
| return new UserCredentials(username, password); |
| } |
| |
| /** |
| * Copies all bytes in the given source stream to the given destination stream. Neither streams are closed. |
| * |
| * @param source |
| * the given source stream |
| * @param destination |
| * the given destination stream |
| * @throws IOException |
| * in case of error |
| */ |
| private static void transferData(InputStream in, OutputStream out) throws IOException { |
| byte[] buf = new byte[1024]; |
| int len; |
| while ((len = in.read(buf)) > 0) { |
| out.write(buf, 0, len); |
| } |
| } |
| |
| private static void unzip(ZipFile zipFile, File rootDstDir, File dstDir, int depth) throws IOException { |
| |
| Enumeration<? extends ZipEntry> entries = zipFile.entries(); |
| |
| try { |
| while (entries.hasMoreElements()) { |
| ZipEntry entry = entries.nextElement(); |
| if (entry.isDirectory()) { |
| continue; |
| } |
| String entryName = entry.getName(); |
| File file = new File(dstDir, changeSeparator(entryName, '/', File.separatorChar)); |
| file.getParentFile().mkdirs(); |
| try (InputStream src = zipFile.getInputStream(entry); |
| OutputStream dst = new BufferedOutputStream(new FileOutputStream(file))) { |
| transferData(src, dst); |
| } |
| } |
| } finally { |
| try { |
| zipFile.close(); |
| } catch (IOException e) { |
| // don't need to catch this |
| } |
| } |
| } |
| |
| public static boolean isCertificateAuthBroken() { |
| // not entirely correct since 1.6.0_3 would also satisfy this check but it should be sufficient in reality |
| return new VersionRange("[0.0.0,1.6.0.25]").isIncluded(CoreUtil.getRuntimeVersion()); |
| } |
| |
| public static boolean hasCertificateCredentials() { |
| try { |
| CommonTestUtil.getCertificateCredentials(); |
| return true; |
| } catch (AssertionFailedError error) { |
| return false; |
| } |
| } |
| |
| public static String getShortUserName(UserCredentials credentials) { |
| String username = credentials.getUserName(); |
| if (username.contains("@")) { |
| return username.substring(0, username.indexOf("@")); |
| } |
| return username; |
| } |
| |
| /** |
| * Activates manual proxy configuration in the Ecipse proxy service if system proxy support is not available. This |
| * sets proxy configuration to Java system properties. |
| * <p> |
| * This work around is required on e3.5/gtk.x86_64 where system proxy settings get enabled but the proxy |
| * configuration is not actually detected resulting in a broken configuration. |
| * <p> |
| * Please note that this only works for http proxies. The https proxy system property is ignored. |
| * |
| * @see #isHttpsProxyBroken() |
| */ |
| public static boolean fixProxyConfiguration() { |
| if (Platform.isRunning() && CommonsNetPlugin.getProxyService() != null |
| && CommonsNetPlugin.getProxyService().isSystemProxiesEnabled() |
| && !CommonsNetPlugin.getProxyService().hasSystemProxies()) { |
| System.err.println("Forcing manual proxy configuration"); |
| CommonsNetPlugin.getProxyService().setSystemProxiesEnabled(false); |
| CommonsNetPlugin.getProxyService().setProxiesEnabled(true); |
| return true; |
| } |
| return false; |
| } |
| |
| public static void dumpSystemInfo(PrintStream out) { |
| Properties p = System.getProperties(); |
| if (Platform.isRunning()) { |
| p.put("build.system", Platform.getOS() + "-" + Platform.getOSArch() + "-" + Platform.getWS()); |
| } else { |
| p.put("build.system", "standalone"); |
| } |
| String info = "System: ${os.name} ${os.version} (${os.arch}) / ${build.system} / ${java.vendor} ${java.vm.name} ${java.version}"; |
| for (Entry<Object, Object> entry : p.entrySet()) { |
| info = info.replaceFirst(Pattern.quote("${" + entry.getKey() + "}"), entry.getValue().toString()); |
| } |
| out.println(info); |
| out.print("HTTP Proxy : " + WebUtil.getProxyForUrl("http://mylyn.org") + " (Platform)"); |
| try { |
| out.print(" / " + ProxySelector.getDefault().select(new URI("http://mylyn.org")) + " (Java)"); |
| } catch (URISyntaxException e) { |
| // ignore |
| } |
| out.println(); |
| out.print("HTTPS Proxy : " + WebUtil.getProxyForUrl("https://mylyn.org") + " (Platform)"); |
| try { |
| out.print(" / " + ProxySelector.getDefault().select(new URI("https://mylyn.org")) + " (Java)"); |
| } catch (URISyntaxException e) { |
| // ignore |
| } |
| out.println(); |
| out.println(); |
| } |
| |
| public static boolean isEclipse4() { |
| return Platform.getBundle("org.eclipse.e4.core.commands") != null; |
| } |
| |
| /** |
| * If Eclipse proxy configuration is set to manual https proxies aren't detected and hence tests that rely on https |
| * connections may fail. Use this method to detect whether https is configured correctly. |
| * |
| * @see #fixProxyConfiguration() |
| */ |
| public static boolean isHttpsProxyBroken() { |
| // checks if http and https proxy configuration matches |
| Proxy httpProxy = WebUtil.getProxyForUrl("http://mylyn.org"); |
| Proxy httpsProxy = WebUtil.getProxyForUrl("https://mylyn.org"); |
| return CoreUtil.areEqual(httpProxy, httpsProxy); |
| } |
| |
| /** |
| * Returns whether to run on local services if present. Returns false, unless a system property has been set to |
| * force to ignore local running services. |
| */ |
| public static boolean ignoreLocalTestServices() { |
| return Boolean.parseBoolean(System.getProperty(KEY_IGNORE_LOCAL_SERVICES)); |
| } |
| |
| public static boolean isBehindProxy() { |
| return NetUtil.getProxyForUrl("https://mylyn.org/secure/index.txt") != null; |
| } |
| |
| public static boolean skipBrowserTests() { |
| return Boolean.parseBoolean(System.getProperty("mylyn.test.skipBrowserTests")); |
| } |
| |
| public static boolean bundleWithNameIsPresent(String name) { |
| Bundle bundle = Platform.getBundle(name); |
| return bundle != null; |
| } |
| |
| } |