Package org.testng.eclipse.ui

Source Code of org.testng.eclipse.ui.TestRunnerViewPart

package org.testng.eclipse.ui;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.internal.debug.ui.StatusInfo;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.EditorActionBarContributor;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.UIJob;
import org.testng.ITestResult;
import org.testng.eclipse.TestNGPlugin;
import org.testng.eclipse.TestNGPluginConstants;
import org.testng.eclipse.ui.summary.SummaryTab;
import org.testng.eclipse.util.CustomSuite;
import org.testng.eclipse.util.JDTUtil;
import org.testng.eclipse.util.LaunchUtil;
import org.testng.eclipse.util.PreferenceStoreUtil;
import org.testng.eclipse.util.ResourceUtil;
import org.testng.eclipse.util.StringUtils;
import org.testng.remote.strprotocol.GenericMessage;
import org.testng.remote.strprotocol.IMessageSender;
import org.testng.remote.strprotocol.IRemoteSuiteListener;
import org.testng.remote.strprotocol.IRemoteTestListener;
import org.testng.remote.strprotocol.SerializedMessageSender;
import org.testng.remote.strprotocol.StringMessageSender;
import org.testng.remote.strprotocol.SuiteMessage;
import org.testng.remote.strprotocol.TestMessage;
import org.testng.remote.strprotocol.TestResultMessage;

