com.salesforce.ide.ui.views.runtest.RunTestsLaunchConfigurationDelegate.java Source code

Java tutorial

Introduction

Here is the source code for com.salesforce.ide.ui.views.runtest.RunTestsLaunchConfigurationDelegate.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Salesforce.com, 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
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Salesforce.com, inc. - initial API and implementation
 ******************************************************************************/

package com.salesforce.ide.ui.views.runtest;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.ILaunchGroup;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

import com.google.common.annotations.VisibleForTesting;
import com.salesforce.ide.core.ForceIdeCorePlugin;
import com.salesforce.ide.core.internal.utils.DialogUtils;
import com.salesforce.ide.core.internal.utils.Utils;
import com.salesforce.ide.core.services.hooks.DebugListener;
import com.sforce.soap.tooling.ApexLogLevel;
import com.sforce.soap.tooling.LogCategory;

/**
 * A launch configuration delegate for Apex Test. This gets called when executing
 * a launch config for Apex Test.
 * 
 * @see RunTestsLaunchConfigurationTab.java
 * @author jwidjaja
 *
 */
public class RunTestsLaunchConfigurationDelegate extends LaunchConfigurationDelegate {

    @Override
    public boolean preLaunchCheck(final ILaunchConfiguration configuration, final String mode,
            IProgressMonitor monitor) throws CoreException {
        // Only supported in run mode
        checkMode(mode);

        RunTestsView runTestsView = getRunTestView();
        if (runTestsView != null) {
            // Only allow one run at a time
            if (!runTestsView.canRun()) {
                throwErrorMsg(Messages.LaunchDelegate_CannotLaunchAnotherConfig);
            } else {
                IProject project = materializeForceProject(configuration);
                // Check if user has an Apex Debugging session and wants to run tests asynchronously
                boolean isAsync = getTestMode(configuration);
                boolean isDebugging = isProjectDebugging(project);
                if (isDebugging && isAsync) {
                    // If yes, inform user that asynchronous Apex tests are not debuggable.
                    if (!confirmAsyncTestRunWhileDebugging()) {
                        // If they want to abort, re-open the launch configuration
                        reopenLaunchConfig(configuration, mode);
                        return false;
                    }
                }

                boolean shouldCreateTraceFlag = shouldCreateTraceFlag(configuration);
                boolean hasExistingTraceFlag = runTestsView.hasExistingTraceFlag(project);
                setExistingTraceFlag(configuration, hasExistingTraceFlag);

                if (shouldCreateTraceFlag && hasExistingTraceFlag) {
                    // Check for existing Trace Flags that would hinder with
                    // the new one
                    if (!confirmExistingTraceFlag()) {
                        // If they want to abort, re-open the launch configuration
                        reopenLaunchConfig(configuration, mode);
                        return false;
                    }
                }
            }
        }

        return secondPhasePreLaunchCheck(configuration, mode, monitor);
    }

    @VisibleForTesting
    public boolean secondPhasePreLaunchCheck(ILaunchConfiguration configuration, String mode,
            IProgressMonitor monitor) throws CoreException {
        return super.preLaunchCheck(configuration, mode, monitor);
    }

    @Override
    public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {
        try {
            // Get the Apex Test Results view
            RunTestsView runTestsView = getRunTestView();

            if (runTestsView != null) {
                IProject project = materializeForceProject(configuration);
                boolean shouldUseSuites = shouldUseSuites(configuration);
                String tests = getTests(configuration, shouldUseSuites);
                boolean isAsync = getTestMode(configuration);
                boolean isDebugging = isProjectDebugging(project);
                boolean shouldCreateTraceFlag = shouldCreateTraceFlag(configuration);
                boolean hasExistingTraceFlag = hasExistingTraceFlag(configuration);
                @SuppressWarnings("unchecked")
                Map<LogCategory, ApexLogLevel> logLevels = (Map<LogCategory, ApexLogLevel>) (shouldCreateTraceFlag
                        ? getLogLevels(configuration)
                        : Collections.emptyMap());

                // Run the tests and update UI
                runTestsView.runTests(project, tests, shouldUseSuites, isAsync, isDebugging, hasExistingTraceFlag,
                        shouldCreateTraceFlag, logLevels, monitor);
            }
        } finally {
            removeLaunch(launch);
        }
    }

    @VisibleForTesting
    public void throwErrorMsg(String msg) throws CoreException {
        if (Utils.isNotEmpty(msg)) {
            throw new CoreException(new Status(IStatus.ERROR, ForceIdeCorePlugin.PLUGIN_ID, 0, msg, null));
        }
    }

    @VisibleForTesting
    public boolean isProjectDebugging(IProject project) {
        return DebugListener.isDebugging(project);
    }

    @VisibleForTesting
    public void checkMode(String mode) throws CoreException {
        if (!mode.equals(ILaunchManager.RUN_MODE)) {
            throwErrorMsg(Messages.LaunchDelegate_CannotLaunchDebugModeErrorMessage);
        }
    }

    @VisibleForTesting
    public IProject materializeForceProject(ILaunchConfiguration configuration) throws CoreException {
        String forceProjectName = getProjectName(configuration);
        IProject project = getProjectFromName(forceProjectName);

        if (Utils.isEmpty(project)) {
            throwErrorMsg(Messages.LaunchDelegate_CannotLaunchInvalidForceProject);
        }

        return project;
    }

    @VisibleForTesting
    public String getProjectName(ILaunchConfiguration configuration) throws CoreException {
        return configuration.getAttribute(RunTestsConstants.ATTR_PROJECT_NAME, "");
    }

    @VisibleForTesting
    public IProject getProjectFromName(String name) {
        return ResourcesPlugin.getWorkspace().getRoot().getProject(name);
    }

