blob: ba7d2ded70d92cce6cc093ec0a77ac9c5faa6080 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson
*
* 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
*******************************************************************************/
package org.eclipse.tracecompass.incubator.callstack.core.ui.swtbot.tests.flamegraph;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.StreamSupport;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.results.Result;
import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
import org.eclipse.tracecompass.incubator.callstack.core.tests.callgraph.instrumented.AggregationTreeTest;
import org.eclipse.tracecompass.incubator.callstack.core.tests.stubs.CallGraphAnalysisStub;
import org.eclipse.tracecompass.incubator.internal.callstack.core.flamegraph.FlameGraphDataProvider;
import org.eclipse.tracecompass.incubator.internal.callstack.core.flamegraph.FlameGraphDataProviderFactory;
import org.eclipse.tracecompass.incubator.internal.callstack.ui.flamegraph.FlameGraphView;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers.SWTBotTestCondition;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotTimeGraph;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils;
import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
import org.eclipse.ui.IViewPart;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
/**
* Unit tests for the flame graph view
*
* @author Matthew Khouzam
*/
@RunWith(SWTBotJunit4ClassRunner.class)
public class FlameGraphTest extends AggregationTreeTest {
private static final @NonNull String SECONDARY_ID = "org.eclipse.tracecompass.incubator.callstack.ui.swtbot.test";
private static final String FLAMEGRAPH_ID = FlameGraphView.ID;
private SWTWorkbenchBot fBot;
private SWTBotView fViewBot;
private FlameGraphView fFg;
/** The Log4j logger instance. */
private static final Logger fLogger = Logger.getRootLogger();
private TimeGraphViewer fTimeGraphViewer;
private SWTBotTimeGraph fTimeGraph;
/**
* Initialization
*/
@BeforeClass
public static void beforeClass() {
SWTBotUtils.initialize();
Thread.currentThread().setName("SWTBotTest");
/* set up for swtbot */
SWTBotPreferences.TIMEOUT = 20000; /* 20 second timeout */
SWTBotPreferences.KEYBOARD_LAYOUT = "EN_US";
fLogger.removeAllAppenders();
fLogger.addAppender(new ConsoleAppender(new SimpleLayout(), ConsoleAppender.SYSTEM_OUT));
SWTWorkbenchBot bot = new SWTWorkbenchBot();
SWTBotUtils.closeView("welcome", bot);
/* Switch perspectives */
SWTBotUtils.switchToTracingPerspective();
/* Finish waiting for eclipse to load */
WaitUtils.waitForJobs();
}
/**
* Open a flamegraph
*/
@Override
@Before
public void before() {
// Open the flame graph first
fBot = new SWTWorkbenchBot();
SWTBotUtils.openView(FLAMEGRAPH_ID, SECONDARY_ID);
SWTBotView view = fBot.viewById(FLAMEGRAPH_ID);
assertNotNull(view);
fViewBot = view;
FlameGraphView flamegraph = UIThreadRunnable.syncExec((Result<FlameGraphView>) () -> {
IViewPart viewRef = fViewBot.getViewReference().getView(true);
return (viewRef instanceof FlameGraphView) ? (FlameGraphView) viewRef : null;
});
assertNotNull(flamegraph);
fTimeGraphViewer = flamegraph.getTimeGraphViewer();
assertNotNull(fTimeGraphViewer);
SWTBotUtils.maximize(flamegraph);
fFg = flamegraph;
fTimeGraph = new SWTBotTimeGraph(view.bot());
// Now open the trace
super.before();
}
/**
* Clean up after a test, reset the views and reset the states of the
* timegraph by pressing reset on all the resets of the legend
*/
@After
public void after() {
// Calling maximize again will minimize
FlameGraphView fg = fFg;
if (fg != null) {
SWTBotUtils.maximize(fg);
}
// Setting the input to null so the view can be emptied, to avoid race conditions with subsequent tests
TimeGraphViewer tg = fTimeGraphViewer;
if (tg != null) {
UIThreadRunnable.syncExec(() -> {
tg.setInput(null);
tg.refresh();
});
}
fBot.waitUntil(new SWTBotTestCondition() {
@Override
public boolean test() throws Exception {
return fTimeGraph.getEntries().length == 0;
}
@Override
public String getFailureMessage() {
return "Flame graph not emptied";
}
});
fViewBot.close();
fBot.waitUntil(ConditionHelpers.viewIsClosed(fViewBot));
}
private void loadFlameGraph() {
CallGraphAnalysisStub cga = Objects.requireNonNull(getCga());
ITmfTrace trace = getTrace();
Display.getDefault().syncExec(() -> fFg.traceSelected(new TmfTraceSelectedSignal(this, trace)));
FlameGraphDataProvider<?, ?, ?> dp = new FlameGraphDataProvider<>(trace, cga, FlameGraphDataProvider.ID + ':' + SECONDARY_ID);
FlameGraphDataProviderFactory.registerDataProviderWithId(SECONDARY_ID, dp);
UIThreadRunnable.syncExec(() -> fFg.buildFlameGraph(trace, null, null));
fBot.waitUntil(new SWTBotTestCondition() {
@Override
public boolean test() throws Exception {
return fTimeGraph.getEntries().length > 0;
}
@Override
public String getFailureMessage() {
return "Flame graph not ready";
}
});
}
private ITimeGraphEntry selectRoot() {
UIThreadRunnable.syncExec(() -> {
fTimeGraphViewer.selectNextItem();
fTimeGraphViewer.selectNextItem();
fTimeGraphViewer.selectNextItem();
});
ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
assertNotNull(entry);
return entry;
}
private static ITimeEvent getFirstEvent(ITimeGraphEntry actualEntry) {
Optional<@NonNull ? extends ITimeEvent> actualEventOpt = StreamSupport.stream(Spliterators.spliteratorUnknownSize(actualEntry.getTimeEventsIterator(), Spliterator.NONNULL), false)
.filter(i -> (i instanceof TimeEvent)).filter(j -> !(j instanceof NullTimeEvent))
.findFirst();
assertTrue(actualEventOpt.isPresent());
ITimeEvent actualEvent = actualEventOpt.get();
return actualEvent;
}
@Override
public void emptyStateSystemTest() {
super.emptyStateSystemTest();
loadFlameGraph();
ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
assertNull(entry);
}
@Override
public void cascadeTest() {
super.cascadeTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(3, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(996, actualEvent.getDuration());
}
@Override
public void mergeFirstLevelCalleesTest() {
super.mergeFirstLevelCalleesTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(3, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(80, actualEvent.getDuration());
}
@Override
public void multiFunctionRootsSecondTest() {
super.multiFunctionRootsSecondTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(2, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(10, actualEvent.getDuration());
}
@Override
public void mergeSecondLevelCalleesTest() {
super.mergeSecondLevelCalleesTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(4, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(90, actualEvent.getDuration());
}
@Override
public void multiFunctionRootsTest() {
super.multiFunctionRootsTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(2, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(10, actualEvent.getDuration());
}
/**
* Also test statistics tooltip
*/
@Override
public void treeTest() {
super.treeTest();
loadFlameGraph();
ITimeGraphEntry entry = selectRoot();
assertEquals(3, entry.getChildren().size());
ITimeGraphEntry actualEntry = entry.getChildren().get(1);
ITimeEvent actualEvent = getFirstEvent(actualEntry);
assertNotNull(actualEvent);
assertEquals(80, actualEvent.getDuration());
FlameGraphView fg = fFg;
Map<String, String> tooltip = fg.getPresentationProvider().getEventHoverToolTipInfo(actualEvent);
assertTrue(tooltip.toString().contains("duration=80 ns"));
assertTrue(tooltip.toString().contains("duration=40 ns"));
tooltip = fg.getPresentationProvider().getEventHoverToolTipInfo(actualEvent, 5);
assertTrue(tooltip.toString().contains("duration=80 ns"));
assertTrue(tooltip.toString().contains("duration=40 ns"));
}
/**
* Takes too much ram
*/
@Ignore
@Override
public void largeTest() {
// Do nothing
}
}