/**
* A ViewPart that shows the results of a test run.
*
* @author Cedric Beust <cedric@beust.com>
*/
public class TestRunnerViewPart extends ViewPart
implements IPropertyChangeListener, IRemoteSuiteListener, IRemoteTestListener {

  /** used by IWorkbenchSiteProgressService */
  private static final Object FAMILY_RUN = new Object();

  /** store the state. */
  private IMemento m_stateMemento;

  /** The launched project */
  private IJavaProject m_workingProject;

  // view components
  private Composite   m_parentComposite;
  private CTabFolder m_tabFolder;

  /** The currently active run tab. */
  private TestRunTab m_activeRunTab;

  // Orientations
  private static final int VIEW_ORIENTATION_VERTICAL = 0;
  private static final int VIEW_ORIENTATION_HORIZONTAL = 1;
  private static final int VIEW_ORIENTATION_AUTOMATIC = 2;

  /**
   * The current orientation; either <code>VIEW_ORIENTATION_HORIZONTAL</code>
   * <code>VIEW_ORIENTATION_VERTICAL</code>, or <code>VIEW_ORIENTATION_AUTOMATIC</code>.
   */
  private int fOrientation = VIEW_ORIENTATION_AUTOMATIC;

  /**
   * The current orientation; either <code>VIEW_ORIENTATION_HORIZONTAL</code>
   * <code>VIEW_ORIENTATION_VERTICAL</code>.
   */
  private int fCurrentOrientation;

  private CounterPanel m_counterPanel;
  private Composite m_counterComposite;

  private final Image m_viewIcon = TestNGPlugin.getImageDescriptor("main16/testng_noshadow.gif").createImage();//$NON-NLS-1$

  /**
   * Actions
   */
  private Action fNextAction;
  private Action fPrevAction;
  private ToggleOrientationAction[] fToggleOrientationActions;
  private Action m_rerunAction;
  private Action m_rerunFailedAction;
  private RunHistoryAction m_runHistoryAction;
  private Action m_openReportAction;

  private ProgressBar fProgressBar;
  private ToolItem m_stopButton;

  private Color fOKColor;
  private Color fFailureColor;

  private boolean m_isDisposed = false;

  // JOBS
  private UpdateUIJob m_updateUIJob;
  /**
   * A Job that runs as long as a test run is running.
   * It is used to get the progress feedback for running jobs in the view.
   */
  private IsRunningJob m_isRunningJob;
  private ILock m_runLock;

  public static final String NAME = "org.testng.eclipse.ResultView"; //$NON-NLS-1$
  public static final String ID_EXTENSION_POINT_TESTRUN_TABS = TestNGPlugin.PLUGIN_ID + "." //$NON-NLS-1$
      + "internal_testRunTabs"//$NON-NLS-1$

  private static final int REFRESH_INTERVAL = 200;

  // Persistence tags.
  private static final String TAG_PAGE = "page"; //$NON-NLS-1$
  private static final String TAG_ORIENTATION = "orientation"; //$NON-NLS-1$

  // If the tree has more than this number of results, then typing a key in the
  // search filter should only update it if the text size is above
  // MAX_TEXT_SIZE_THRESHOLD.
  private static final int MAX_RESULTS_THRESHOLD = 1000;
  private static final int MAX_TEXT_SIZE_THRESHOLD = 3;

  /** Infos for the current suite run. */
  private SuiteRunInfo currentSuiteRunInfo;

  /**
   * The client side of the remote test runner
   */
  private EclipseTestRunnerClient fTestRunnerClient;

  /**
   * Stores any test descriptions of failed tests. For any test class that
   * implements ITest, this will be the returned value of getTestName().
   */
  private Set<String> testDescriptions;
  private Text m_searchText;

  /** The thread that watches the testng-results.xml file */
  private WatchResultThread m_watchThread;

  private Action m_clearTreeAction;

  @Override
  public void init(IViewSite site, IMemento memento) throws PartInitException {
    super.init(site, memento);
    m_stateMemento = memento;

    IWorkbenchSiteProgressService progressService = getProgressService();
    if(progressService != null) {
      progressService.showBusyForFamily(TestRunnerViewPart.FAMILY_RUN);
    }

    // Start the watcher thread, if applicable
    updateResultThread();
  }

  private IWorkbenchSiteProgressService getProgressService() {
    Object siteService = getSite().getAdapter(IWorkbenchSiteProgressService.class);
    if(siteService != null) {
      return (IWorkbenchSiteProgressService) siteService;
    }

    return null;
  }

  private void restoreLayoutState(IMemento memento) {
    Integer page = memento.getInteger(TAG_PAGE);
    if(page != null) {
      int p = page.intValue();
      m_tabFolder.setSelection(p);
      m_activeRunTab = ALL_TABS.get(p);
    }

    for (TestRunTab trt : ALL_TABS) {
      trt.restoreState(memento);
    }

    Integer orientation = memento.getInteger(TAG_ORIENTATION);
    if(orientation != null) {
      fOrientation = orientation.intValue();
    }

    computeOrientation();
  }

  void computeOrientation() {
    if (fOrientation != VIEW_ORIENTATION_AUTOMATIC) {
      fCurrentOrientation = fOrientation;
      setOrientation(fCurrentOrientation);
    }
    else {
      Point size = m_parentComposite.getSize();
      if((size.x != 0) && (size.y != 0)) {
        if(size.x > size.y) {
          setOrientation(VIEW_ORIENTATION_HORIZONTAL);
        }
        else {
          setOrientation(VIEW_ORIENTATION_VERTICAL);
        }
      }
    }
  }

  private void setOrientation(int orientation) {

    boolean horizontal = orientation == VIEW_ORIENTATION_HORIZONTAL;
    for (TestRunTab trt : ALL_TABS) {
      trt.setOrientation(horizontal);
    }

    for (ToggleOrientationAction fToggleOrientationAction : fToggleOrientationActions) {
      fToggleOrientationAction.setChecked(
          fOrientation == fToggleOrientationAction.getOrientation());
    }
    fCurrentOrientation = orientation;

    GridLayout layout = (GridLayout) m_counterComposite.getLayout();
//    layout.numColumns = 1;
    setCounterColumns(layout);

    try {
      m_parentComposite.layout();
    }
    catch(Throwable cause) {
      cause.printStackTrace();
    }
  }

  /**
   * Stops the currently running test and shuts down the RemoteTestRunner.
   */
  private void stopTest() {
    if(null != fTestRunnerClient) {
      fTestRunnerClient.stopTest();
    }
    stopUpdateJobs();
  }

  public void selectNextFailure() {
    m_activeRunTab.selectNext();
  }

  public void selectPreviousFailure() {
    m_activeRunTab.selectPrevious();
  }

  public void showTest(RunInfo test) {
    m_activeRunTab.setSelectedTest(test.getId());
    new OpenTestAction(this, test.getClassName(), test.getMethodName(), false).run();
  }


  public void reset() {
    reset(0, 0);
    clearStatus();

    // disable all the actions on resetting the view
    fNextAction.setEnabled(false);
    fPrevAction.setEnabled(false);
    m_rerunAction.setEnabled(false);
    m_rerunFailedAction.setEnabled(false);
    m_openReportAction.setEnabled(false);
  }

  private void stopUpdateJobs() {
    if(m_updateUIJob != null) {
      m_updateUIJob.stop();
      m_updateUIJob = null;
    }
    if((m_isRunningJob != null) && (m_runLock != null)) {
      m_runLock.release();
      m_isRunningJob = null;
    }
  }

  public void startTestRunListening(IJavaProject project,
                                    String subName,
                                    int port,
                                    ILaunch launch) {
    m_workingProject = project;

    aboutToLaunch(subName);

//    if(null != fTestRunnerClient) {
//      stopTest();
//    }
    fTestRunnerClient = new EclipseTestRunnerClient();
    IMessageSender messageMarshaller = LaunchUtil.useStringProtocol(launch.getLaunchConfiguration())
        ? new StringMessageSender("localhost", port)
        : new SerializedMessageSender("localhost", port);

    boolean isInitSuccess = false;
    do {
      try {
        messageMarshaller.initReceiver();
        isInitSuccess = true;
      } catch (SocketTimeoutException e) {
        TestNGPlugin.log(e);
      }
    } while (isInitSuccess == false && launch.isTerminated() == false);

    if (isInitSuccess == true) {
      newSuiteRunInfo(launch);

      fTestRunnerClient.startListening(currentSuiteRunInfo, currentSuiteRunInfo, messageMarshaller);
      m_rerunAction.setEnabled(true);
      m_rerunFailedAction.setEnabled(false);
      m_openReportAction.setEnabled(true);
    } else {
      boolean useProjectJar =
          TestNGPlugin.getPluginPreferenceStore().getUseProjectJar(project.getProject().getName());
      String suggestion = useProjectJar
          ? "Uncheck the 'Use Project testng.jar' option from your Project properties and try again."
              : "Make sure you don't have an older version of testng.jar on your class path.";
      new ErrorDialog(m_counterComposite.getShell(), "Couldn't launch TestNG",
          "Couldn't contact the RemoteTestNG client. " + suggestion,
          new StatusInfo(IStatus.ERROR, "Timeout while trying to contact RemoteTestNG."),
          IStatus.ERROR).open();
    }
//    getViewSite().getActionBars().updateActionBars();
  }

  /**
   * Start or stop the watch thread.
   */
  private void updateResultThread() {
    boolean enabled = getWatchResults();
    String path = getWatchResultDirectory();
    if (m_watchThread != null) m_watchThread.stopWatching();
    if (enabled) {
      TestNGPlugin.log("Monitoring results at " + path);
      newSuiteRunInfo(null);

      m_watchThread = new WatchResultThread(path, currentSuiteRunInfo, currentSuiteRunInfo);
    } else {
      if (! StringUtils.isEmptyString(path)) TestNGPlugin.log("No longer monitoring results at " + path);
      m_watchThread = null;
    }
  }

  private void newSuiteRunInfo(ILaunch launch) {
    if (currentSuiteRunInfo != null) {
      currentSuiteRunInfo.removeDelegateListeners();
    }
    currentSuiteRunInfo = new SuiteRunInfo(this, this, launch);
    this.m_runHistoryAction.add(currentSuiteRunInfo);
  }

  /**
   * Used if we are reading our results from testng-results.xml. In this case, we don't have
   * a project name, so we pick whatever project the current selection of the package explorer
   * is and hope for the best.
   */
  private void initProject() {
    IWorkbench iworkbench = PlatformUI.getWorkbench();
    if (iworkbench != null) {
      IWorkbenchWindow iworkbenchwindow = iworkbench.getActiveWorkbenchWindow();
      if (iworkbenchwindow != null) {
        IWorkbenchPage iworkbenchpage = iworkbenchwindow.getActivePage();
        if (iworkbenchpage != null) {
          IEditorPart ieditorpart = iworkbenchpage.getActiveEditor();
          if (ieditorpart != null) {
            IEditorInput input = ieditorpart.getEditorInput();
            if (input != null && input instanceof IFileEditorInput) {
              IResource resource = ((IFileEditorInput) input).getFile();
              IProject project = resource.getProject();
              IJavaProject javaProject = JDTUtil.getJavaProject(project.getName());
              if (javaProject != null) {
                m_workingProject = javaProject;
              } else {
                TestNGPlugin.log("Current project " + project.getName() + " is not a Java project");
              }
            }
          }
        }
      }
    }
  }

  private void aboutToLaunch(final String message) {
    String msg =
      ResourceUtil.getFormattedString("TestRunnerViewPart.message.launching", message); //$NON-NLS-1$
    setPartName(msg);
    firePropertyChange(IWorkbenchPart.PROP_TITLE);
  }

  @Override
  public synchronized void dispose() {
    m_isDisposed = true;
    stopTest();

    TestNGPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
    m_viewIcon.dispose();
    fOKColor.dispose();
    fFailureColor.dispose();
  }

  private void postSyncRunnable(Runnable r) {
    if(!isDisposed()) {
      getDisplay().syncExec(r);
    }
  }

  private void postAsyncRunnable(Runnable r) {
    if(!isDisposed()) {
      getDisplay().asyncExec(r);
    }
  }

  private void refreshCounters() {
    m_counterPanel.setMethodCount(currentSuiteRunInfo.getMethodCount());
    m_counterPanel.setPassedCount(currentSuiteRunInfo.getPassedCount());
    m_counterPanel.setFailedCount(currentSuiteRunInfo.getFailedCount());
    m_counterPanel.setSkippedCount(currentSuiteRunInfo.getSkippedCount());
    String msg= "";
    if (currentSuiteRunInfo.hasRun()) {
      msg = " (" + currentSuiteRunInfo.getRunDuration() + " ms)";
    }

    fProgressBar.refresh(currentSuiteRunInfo.getStatus(), msg);
  }

  private void postShowTestResultsView() {
    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }
        showTestResultsView();
      }
    });
  }

  /**
   * Show the result view.
   */
  public void showTestResultsView() {
    IWorkbenchWindow   window = getSite().getWorkbenchWindow();
    IWorkbenchPage     page = window.getActivePage();
    TestRunnerViewPart testRunner = null;

    if(page != null) {
      try {
        testRunner = (TestRunnerViewPart) page.findView(TestRunnerViewPart.NAME);
        if(testRunner == null) {

          IWorkbenchPart activePart = page.getActivePart();
          testRunner = (TestRunnerViewPart) page.showView(TestRunnerViewPart.NAME);

          //restore focus
          page.activate(activePart);
        }
        else {
          page.bringToTop(testRunner);
        }
      }
      catch(PartInitException pie) {
        TestNGPlugin.log(pie);
      }
    }
  }

  private void clearStatus() {
    getStatusLine().setMessage(null);
    getStatusLine().setErrorMessage(null);
  }


  private CTabFolder createTestRunTabs(Composite parent) {
    CTabFolder tabFolder = new CTabFolder(parent, SWT.TOP);
    tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    loadTestRunTabs(tabFolder);
    tabFolder.setSelection(0);
    m_activeRunTab = ALL_TABS.get(0);

    tabFolder.addSelectionListener(new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent event) {
          testTabChanged(event);
        }
      });

    return tabFolder;
  }

  private static TestRunTab m_failureTab = new FailureTab();
  private static SummaryTab m_summaryTab = new SummaryTab();

  /**
   * The list of tabs that need to be updated at each new result.
   */
  private static final TestRunTab[] LISTENING_TABS = new TestRunTab[] {
    m_summaryTab
  };

  /**
   * The list of tabs that need to be updated after the suite has run.
   */
  private static final TestRunTab[] REPORTING_TABS = new TestRunTab[] {
    new SuccessTab(),
    m_failureTab
  };

  @SuppressWarnings("serial")
  private static final List<TestRunTab> ALL_TABS = new ArrayList<TestRunTab>() {{
    addAll(Arrays.asList(REPORTING_TABS));
    addAll(Arrays.asList(LISTENING_TABS));
  }};

  private void loadTestRunTabs(CTabFolder tabFolder) {
    for (TestRunTab t : REPORTING_TABS) {
      createTabControl(t, tabFolder, this);
    }
    for (TestRunTab t : LISTENING_TABS) {
      createTabControl(t, tabFolder, this);
    }
  }

  private void createTabControl(TestRunTab testRunTab, CTabFolder tabFolder,
      TestRunnerViewPart testRunnerViewPart) {
    Composite composite = testRunTab.createTabControl(tabFolder, this);

    CTabItem tab = new CTabItem(tabFolder, SWT.NONE);
    tab.setText(ResourceUtil.getString(testRunTab.getNameKey()));
    tab.setImage(testRunTab.getImage());
    tab.setToolTipText(ResourceUtil.getString(testRunTab.getTooltipKey())); //$NON-NLS-1$

    tab.setControl(composite);
  }

  private void testTabChanged(SelectionEvent event) {
    String selectedTestId = m_activeRunTab.getSelectedTestId();

    for (TestRunTab tab : ALL_TABS) {
      tab.setSelectedTest(selectedTestId);

      String name = ResourceUtil.getString(tab.getNameKey());
      if(((CTabFolder) event.widget).getSelection().getText() == name) {
        m_activeRunTab = tab;
        m_activeRunTab.activate();
      }
    }
  }

  void reset(final int suiteCount, final int testCount) {
    currentSuiteRunInfo.setSuitesTotalCount(suiteCount);
    currentSuiteRunInfo.setTestsTotalCount(testCount);

    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }

        m_counterPanel.reset();
        fProgressBar.reset(testCount);
        clearStatus();

        for (TestRunTab tab : ALL_TABS) {
          tab.aboutToStart();
        }
      }
    });
  }

  @Override
  public void setFocus() {
    if(m_activeRunTab != null) {
      m_activeRunTab.setFocus();
    }
  }

  /**
   * @return true if we should be monitoring testng-results.xml.
   */
  private boolean getWatchResults() {
    return TestNGPlugin.getPluginPreferenceStore().getWatchResults(getProjectName());
  }

  private String getWatchResultDirectory() {
    String projectName = getProjectName();
    return projectName != null
        ? TestNGPlugin.getPluginPreferenceStore().getWatchResultDirectory(projectName)
        : null;
  }

  @Override
  public void createPartControl(Composite parent) {
    if (getWatchResultDirectory() != null) {
      updateResultThread();
    }
    m_parentComposite = parent;

    GridLayout gridLayout = new GridLayout();
    gridLayout.marginWidth = 0;
    gridLayout.marginHeight = 0;
    parent.setLayout(gridLayout);

    configureToolBar();

    createProgressCountPanel(parent);

    m_tabFolder = createTestRunTabs(parent);

    TestNGPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);

    if (m_stateMemento != null) {
      restoreLayoutState(m_stateMemento);
    }
    m_stateMemento = null;
  }

  @Override
  public void saveState(IMemento memento) {
    int activePage = m_tabFolder.getSelectionIndex();
    memento.putInteger(TAG_PAGE, activePage);
    memento.putInteger(TAG_ORIENTATION, fOrientation);

    for (TestRunTab tab : ALL_TABS) {
      tab.saveState(memento);
    }
  }

  private void configureToolBar() {
    IActionBars     actionBars = getViewSite().getActionBars();
    IToolBarManager toolBar = actionBars.getToolBarManager();
    IMenuManager    viewMenu = actionBars.getMenuManager();

    fToggleOrientationActions = new ToggleOrientationAction[] {
        new ToggleOrientationAction(this, VIEW_ORIENTATION_VERTICAL),
        new ToggleOrientationAction(this, VIEW_ORIENTATION_HORIZONTAL),
        new ToggleOrientationAction(this, VIEW_ORIENTATION_AUTOMATIC)
    };
    fNextAction = new ShowNextFailureAction(this);
    fPrevAction = new ShowPreviousFailureAction(this);
    m_rerunAction= new RerunAction();
    m_rerunFailedAction= new RerunFailedAction();
    m_runHistoryAction = new RunHistoryAction(this);
    m_openReportAction= new OpenReportAction();

    m_clearTreeAction = new ClearResultsAction(ALL_TABS);
    fNextAction.setEnabled(false);
    fPrevAction.setEnabled(false);
    m_rerunAction.setEnabled(false);
    m_rerunFailedAction.setEnabled(false);
    m_openReportAction.setEnabled(false);

    actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), fNextAction);
    actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), fPrevAction);

    toolBar.add(m_clearTreeAction);
    toolBar.add(new Separator());
    toolBar.add(fNextAction);
    toolBar.add(fPrevAction);
    toolBar.add(new Separator());
    toolBar.add(m_rerunAction);
    toolBar.add(m_rerunFailedAction);
    toolBar.add(m_runHistoryAction);
    toolBar.add(new Separator());
    toolBar.add(m_openReportAction);

    for (ToggleOrientationAction fToggleOrientationAction : fToggleOrientationActions) {
      viewMenu.add(fToggleOrientationAction);
    }

    actionBars.updateActionBars();
  }

  private IStatusLineManager getStatusLine() {
    // we want to show messages globally hence we
    // have to go through the active part
    IViewSite      site = getViewSite();
    IWorkbenchPage page = site.getPage();
    IWorkbenchPart activePart = page.getActivePart();

    if(activePart instanceof IViewPart) {

      IViewPart activeViewPart = (IViewPart) activePart;
      IViewSite activeViewSite = activeViewPart.getViewSite();

      return activeViewSite.getActionBars().getStatusLineManager();
    }

    if(activePart instanceof IEditorPart) {
      IEditorPart activeEditorPart = (IEditorPart) activePart;
      IEditorActionBarContributor contributor = activeEditorPart.getEditorSite()
                                                                .getActionBarContributor();
      if(contributor instanceof EditorActionBarContributor) {
        return ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager();
      }
    }

    // no active part
    return getViewSite().getActionBars().getStatusLineManager();
  }

  private void createProgressCountPanel(Composite parent) {
    Display display= parent.getDisplay();
    fFailureColor= new Color(display, 159, 63, 63);
    fOKColor= new Color(display, 95, 191, 95);

    {
      //
      // Progress bar
      //
      m_counterComposite = new Composite(parent, SWT.NONE);
      m_counterComposite.setLayoutData(
          new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
      GridLayout layout = new GridLayout();
      m_counterComposite.setLayout(layout);
      setCounterColumns(layout);

      fProgressBar = new ProgressBar(m_counterComposite);
      fProgressBar.setLayoutData(
          new GridData(GridData.GRAB_HORIZONTAL| GridData.HORIZONTAL_ALIGN_FILL));

      //
      // Stop button (a toolbar, actually)
      //
      ToolBar toolBar = new ToolBar(m_counterComposite, SWT.FLAT);
      m_stopButton = new ToolItem(toolBar, SWT.PUSH);
      m_stopButton.setEnabled(false);
      m_stopButton.setImage(Images.getImage(Images.IMG_STOP));
      m_stopButton.setToolTipText("Stop the current test run");
      m_stopButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
          stopTest();
        }

        public void widgetDefaultSelected(SelectionEvent e) {
        }
      });
    }

    {
      //
      // Search
      //
      Composite line2 = new Composite(parent, SWT.NONE);
      line2.setLayoutData(
          new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
      GridLayout layout = new GridLayout();
      layout.numColumns = 3;
      line2.setLayout(layout);
      new Label(line2, SWT.NONE).setText("Search:");
      m_searchText = new Text(line2, SWT.SINGLE | SWT.BORDER);
      m_searchText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
      m_searchText.addKeyListener(new KeyListener() {

        public void keyPressed(KeyEvent e) {
        }

        public void keyReleased(KeyEvent e) {
          // Update the tree based on the search filter only if we don't have too many
          // results, otherwise, wait for at least n characters to be typed.
          String filter = "";
          if (currentSuiteRunInfo.getNbResults() < MAX_RESULTS_THRESHOLD
              || currentSuiteRunInfo.getNbResults() >= MAX_RESULTS_THRESHOLD
              && m_searchText.getText().length() >= MAX_TEXT_SIZE_THRESHOLD) {
            filter = m_searchText.getText();
          }

          for (TestRunTab tab : ALL_TABS) {
            tab.updateSearchFilter(filter);
          }
        }

      });

      //
      // Counter panel
      //
      m_counterPanel = new CounterPanel(line2);
    }
  }

  public IJavaProject getLaunchedProject() {
    if (m_workingProject == null) initProject();
    return m_workingProject;
  }

  public void setLaunchedProject(IJavaProject project) {
    m_workingProject = project;
  }

  public ILaunch getLastLaunch() {
    if (currentSuiteRunInfo != null) {
      return currentSuiteRunInfo.getLaunch();
    }
    return null;
  }

  private boolean isDisposed() {
    return m_isDisposed || m_counterPanel.isDisposed();
  }

  private Display getDisplay() {
    return getViewSite().getShell().getDisplay();
  }

  public boolean isCreated() {
    return m_counterPanel != null;
  }

  public void warnOfContentChange() {

    IWorkbenchSiteProgressService service = getProgressService();
    if(service != null) {
      service.warnOfContentChange();
    }
  }

  public boolean lastLaunchIsKeptAlive() {
    return false;
  }

  private void setCounterColumns(GridLayout layout) {
    if(fCurrentOrientation == VIEW_ORIENTATION_HORIZONTAL) {
      layout.numColumns = 3;
    }
    else {
      layout.numColumns = 2;
    }
  }

  private class ToggleOrientationAction extends Action {

    private final int fActionOrientation;

    public ToggleOrientationAction(TestRunnerViewPart v, int orientation) {
      super("", AS_RADIO_BUTTON); //$NON-NLS-1$
      if(orientation == TestRunnerViewPart.VIEW_ORIENTATION_HORIZONTAL) {
        setText(ResourceUtil.getString("TestRunnerViewPart.toggle.horizontal.label")); //$NON-NLS-1$
        setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/th_horizontal.gif")); //$NON-NLS-1$
      }
      else if(orientation == TestRunnerViewPart.VIEW_ORIENTATION_VERTICAL) {
        setText(ResourceUtil.getString("TestRunnerViewPart.toggle.vertical.label")); //$NON-NLS-1$
        setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/th_vertical.gif")); //$NON-NLS-1$
      }
      else if(orientation == TestRunnerViewPart.VIEW_ORIENTATION_AUTOMATIC) {
        setText(ResourceUtil.getString("TestRunnerViewPart.toggle.automatic.label")); //$NON-NLS-1$
        setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/th_automatic.gif")); //$NON-NLS-1$
      }
      fActionOrientation = orientation;
    }

    public int getOrientation() {
      return fActionOrientation;
    }

    @Override
    public void run() {
      if(isChecked()) {
        fOrientation = fActionOrientation;
        computeOrientation();
      }
    }
  }

  /**
   * Background job running in UI thread for updating components info.
   */
  class UpdateUIJob extends UIJob {
    private volatile boolean fRunning = true;

    public UpdateUIJob(String name) {
      super(name);
      setSystem(true);
    }

    @Override
    public IStatus runInUIThread(IProgressMonitor monitor) {
      if(!isDisposed()) {
//        doShowStatus();
        refreshCounters();
//        m_progressBar.redraw();
      }
      schedule(REFRESH_INTERVAL);

      return Status.OK_STATUS;
    }

    public void stop() {
      fRunning = false;
    }

    @Override
    public boolean shouldSchedule() {
      return fRunning;
    }
  }

  class IsRunningJob extends Job {
    public IsRunningJob(String name) {
      super(name);
      setSystem(true);
    }

    @Override
    public IStatus run(IProgressMonitor monitor) {
      // wait until the test run terminates
      m_runLock.acquire();

      return Status.OK_STATUS;
    }

    @Override
    public boolean belongsTo(Object family) {
      return family == TestRunnerViewPart.FAMILY_RUN;
    }
  }

  private static void ppp(final Object message) {
    if (true) {
      System.out.println("[TestRunnerViewPart] " + message);
    }
  }

  /**
   * @see IWorkbenchPart#getTitleImage()
   */
  @Override
  public Image getTitleImage() {
    return m_viewIcon;
  }

  /**
   * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
   */
  public void propertyChange(PropertyChangeEvent event) {
    String name = event.getProperty();
    String statusChanged = getProjectName() + TestNGPluginConstants.S_WATCH_RESULTS;
    String directoryChanged = getProjectName() + TestNGPluginConstants.S_WATCH_RESULT_DIRECTORY;
    if (statusChanged.equals(name) || directoryChanged.equals(name)) {
      updateResultThread();
    }
  }

  private void postTestResult(final RunInfo runInfo, final boolean isSuccess) {
    currentSuiteRunInfo.add(runInfo);

//    long start = System.currentTimeMillis();

    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }

        fProgressBar.step(isSuccess);
        for (TestRunTab tab : ALL_TABS) {
          tab.updateTestResult(runInfo, true /* expand */);
        }
      }
    });
