org.grails.ide.eclipse.test.util.AbstractGrailsJUnitIntegrationsTest.java Source code

Java tutorial

Introduction

Here is the source code for org.grails.ide.eclipse.test.util.AbstractGrailsJUnitIntegrationsTest.java

Source

/*******************************************************************************
 * Copyright (c) 2012 VMWare, Inc.
 * 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
 * https://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     VMWare, Inc. - initial API and implementation
 *******************************************************************************/
package org.grails.ide.eclipse.test.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.internal.junit.launcher.ITestFinder;
import org.eclipse.jdt.internal.junit.launcher.ITestKind;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.JUnitMigrationDelegate;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
import org.eclipse.jdt.internal.junit.model.TestCaseElement;
import org.eclipse.jdt.internal.junit.model.TestElement;
import org.eclipse.jdt.internal.junit.model.TestRunSession;
import org.eclipse.jdt.junit.JUnitCore;
import org.eclipse.jdt.junit.TestRunListener;
import org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate;
import org.eclipse.jdt.junit.model.ITestElement;
import org.eclipse.jdt.junit.model.ITestElementContainer;
import org.eclipse.jdt.junit.model.ITestRunSession;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition;
import org.springsource.ide.eclipse.commons.tests.util.StsTestUtil;

/**
 * @author Kris De Volder
 *
 * @since 2.9
 */
public class AbstractGrailsJUnitIntegrationsTest extends GrailsTest {

    public static class MockTestRunListener extends TestRunListener {
        public ITestRunSession session = null; //captured when the session ends.

        @Override
        public void sessionFinished(ITestRunSession session) {
            assertNull(this.session);
            this.session = session;
        }
    }

    public static ITestFinder getJUnit4TestFinder() {
        String testKind = TestKindRegistry.JUNIT4_TEST_KIND_ID;
        return getTestFinder(testKind);
    }

    public static ITestFinder getTestFinder(String testKind) {
        TestKindRegistry registry = TestKindRegistry.getDefault();
        ITestKind junit4kind = registry.getKind(testKind);
        ITestFinder finder = junit4kind.getFinder();
        return finder;
    }

    /**
     * Constructs a class loader based on the given javaProject's resolved runtime classpath, using
     * a launch configuration equivalent to the one created by "run as >> JUnit test" launch shortcut.
     */
    public static URLClassLoader getRuntimeClassLoader(IJavaProject javaProject)
            throws CoreException, MalformedURLException {
        ILaunchConfigurationWorkingCopy wc = createLaunchConfiguration(javaProject);
        JUnitLaunchConfigurationDelegate delegate = new JUnitLaunchConfigurationDelegate();
        String[] classpath = delegate.getClasspath(wc);
        //            System.out.println(">>> Creating JUnit runtime classloader with entries:");
        URL[] classpathURLs = new URL[classpath.length];
        for (int i = 0; i < classpathURLs.length; i++) {
            //               System.out.println(classpath[i]);
            classpathURLs[i] = new File(classpath[i]).toURI().toURL();
        }
        //            System.out.println("<<< Creating JUnit runtime classloader");
        URLClassLoader classLoader = new URLClassLoader(classpathURLs);
        return classLoader;
    }

