X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=tmf%2Forg.eclipse.tracecompass.tmf.ui.swtbot.tests%2Fshared%2Forg%2Feclipse%2Ftracecompass%2Ftmf%2Fui%2Fswtbot%2Ftests%2Fshared%2FSWTBotUtils.java;h=48f24b5c9824a0491d0f5e7eac01b871fb2ad7de;hb=f0beeb4aa356d812661dfa658bfd15a4a1e76e30;hp=b8bbe60a511dbdb8a62c5a4b3cacfa748e603ea3;hpb=5785ab49cfe1e9e1d200316e95c0c5b4096c9ad9;p=deliverable%2Ftracecompass.git diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java b/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java index b8bbe60a51..48f24b5c98 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java @@ -16,18 +16,26 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.Arrays; import java.util.List; +import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.log4j.Logger; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.bindings.keys.IKeyLookup; import org.eclipse.jface.bindings.keys.KeyStroke; import org.eclipse.jface.bindings.keys.ParseException; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; @@ -40,8 +48,12 @@ import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; import org.eclipse.swtbot.swt.finder.SWTBot; import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.keyboard.Keyboard; +import org.eclipse.swtbot.swt.finder.keyboard.Keystrokes; import org.eclipse.swtbot.swt.finder.results.Result; import org.eclipse.swtbot.swt.finder.results.VoidResult; +import org.eclipse.swtbot.swt.finder.utils.MessageFormat; +import org.eclipse.swtbot.swt.finder.utils.SWTUtils; import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton; @@ -51,12 +63,19 @@ import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.eclipse.swtbot.swt.finder.widgets.TimeoutException; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.NewExperimentOperation; import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers.ProjectElementHasChild; +import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils; import org.eclipse.tracecompass.tmf.ui.views.TracingPerspectiveFactory; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; @@ -71,20 +90,32 @@ import org.hamcrest.Matcher; * * @author Matthew Khouzam */ +@SuppressWarnings("restriction") public final class SWTBotUtils { + private static final String WINDOW_MENU = "Window"; + private static final String PREFERENCES_MENU_ITEM = "Preferences"; + private static boolean fPrintedEnvironment = false; + private static Logger log = Logger.getLogger(SWTBotUtils.class); + private SWTBotUtils() { + } private static final String TRACING_PERSPECTIVE_ID = TracingPerspectiveFactory.ID; /** - * Waits for all Eclipse jobs to finish + * Waits for all Eclipse jobs to finish. Times out after + * WaitUtils#MAX_JOBS_WAIT_TIME by default. + * + * @throws RuntimeException + * once the waiting time passes the default maximum value + * + * @deprecated Use {@link WaitUtils#waitForJobs()} instead */ + @Deprecated public static void waitForJobs() { - while (!Job.getJobManager().isIdle()) { - delay(100); - } + WaitUtils.waitForJobs(); } /** @@ -119,7 +150,7 @@ public final class SWTBotUtils { } }); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -135,13 +166,16 @@ public final class SWTBotUtils { public static void deleteProject(final String projectName, boolean deleteResources, SWTWorkbenchBot bot) { // Wait for any analysis to complete because it might create // supplementary files - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); try { ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { } - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); + + closeSecondaryShells(bot); + WaitUtils.waitForJobs(); final SWTBotView projectViewBot = bot.viewById(IPageLayout.ID_PROJECT_EXPLORER); projectViewBot.setFocus(); @@ -162,7 +196,7 @@ public final class SWTBotUtils { bot.waitUntil(Conditions.widgetIsEnabled(okButton)); okButton.click(); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -177,6 +211,39 @@ public final class SWTBotUtils { deleteProject(projectName, true, bot); } + /** + * Creates an experiment + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project, creates the project if needed + * @param expName + * the experiment name + */ + public static void createExperiment(SWTWorkbenchBot bot, String projectName, final @NonNull String expName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, true); + TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder(); + assertNotNull(expFolder); + NewExperimentOperation operation = new NewExperimentOperation(expFolder, expName); + operation.run(new NullProgressMonitor()); + + bot.waitUntil(new DefaultCondition() { + @Override + public boolean test() throws Exception { + TmfExperimentElement experiment = expFolder.getExperiment(expName); + return experiment != null; + } + + @Override + public String getFailureMessage() { + return "Experiment (" + expName + ") couldn't be created"; + } + }); + } + + /** * Focus on the main window * @@ -184,11 +251,42 @@ public final class SWTBotUtils { * swtbotshells for all the shells */ public static void focusMainWindow(SWTBotShell[] shellBots) { + SWTBotShell mainShell = getMainShell(shellBots); + if (mainShell != null) { + mainShell.activate(); + } + } + + private static SWTBotShell getMainShell(SWTBotShell[] shellBots) { + SWTBotShell mainShell = null; for (SWTBotShell shellBot : shellBots) { if (shellBot.getText().toLowerCase().contains("eclipse")) { - shellBot.activate(); + mainShell = shellBot; } } + return mainShell; + } + + /** + * Close all non-main shells that are visible. + * + * @param bot + * the workbench bot + */ + public static void closeSecondaryShells(SWTWorkbenchBot bot) { + SWTBotShell[] shells = bot.shells(); + SWTBotShell mainShell = getMainShell(shells); + if (mainShell == null) { + return; + } + + // Close all non-main shell but make sure we don't close an invisible + // shell such the special "limbo shell" that Eclipse needs to work + Arrays.stream(shells) + .filter(shell -> shell != mainShell) + .filter(SWTBotShell::isVisible) + .peek(shell -> log.debug(MessageFormat.format("Closing lingering shell with title {0}", shell.getText()))) + .forEach(SWTBotShell::close); } /** @@ -258,6 +356,12 @@ public final class SWTBotUtils { SWTWorkbenchBot bot = new SWTWorkbenchBot(); UIThreadRunnable.syncExec(() -> { + printEnvironment(); + + // There seems to be problems on some system where the main shell is + // not in focus initially. This was seen using Xvfb and Xephyr on some occasions. + focusMainWindow(bot.shells()); + Shell shell = bot.activeShell().widget; // Only adjust shell if it appears to be the top-most @@ -267,6 +371,41 @@ public final class SWTBotUtils { }); } + private static void printEnvironment() { + if (fPrintedEnvironment) { + return; + } + + // Print some information about the environment that could affect test outcome + Rectangle bounds = Display.getDefault().getBounds(); + System.out.println("Display size: " + bounds.width + "x" + bounds.height); + + String osVersion = System.getProperty("os.version"); + if (osVersion != null) { + System.out.println("OS version=" + osVersion); + } + String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version"); + if (gtkVersion != null) { + System.out.println("GTK version=" + gtkVersion); + // Try to print the GTK theme information as behavior can change depending on the theme + String gtkTheme = System.getProperty("org.eclipse.swt.internal.gtk.theme"); + System.out.println("GTK theme=" + (gtkTheme == null ? "unknown" : gtkTheme)); + + String overlayScrollbar = System.getenv("LIBOVERLAY_SCROLLBAR"); + if (overlayScrollbar != null) { + System.out.println("LIBOVERLAY_SCROLLBAR=" + overlayScrollbar); + } + String ubuntuMenuProxy = System.getenv("UBUNTU_MENUPROXY"); + if (ubuntuMenuProxy != null) { + System.out.println("UBUNTU_MENUPROXY=" + ubuntuMenuProxy); + } + } + + System.out.println("Time zone: " + TimeZone.getDefault().getDisplayName()); + + fPrintedEnvironment = true; + } + /** * If the test is running in the UI thread then fail */ @@ -345,7 +484,7 @@ public final class SWTBotUtils { if (delay) { delay(1000); - waitForJobs(); + WaitUtils.waitForJobs(); } } @@ -371,7 +510,7 @@ public final class SWTBotUtils { } }); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); SWTBotUtils.delay(1000); assertNotNull(tmfEd); return editorBot; @@ -404,7 +543,6 @@ public final class SWTBotUtils { SWTBotTreeItem currentItem = tracesNode; for (String segment : elementPath.segments()) { currentItem = getTraceProjectItem(projectExplorerBot, currentItem, segment); - currentItem.select(); currentItem.doubleClick(); } @@ -450,6 +588,121 @@ public final class SWTBotUtils { return tracesFolderItem; } + /** + * Clear the traces folder + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearTracesFolder(SWTWorkbenchBot bot, String projectName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false); + TmfTraceFolder tracesFolder = tmfProject.getTracesFolder(); + try { + for (TmfTraceElement traceElement : tracesFolder.getTraces()) { + traceElement.delete(null); + } + + final IFolder resource = tracesFolder.getResource(); + resource.accept(new IResourceVisitor() { + @Override + public boolean visit(IResource visitedResource) throws CoreException { + if (visitedResource != resource) { + visitedResource.delete(true, null); + } + return true; + } + }, IResource.DEPTH_ONE, 0); + } catch (CoreException e) { + fail(e.getMessage()); + } + + bot.waitUntil(new DefaultCondition() { + private int fTraceNb = 0; + + @Override + public boolean test() throws Exception { + List traces = tracesFolder.getTraces(); + fTraceNb = traces.size(); + return fTraceNb == 0; + } + + @Override + public String getFailureMessage() { + return "Traces Folder not empty (" + fTraceNb + ")"; + } + }); + } + + /** + * Clear the trace folder (using the UI) + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearTracesFolderUI(SWTWorkbenchBot bot, String projectName) { + SWTBotTreeItem tracesFolder = selectTracesFolder(bot, projectName); + tracesFolder.contextMenu().menu("Clear").click(); + String CONFIRM_CLEAR_DIALOG_TITLE = "Confirm Clear"; + bot.waitUntil(Conditions.shellIsActive(CONFIRM_CLEAR_DIALOG_TITLE)); + + SWTBotShell shell = bot.shell(CONFIRM_CLEAR_DIALOG_TITLE); + shell.bot().button("Yes").click(); + bot.waitUntil(Conditions.shellCloses(shell)); + bot.waitWhile(ConditionHelpers.treeItemHasChildren(tracesFolder)); + } + + /** + * Clear the experiment folder + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearExperimentFolder(SWTWorkbenchBot bot, String projectName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false); + TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder(); + expFolder.getExperiments().forEach(experiment -> { + IResource resource = experiment.getResource(); + try { + // Close the experiment if open + experiment.closeEditors(); + + IPath path = resource.getLocation(); + if (path != null) { + // Delete supplementary files + experiment.deleteSupplementaryFolder(); + } + // Finally, delete the experiment + resource.delete(true, null); + } catch (CoreException e) { + fail(e.getMessage()); + } + }); + + bot.waitUntil(new DefaultCondition() { + private int fExperimentNb = 0; + + @Override + public boolean test() throws Exception { + List experiments = expFolder.getExperiments(); + fExperimentNb = experiments.size(); + return fExperimentNb == 0; + } + + @Override + public String getFailureMessage() { + return "Experiment Folder not empty (" + fExperimentNb + ")"; + } + }); + } + /** * Select the project in Project Explorer * @@ -462,6 +715,11 @@ public final class SWTBotUtils { public static SWTBotTreeItem selectProject(SWTWorkbenchBot bot, String projectName) { SWTBotView projectExplorerBot = bot.viewByTitle("Project Explorer"); projectExplorerBot.show(); + // FIXME: Bug 496519. Sometimes, the tree becomes disabled for a certain + // amount of time. This can happen during a long running operation + // (BusyIndicator.showWhile) which brings up the modal dialog "operation + // in progress" and this disables all shells + projectExplorerBot.bot().waitUntil(Conditions.widgetIsEnabled(projectExplorerBot.bot().tree())); SWTBotTreeItem treeItem = projectExplorerBot.bot().tree().getTreeItem(projectName); treeItem.select(); return treeItem; @@ -488,7 +746,7 @@ public final class SWTBotUtils { if (res[0] != null) { fail(res[0].getMessage()); } - waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -498,11 +756,35 @@ public final class SWTBotUtils { * the {@link SWTBotTable} table */ public static void maximizeTable(SWTBotTable tableBot) { + final AtomicBoolean controlResized = new AtomicBoolean(); + UIThreadRunnable.syncExec(new VoidResult() { + @Override + public void run() { + tableBot.widget.addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + tableBot.widget.removeControlListener(this); + controlResized.set(true); + } + }); + } + }); try { tableBot.pressShortcut(KeyStroke.getInstance(IKeyLookup.CTRL_NAME + "+"), KeyStroke.getInstance("M")); } catch (ParseException e) { fail(); } + new SWTBot().waitUntil(new DefaultCondition() { + @Override + public boolean test() throws Exception { + return controlResized.get(); + } + + @Override + public String getFailureMessage() { + return "Control was not resized"; + } + }); } /** @@ -549,11 +831,41 @@ public final class SWTBotUtils { bot.waitUntil(ConditionHelpers.IsTreeNodeAvailable(nodeNames[0], tree)); SWTBotTreeItem currentNode = tree.getTreeItem(nodeNames[0]); - for (int i = 1; i < nodeNames.length; i++) { + return getTreeItem(bot, currentNode, Arrays.copyOfRange(nodeNames, 1, nodeNames.length)); + } + + /** + * Get the tree item from a parent tree item at the specified location + * + * @param bot + * the SWTBot + * @param treeItem + * the treeItem to find the tree item under + * @param nodeNames + * the path to the tree item, in the form of node names (from + * parent to child). + * @return the tree item + */ + public static SWTBotTreeItem getTreeItem(SWTBot bot, SWTBotTreeItem treeItem, String... nodeNames) { + if (nodeNames.length == 0) { + return treeItem; + } + + SWTBotTreeItem currentNode = treeItem; + for (int i = 0; i < nodeNames.length; i++) { + bot.waitUntil(ConditionHelpers.treeItemHasChildren(treeItem)); currentNode.expand(); String nodeName = nodeNames[i]; - bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + try { + bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + } catch (TimeoutException e) { + //FIXME: Sometimes in a JFace TreeViewer, it expands to nothing. Need to find out why. + currentNode.collapse(); + currentNode.expand(); + bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + } + SWTBotTreeItem newNode = currentNode.getNode(nodeName); currentNode = newNode; } @@ -561,6 +873,21 @@ public final class SWTBotUtils { return currentNode; } + /** + * Press the keyboard shortcut that goes to the top of a tree widget. The + * key combination can differ on different platforms. + * + * @param keyboard + * the keyboard to use + */ + public static void pressShortcutGoToTreeTop(Keyboard keyboard) { + if (SWTUtils.isMac()) { + keyboard.pressShortcut(Keystrokes.ALT, Keystrokes.UP); + } else { + keyboard.pressShortcut(Keystrokes.HOME); + } + } + /** * Get the active events editor. Note that this will wait until such editor * is available. @@ -570,25 +897,50 @@ public final class SWTBotUtils { * @return the active events editor */ public static SWTBotEditor activeEventsEditor(final SWTWorkbenchBot workbenchBot) { - final SWTBotEditor editor[] = new SWTBotEditor[1]; - workbenchBot.waitUntil(new DefaultCondition() { - @Override - public boolean test() throws Exception { - List editors = workbenchBot.editors(WidgetMatcherFactory.withPartId(TmfEventsEditor.ID)); - for (SWTBotEditor e : editors) { - if (e.isActive() && !e.getWidget().isDisposed()) { - editor[0] = e; - return true; - } - } - return false; - } + ConditionHelpers.ActiveEventsEditor condition = new ConditionHelpers.ActiveEventsEditor(workbenchBot, null); + workbenchBot.waitUntil(condition); + return condition.getActiveEditor(); + } - @Override - public String getFailureMessage() { - return "Active events editor not found"; + /** + * Get the active events editor. Note that this will wait until such editor + * is available. + * + * @param workbenchBot + * a given workbench bot + * @param editorTitle + * the desired editor title. If null, any active events editor + * will be considered valid. + * @return the active events editor + */ + public static SWTBotEditor activeEventsEditor(final SWTWorkbenchBot workbenchBot, String editorTitle) { + ConditionHelpers.ActiveEventsEditor condition = new ConditionHelpers.ActiveEventsEditor(workbenchBot, editorTitle); + workbenchBot.waitUntil(condition); + return condition.getActiveEditor(); + } + + /** + * Open the preferences dialog and return the corresponding shell. + * + * @param bot + * a given workbench bot + * @return the preferences shell + */ + public static SWTBotShell openPreferences(SWTBot bot) { + if (SWTUtils.isMac()) { + // On Mac, the Preferences menu item is under the application name. + // For some reason, we can't access the application menu anymore so + // we use the keyboard shortcut. + try { + bot.activeShell().pressShortcut(KeyStroke.getInstance(IKeyLookup.COMMAND_NAME + "+"), KeyStroke.getInstance(",")); + } catch (ParseException e) { + fail(); } - }); - return editor[0]; + } else { + bot.menu(WINDOW_MENU).menu(PREFERENCES_MENU_ITEM).click(); + } + + bot.waitUntil(Conditions.shellIsActive(PREFERENCES_MENU_ITEM)); + return bot.activeShell(); } }