//    System.out.println("Time to post:" + (System.currentTimeMillis() - start));
  }

  private void showResultsInTree() {
    postSyncRunnable(new Runnable() {
      public void run() {
//        long start = System.currentTimeMillis();
        for (TestRunTab tab : ALL_TABS) {
          tab.updateTestResult(currentSuiteRunInfo.getResults());
        }
//        System.out.println("Done updating tree:" + (System.currentTimeMillis() - start) + "ms");
      }
    });
  }

  private class RerunAction extends Action {
    public RerunAction() {
      setText(ResourceUtil.getString("TestRunnerViewPart.rerunaction.label")); //$NON-NLS-1$
      setToolTipText(ResourceUtil.getString("TestRunnerViewPart.rerunaction.tooltip")); //$NON-NLS-1$
      setDisabledImageDescriptor(TestNGPlugin.getImageDescriptor("dlcl16/relaunch.gif")); //$NON-NLS-1$
      setHoverImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/relaunch.gif")); //$NON-NLS-1$
      setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/relaunch.gif")); //$NON-NLS-1$
    }

    @Override
    public void run() {
      ILaunch launch = getLastLaunch();
      if(null != launch) {
        DebugUITools.launch(launch.getLaunchConfiguration(), launch.getLaunchMode());
      }
    }
  }

  private class OpenReportAction extends Action {
    public OpenReportAction() {
      setText(ResourceUtil.getString("TestRunnerViewPart.openreport.label")); //$NON-NLS-1$
      setToolTipText(ResourceUtil.getString("TestRunnerViewPart.openreport.tooltip")); //$NON-NLS-1$
      setDisabledImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/report.gif")); //$NON-NLS-1$
      setHoverImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/report.gif")); //$NON-NLS-1$
      setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/report.gif")); //$NON-NLS-1$
    }

    private void openEditor(IFile file) {
      final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
      if(window == null) {
        return;
      }

      final IWorkbenchPage page = window.getActivePage();
      if(page == null) {
        return;
      }
      try {
        IDE.openEditor(page, file);
      }
      catch(final PartInitException e) {
        TestNGPlugin.log(e);
      }
    }

    @Override
    public void run() {
      Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
      IJavaProject javaProject= m_workingProject != null ? m_workingProject : JDTUtil.getJavaProjectContext();
      if(null == javaProject) {
        return;
      }
      PreferenceStoreUtil storage= TestNGPlugin.getPluginPreferenceStore();
      IPath filePath= new Path(storage.getOutputDirectoryPath(javaProject).toOSString() + "/index.html");
      boolean isAbsolute= storage.isOutputAbsolutePath(javaProject.getElementName(), false);

      IProgressMonitor progressMonitor= new NullProgressMonitor();
      if(isAbsolute) {
        IFile file = javaProject.getProject().getFile("temp-testng-index.html");
        try {
          file.createLink(filePath, IResource.NONE, progressMonitor);
          if(null == file) return;
          try {
            openEditor(file);
          }
          finally {
            file.delete(true, progressMonitor);
          }
        }
        catch(CoreException cex) {
          ; // TODO: is there any other option?
        }
      }
      else {
        IFile file= (IFile) workspace.newResource(filePath, IResource.FILE);
        if(null == file) return;
        try {
          file.refreshLocal(IResource.DEPTH_ZERO, progressMonitor);
          openEditor(file);
        }
        catch(CoreException cex) {
          ; // nothing I can do about it
        }
      }
    }
  }

  private class RerunFailedAction extends Action {
    public RerunFailedAction() {
      setText(ResourceUtil.getString("TestRunnerViewPart.rerunfailedsaction.label")); //$NON-NLS-1$
      setToolTipText(ResourceUtil.getString("TestRunnerViewPart.rerunfailedsaction.tooltip")); //$NON-NLS-1$
      setDisabledImageDescriptor(TestNGPlugin.getImageDescriptor("dlcl16/relaunchf.gif")); //$NON-NLS-1$
      setHoverImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/relaunchf.gif")); //$NON-NLS-1$
      setImageDescriptor(TestNGPlugin.getImageDescriptor("elcl16/relaunchf.gif")); //$NON-NLS-1$
    }

    @Override
    public void run() {
      ILaunch launch = getLastLaunch();
      if(null != launch && currentSuiteRunInfo.hasErrors()) {
        LaunchUtil.launchFailedSuiteConfiguration(m_workingProject,
            launch.getLaunchMode(),
            launch.getLaunchConfiguration(),
            getTestDescriptions());
      }
    }
  }

  /// ~ ITestNGRemoteEventListener
  public void onInitialization(GenericMessage genericMessage) {
    int suiteCount = genericMessage.getSuiteCount();
    int testCount = genericMessage.getTestCount();
    reset(suiteCount, testCount);
    stopUpdateJobs();
    m_updateUIJob= new UpdateUIJob("Update TestNG"); //$NON-NLS-1$
    m_isRunningJob = new IsRunningJob("TestNG run wrapper job"); //$NON-NLS-1$
    m_runLock = Job.getJobManager().newLock();
    // acquire lock while a test run is running the lock is released when the test run terminates
    // the wrapper job will wait on this lock.
    m_runLock.acquire();
    getProgressService().schedule(m_isRunningJob);
    m_updateUIJob.schedule(REFRESH_INTERVAL);
  }

  public void onFinish(SuiteMessage suiteMessage) {
    // Do this again in onFinish() in case the set of excluded methods changed since
    // onStart()
    m_summaryTab.setExcludedMethodsModel(suiteMessage);

    // If a threshold is now in place, let the user know that they now need
    // to type more than one character in the search field in order for
    // the filtering to occur.
    postAsyncRunnable(new Runnable() {
      public void run() {
        m_searchText
            .setToolTipText(currentSuiteRunInfo.getNbResults() > MAX_RESULTS_THRESHOLD ? ResourceUtil
                .getFormattedString(
                    "TestRunnerViewPart.typeCharacters.tooltip",
                    MAX_TEXT_SIZE_THRESHOLD) : "");
      }
    });

//    postSyncRunnable(new Runnable() {
//      public void run() {
//        if(isDisposed()) {
//          return;
//        }
//        for(int i = 0; i < ALL_TABS.size(); i++) {
//          ((TestRunTab) ALL_TABS.elementAt(i)).updateEntry(entryId);
//        }
//      }
//    });

    if (currentSuiteRunInfo.isSuiteRunFinished()) {
      final boolean hasErrors = currentSuiteRunInfo.hasErrors();
      fNextAction.setEnabled(hasErrors);
      fPrevAction.setEnabled(hasErrors);
      m_rerunFailedAction.setEnabled(hasErrors);
      postShowTestResultsView();
      stopTest();
      postSyncRunnable(new Runnable() {
        public void run() {
          if(isDisposed()) {
            return;
          }
          refreshCounters();
//          m_progressBar.redraw();
          m_stopButton.setEnabled(false);
        }
      });

    }

    showResultsInTree();
  }

  public void onStart(TestMessage tm) {
    RunInfo ri= new RunInfo(tm.getSuiteName(), tm.getTestName());
    ri.m_methodCount = tm.getTestMethodCount();

    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }

        updateProgressBar();