    /**
     * COPIED from JUnitLaunchShortcut... create a JUnit lauch config just like the one the JUnit UI would.
     */
    public static ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element)
            throws CoreException {
        final String testName;
        final String mainTypeQualifiedName;
        final String containerHandleId;

        switch (element.getElementType()) {
        case IJavaElement.JAVA_PROJECT:
        case IJavaElement.PACKAGE_FRAGMENT_ROOT:
        case IJavaElement.PACKAGE_FRAGMENT: {
            String name = element.getElementName();
            containerHandleId = element.getHandleIdentifier();
            mainTypeQualifiedName = "";
            testName = name.substring(name.lastIndexOf(IPath.SEPARATOR) + 1);
        }
            break;
        case IJavaElement.TYPE: {
            containerHandleId = "";
            mainTypeQualifiedName = ((IType) element).getFullyQualifiedName('.'); // don't replace, fix for binary inner types
            testName = element.getElementName();
        }
            break;
        case IJavaElement.METHOD: {
            IMethod method = (IMethod) element;
            containerHandleId = "";
            mainTypeQualifiedName = method.getDeclaringType().getFullyQualifiedName('.');
            testName = method.getDeclaringType().getElementName() + '.' + method.getElementName();
        }
            break;
        default:
            throw new IllegalArgumentException(
                    "Invalid element type to create a launch configuration: " + element.getClass().getName()); //$NON-NLS-1$
        }

        String testKindId = TestKindRegistry.getContainerTestKindId(element);

        ILaunchConfigurationType configType = getLaunchManager()
                .getLaunchConfigurationType(JUnitLaunchConfigurationConstants.ID_JUNIT_APPLICATION);
        ILaunchConfigurationWorkingCopy wc = configType.newInstance(null,
                getLaunchManager().generateLaunchConfigurationName(testName));

        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, mainTypeQualifiedName);
        wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
                element.getJavaProject().getElementName());
        wc.setAttribute(JUnitLaunchConfigurationConstants.ATTR_KEEPRUNNING, false);
        wc.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, containerHandleId);
        wc.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, testKindId);
        JUnitMigrationDelegate.mapResources(wc);
        //AssertionVMArg.setArgDefault(wc);
        if (element instanceof IMethod) {
            wc.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, element.getElementName()); // only set for methods
        }
        return wc;
    }

    /**
     * COPIED from JUnitLaunchShortcut... create a JUnit launch config just like the one the JUnit UI would.
     */
    public static ILaunchManager getLaunchManager() {
        return DebugPlugin.getDefault().getLaunchManager();
    }

    /**
     * Assert that a given test run session contains a certain test, which failed, and who's
     * stacktrace contains a given String.
     * <p>
     * The test is identified by a 'path' where each segment of the path is the name of a Test element in
     * the test tree, leading to a test of interest.
     */
    public static void assertTestFailure(ITestRunSession session, String expectedFailureSnippet,
            String... pathToTest) {
        ITestElement node = findTestNode(session, pathToTest, 0);
        TestCaseElement element = (TestCaseElement) node;
        assertEquals(TestElement.Status.FAILURE, element.getStatus());
        assertContains(expectedFailureSnippet, element.getTrace());
    }

    public static ITestElement findTestNode(ITestElement node, String[] pathToTest, int pos) {
        if (pos < pathToTest.length) {
            String head = pathToTest[pos];
            if (node instanceof ITestElementContainer) {
                ITestElementContainer container = (ITestElementContainer) node;
                for (ITestElement child : container.getChildren()) {
                    if (head.equals(getName(child))) {
                        return findTestNode(child, pathToTest, pos + 1);
                    }
                    System.out.println(child);
                }
            }
            fail("Test not found: " + head);
        } else {
            return node;
        }
        return null; //Unreachable because of 'fail' calls above, but Java compiler doesn't know this.
    }

    public static String getName(ITestElement child) {
        if (child instanceof TestElement) {
            String name = ((TestElement) child).getTestName();
            int chop = name.indexOf('(');
            if (chop >= 0) {
                name = name.substring(0, chop);
            }
            return name;
        }
        return null;
    }

    public static TestRunSession runAsJUnit(IJavaElement element) throws CoreException, Exception, DebugException {
        StsTestUtil.assertNoErrors(element.getJavaProject().getProject()); //This is to avoid trying to run a project with errors...
        // Trying to do so would hang the test when debug UI pops up a dialog.
        ILaunchConfigurationWorkingCopy launchConf = createLaunchConfiguration(element);
        final MockTestRunListener listener = new MockTestRunListener();
        JUnitCore.addTestRunListener(listener);
        try {
            final ILaunch launch = launchConf.launch(ILaunchManager.RUN_MODE, new NullProgressMonitor(), true);

            new ACondition() {
                @Override
                public boolean test() throws Exception {
                    return listener.session != null && launch.isTerminated();
                }
            }.waitFor(80000);
            assertEquals(0, launch.getProcesses()[0].getExitValue());

        } finally {
            JUnitCore.removeTestRunListener(listener);
        }
        return (TestRunSession) listener.session;
    }

}