    @VisibleForTesting
    public boolean shouldUseSuites(ILaunchConfiguration configuration) throws CoreException {
        return configuration.getAttribute(RunTestsConstants.ATTR_USE_SUITES, false);
    }

    @VisibleForTesting
    public String getTests(ILaunchConfiguration configuration, boolean shouldUseSuites) throws CoreException {
        if (shouldUseSuites) {
            // If user wants to use suites, get the suites JSON
            return configuration.getAttribute(RunTestsConstants.ATTR_SUITES, "");
        } else {
            // Otherwise, get the tests json
            return configuration.getAttribute(RunTestsConstants.ATTR_TESTS_ARRAY, "");
        }
    }

    @VisibleForTesting
    public boolean getTestMode(ILaunchConfiguration configuration) throws CoreException {
        // Async = true, sync = false
        return configuration.getAttribute(RunTestsConstants.ATTR_TEST_MODE, true);
    }

    @VisibleForTesting
    public boolean shouldCreateTraceFlag(ILaunchConfiguration configuration) throws CoreException {
        return configuration.getAttribute(RunTestsConstants.ATTR_ENABLE_LOGGING, false);
    }

    private boolean hasExistingTraceFlag(ILaunchConfiguration configuration) throws CoreException {
        return configuration.getAttribute(RunTestsConstants.ATTR_EXISTING_TF, false);
    }

    @VisibleForTesting
    public void setExistingTraceFlag(ILaunchConfiguration configuration, boolean existing) throws CoreException {
        ILaunchConfigurationWorkingCopy realConfig = configuration.getWorkingCopy();
        realConfig.setAttribute(RunTestsConstants.ATTR_EXISTING_TF, existing);
        realConfig.doSave();
    }

    @VisibleForTesting
    public Map<LogCategory, ApexLogLevel> getLogLevels(ILaunchConfiguration configuration) throws CoreException {
        Map<LogCategory, ApexLogLevel> finalLogLevels = new LinkedHashMap<LogCategory, ApexLogLevel>();

        if (Utils.isEmpty(configuration)) {
            return finalLogLevels;
        }

        Map<String, String> savedLogLevels = (Map<String, String>) configuration
                .getAttribute(RunTestsConstants.ATTR_LOG_LEVELS, Collections.emptyMap());

        for (String categoryName : savedLogLevels.keySet()) {
            ApexLogLevel logLevel = ApexLogLevel.valueOf(savedLogLevels.get(categoryName));

            if (categoryName.equals(Messages.Tab_LogCategoryDatabase)) {
                finalLogLevels.put(LogCategory.Db, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryWorkflow)) {
                finalLogLevels.put(LogCategory.Workflow, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryValidation)) {
                finalLogLevels.put(LogCategory.Validation, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryCallout)) {
                finalLogLevels.put(LogCategory.Callout, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryApexCode)) {
                finalLogLevels.put(LogCategory.Apex_code, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryApexProfiling)) {
                finalLogLevels.put(LogCategory.Apex_profiling, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategoryVisualforce)) {
                finalLogLevels.put(LogCategory.Visualforce, logLevel);
            } else if (categoryName.equals(Messages.Tab_LogCategorySystem)) {
                finalLogLevels.put(LogCategory.System, logLevel);
            }
        }

        return finalLogLevels;
    }

    @VisibleForTesting
    public RunTestsView getRunTestView() {
        return RunTestsView.getInstance();
    }

    @VisibleForTesting
    public Display getDisplay() {
        return PlatformUI.getWorkbench().getDisplay();
    }

    @VisibleForTesting
    public void removeLaunch(ILaunch launch) {
        DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
    }

    /**
      * Pop up a confirmation dialog regarding asynchronous test run while debugging
      * @return False if abort, true if continue
      */
    @VisibleForTesting
    public boolean confirmAsyncTestRunWhileDebugging() {
        Display display = getDisplay();
        final AtomicInteger choice = new AtomicInteger(0);

        display.syncExec(new Runnable() {
            @Override
            public void run() {
                choice.set(
                        DialogUtils.getInstance().cancelContinueMessage(Messages.LaunchDelegate_ConfirmDialogTitle,
                                Messages.LaunchDelegate_CannotLaunchAsyncWhileDebugging, MessageDialog.WARNING));
            }
        });

        return choice.get() == 1;
    }

    /**
     * Inform user there is an existing Trace Flag.
     * @return False if abort, true if continue
     */
    @VisibleForTesting
    public boolean confirmExistingTraceFlag() {
        Display display = getDisplay();
        final AtomicInteger choice = new AtomicInteger(0);

        display.syncExec(new Runnable() {
            @Override
            public void run() {
                choice.set(
                        DialogUtils.getInstance().cancelContinueMessage(Messages.LaunchDelegate_ConfirmDialogTitle,
                                Messages.LaunchDelegate_ExistingTraceFlag, MessageDialog.INFORMATION));
            }
        });

        return choice.get() == 1;
    }

    /**
     * Re-open config window with the specified launch config
     * @param configuration
     * @param mode
     */
    @VisibleForTesting
    public void reopenLaunchConfig(final ILaunchConfiguration configuration, final String mode) {
        if (Utils.isNotEmpty(configuration) && Utils.isNotEmpty(mode)) {
            Display display = getDisplay();
            display.asyncExec(new Runnable() {
                @Override
                public void run() {
                    IWorkbenchWindow aww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
                    ILaunchGroup launchGroup = DebugUITools.getLaunchGroup(configuration, mode);
                    DebugUITools.openLaunchConfigurationDialog(aww.getShell(), configuration,
                            launchGroup.getIdentifier(), null);
                }
            });
        }
    }
}