//        m_progressBar.setMaximum(newMaxBar);
        m_stopButton.setEnabled(true);
      }
    });
  }

  private void updateProgressBar() {
    postSyncRunnable(new Runnable() {
      public void run() {
        int newMaxBar = currentSuiteRunInfo.getNewMax();
        // FIXME JNR progress bar does not move to maximum anymore
        fProgressBar.setMaximum(newMaxBar, currentSuiteRunInfo.getMethodTotalCount());
      }
    });
  }

  public void onFinish(TestMessage tm) {
    updateProgressBar();

    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }
//        for(int i = 0; i < ALL_TABS.size(); i++) {
//          ((TestRunTab) ALL_TABS.elementAt(i)).updateEntry(entryId);
//        }

        fProgressBar.stepTests();
        m_stopButton.setEnabled(false);
      }
    });
  }

  private RunInfo createRunInfo(TestResultMessage trm, String stackTrace, int type) {
    String testName = trm.getName();
    if (testName == null) {
      testName = CustomSuite.DEFAULT_TEST_TAG_NAME;
    }
    return new RunInfo(trm.getSuiteName(),
                       testName,
                       trm.getTestClass(),
                       trm.getMethod(),
                       trm.getTestDescription(),
                       trm.getInstanceName(),
                       trm.getParameters(),
                       trm.getParameterTypes(),
                       trm.getEndMillis() - trm.getStartMillis(),
                       stackTrace,
                       type,
                       trm.getInvocationCount(),
                       trm.getCurrentInvocationCount());
  }

  public void onTestSuccess(TestResultMessage trm) {
    postTestResult(createRunInfo(trm, null, ITestResult.SUCCESS), true);
  }

  public void onTestFailure(TestResultMessage trm) {
    String desc = trm.getTestDescription();
    if (desc != null) {
      getTestDescriptions().add (desc);
    }
    //    System.out.println("[INFO:onTestFailure]:" + trm.getMessageAsString());
    postTestResult(createRunInfo(trm, trm.getStackTrace(), ITestResult.FAILURE), false);
  }

  public void onTestSkipped(TestResultMessage trm) {
//    System.out.println("[INFO:onTestSkipped]:" + trm.getMessageAsString());
    postTestResult(createRunInfo(trm, trm.getStackTrace(), ITestResult.SKIP), false);
  }

  public void onTestFailedButWithinSuccessPercentage(TestResultMessage trm) {
    postTestResult(createRunInfo(trm, trm.getStackTrace(), ITestResult.SUCCESS_PERCENTAGE_FAILURE), false);
  }

  public Set<String> getTestDescriptions() {
    if (testDescriptions == null) {
      testDescriptions = new HashSet<String>();
    }
    return testDescriptions;
  }

  /**
   * If any test descriptions of failed tests have been saved, pass them along
   * as a jvm argument. They can then be used by
   * @Factory methods to select which parameters to use for creating the set
   * of test instances to re-run.
   */
  public void run() {
    ILaunch launch = getLastLaunch();
    if (null != launch && currentSuiteRunInfo.hasErrors()) {
      ILaunchConfiguration config = launch.getLaunchConfiguration();

      try {
        ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
        Set<String> descriptions = getTestDescriptions();
        if (!descriptions.isEmpty()) { // String.join is not
          // available in jdk 1.4
          StringBuffer buf = new StringBuffer();
          Iterator<String> it = descriptions.iterator();
          boolean first = true;
          while (it.hasNext()) {
            if (first) {
              first = false;
            } else {
              buf.append(",");
            }
            buf.append(it.next());
          }
          config = LaunchUtil.addJvmArg(TestNGPlugin
              .getFailedTestsKey(), buf.toString(), wc);
        }
      } catch (CoreException ce) {
        ce.printStackTrace();
      }
      LaunchUtil.launchFailedSuiteConfiguration(m_workingProject,
          launch.getLaunchMode());
    }
  }

  /**
   * FIXME: currently not used; it should be use to mark the currently running
   * tests.
   */
  public void onTestStart(TestResultMessage trm) {
//    System.out.println("[INFO:onTestStart]:" + trm.getMessageAsString());
  }

  public void onStart(SuiteMessage suiteMessage) {
    m_summaryTab.setExcludedMethodsModel(suiteMessage);
  }

  private String getProjectName() {
    IJavaProject project = getLaunchedProject();
    return project != null ? project.getProject().getName() : null;
  }

  void reset(final SuiteRunInfo run) {
    postSyncRunnable(new Runnable() {
      public void run() {
        if(isDisposed()) {
          return;
        }

        currentSuiteRunInfo = run;
        refreshCounters();
        clearStatus();
        for (TestRunTab tab : ALL_TABS) {
          tab.updateTestResult(currentSuiteRunInfo.getResults());
        }
      }
    });
  }

}
TOP

Related Classes of org.testng.eclipse.ui.TestRunnerViewPart

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.