From 101bcc6537f5cca823925bd159fa704892dced58 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Wed, 26 Oct 2016 20:35:25 -0400 Subject: [PATCH] timing.swtbot: add Generic SegmentTable tests This makes table tests truly extendible. In order to implement custom tests, one must override getSegmentStoreProvider with the analysis to test, createSegment to return the right type of segment and the test validation they want. The System Call table view is an example implementation. Change-Id: Id77c8afce3a5296d066d94885e8f54ddcf719de0 Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/84446 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Hudson CI --- .../META-INF/MANIFEST.MF | 6 +- .../META-INF/MANIFEST.MF | 3 +- .../SystemCallLatencyTableAnalysisTest.java | 379 +++--------- .../META-INF/MANIFEST.MF | 6 +- .../build.properties | 3 +- .../plugin.xml | 14 + .../swtbot/tests/table/SegmentTableTest.java | 552 ++++++++++++++++++ .../AbstractSegmentStoreTableViewer.java | 29 + 8 files changed, 679 insertions(+), 313 deletions(-) create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/plugin.xml create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/timing/ui/swtbot/tests/table/SegmentTableTest.java diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF index 3a05843db1..4945e61630 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF @@ -34,5 +34,9 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch, org.eclipse.tracecompass.internal.analysis.os.linux.core.inputoutput.handlers;x-internal:=true, org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests", org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests", - org.eclipse.tracecompass.internal.analysis.os.linux.core.latency;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests", + org.eclipse.tracecompass.internal.analysis.os.linux.core.latency; + x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests, + org.eclipse.tracecompass.analysis.os.linux.ui, + org.eclipse.tracecompass.lttng2.kernel.core.tests, + org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests", org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests" diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/META-INF/MANIFEST.MF index ea9974e502..7cf4e261ff 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/META-INF/MANIFEST.MF @@ -31,7 +31,8 @@ Require-Bundle: org.apache.log4j, org.eclipse.tracecompass.analysis.os.linux.core, org.eclipse.tracecompass.segmentstore.core, org.eclipse.tracecompass.lttng2.kernel.core, - org.eclipse.tracecompass.tmf.ui.tests + org.eclipse.tracecompass.tmf.ui.tests, + org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests Import-Package: com.google.common.collect;version="15.0.0", org.eclipse.tracecompass.testtraces.ctf, org.swtchart diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyTableAnalysisTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyTableAnalysisTest.java index b1ac1070d1..358d252e85 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyTableAnalysisTest.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/os/linux/ui/swtbot/tests/latency/SystemCallLatencyTableAnalysisTest.java @@ -14,110 +14,66 @@ package org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests.latency; 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 static org.junit.Assert.fail; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.Logger; -import org.apache.log4j.SimpleLayout; import org.eclipse.core.runtime.FileLocator; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; 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.junit.SWTBotJunit4ClassRunner; -import org.eclipse.swtbot.swt.finder.results.BoolResult; import org.eclipse.swtbot.swt.finder.results.Result; -import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences; -import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.table.SegmentTableTest; import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableView; import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableViewer; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.SystemCall; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.SystemCallLatencyAnalysis; import org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency.SystemCallLatencyView; -import org.eclipse.tracecompass.segmentstore.core.BasicSegment; +import org.eclipse.tracecompass.segmentstore.core.ISegment; import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; -import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; -import org.eclipse.tracecompass.tmf.ui.dialog.TmfFileDialogFactory; import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers; import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils; import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewReference; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.WorkbenchException; -import org.junit.After; -import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; /** - * Tests of the latency table + * SystemCall Latency Table Test. This adds specific tests for the system call + * name for the TSV export and adds a column test. * * @author Matthew Khouzam */ @RunWith(SWTBotJunit4ClassRunner.class) -public class SystemCallLatencyTableAnalysisTest { +public class SystemCallLatencyTableAnalysisTest extends SegmentTableTest { private static final String TRACE_TYPE = "org.eclipse.linuxtools.lttng2.kernel.tracetype"; private static final String PROJECT_NAME = "test"; - private static final String VIEW_ID = SystemCallLatencyView.ID; - private static final String TRACING_PERSPECTIVE_ID = "org.eclipse.linuxtools.tmf.ui.perspective"; + static final String VIEW_ID = SystemCallLatencyView.ID; + private static final SystemCallLatencyAnalysis fSystemCallLatencyAnalysis = new SystemCallLatencyAnalysis(); - /** The Log4j logger instance. */ - private static final Logger fLogger = Logger.getRootLogger(); - private SystemCallLatencyView fLatencyView; - private AbstractSegmentStoreTableViewer fTable; + @Override + protected ISegmentStoreProvider getSegStoreProvider() { + return fSystemCallLatencyAnalysis; + } /** * Things to setup */ @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(); - final List openViews = bot.views(); - for (SWTBotView view : openViews) { - if (view.getTitle().equals("Welcome")) { - view.close(); - bot.waitUntil(ConditionHelpers.ViewIsClosed(view)); - } - } - /* Switch perspectives */ - switchTracingPerspective(); - /* Finish waiting for eclipse to load */ - WaitUtils.waitForJobs(); - + SegmentTableTest.beforeClass(); } - /** - * Opens a latency table - */ - @Before - public void createTable() { + @Override + protected AbstractSegmentStoreTableView openTable() { /* * Open latency view */ @@ -135,261 +91,35 @@ public class SystemCallLatencyTableAnalysisTest { if (!(viewPart instanceof SystemCallLatencyView)) { fail("Could not instanciate view"); } - fLatencyView = (SystemCallLatencyView) viewPart; - fTable = fLatencyView.getSegmentStoreViewer(); - assertNotNull(fTable); + return (SystemCallLatencyView) viewPart; } - /** - * Closes the view - */ - @After - public void closeTable() { - final SWTWorkbenchBot swtWorkbenchBot = new SWTWorkbenchBot(); - SWTBotView viewBot = swtWorkbenchBot.viewById(VIEW_ID); - viewBot.close(); + @Override + protected @NonNull ISegment createSegment(long start, long end) { + // Notice the string is interned, that saves a lot of ram. + return new SystemCall(new SystemCall.InitialInfo(start, start % 3 == 0 ? "rightpad" : "leftpad"), end); } - private static void switchTracingPerspective() { - final Exception retE[] = new Exception[1]; - if (!UIThreadRunnable.syncExec(new BoolResult() { - @Override - public Boolean run() { - try { - PlatformUI.getWorkbench().showPerspective(TRACING_PERSPECTIVE_ID, - PlatformUI.getWorkbench().getActiveWorkbenchWindow()); - } catch (WorkbenchException e) { - retE[0] = e; - return false; - } - return true; - } - })) { - fail(retE[0].getMessage()); - } - - } - - /** - * Test incrementing - */ @Test + @Override public void climbTest() { - List<@NonNull BasicSegment> fixture = new ArrayList<>(); - for (int i = 0; i < 100; i++) { - fixture.add(new BasicSegment(i, 2 * i)); - } - - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + super.climbTest(); + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + tableBot.header("System Call").click(); + // this is an assert in the sense that it will timeout if it is not true + // FIXME: The first one should be leftpad, but because of preceding + // sorts, it first sort descending in this case + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "rightpad", 0, 3)); + tableBot.header("System Call").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "leftpad", 0, 3)); + // Test that duration still works after having tested System Call tableBot.header("Duration").click(); bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); tableBot.header("Duration").click(); bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "99", 0, 2)); - } - - /** - * Test decrementing - */ - @Test - public void decrementingTest() { - List<@NonNull BasicSegment> fixture = new ArrayList<>(); - for (int i = 100; i >= 0; i--) { - fixture.add(new BasicSegment(i, 2 * i)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2)); - } - - /** - * Test small table - */ - @Test - public void smallTest() { - List<@NonNull BasicSegment> fixture = new ArrayList<>(); - for (int i = 1; i >= 0; i--) { - fixture.add(new BasicSegment(i, 2 * i)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); - } - - /** - * Test large - */ - @Test - public void largeTest() { - final int size = 1000000; - BasicSegment[] fixture = new BasicSegment[size]; - for (int i = 0; i < size; i++) { - fixture[i] = (new BasicSegment(i, 2 * i)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2)); - } - - /** - * Test noise - */ - @Test - public void noiseTest() { - Random rnd = new Random(); - rnd.setSeed(1234); - final int size = 1000000; - BasicSegment[] fixture = new BasicSegment[size]; - for (int i = 0; i < size; i++) { - int start = Math.abs(rnd.nextInt(100000000)); - int end = start + Math.abs(rnd.nextInt(1000000)); - fixture[i] = (new BasicSegment(start, end)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "894,633", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2)); - } - - /** - * Test gaussian noise - */ - @Test - public void gaussianNoiseTest() { - Random rnd = new Random(); - rnd.setSeed(1234); - List<@NonNull BasicSegment> fixture = new ArrayList<>(); - for (int i = 1; i <= 1000000; i++) { - int start = Math.abs(rnd.nextInt(100000000)); - final int delta = Math.abs(rnd.nextInt(1000)); - int end = start + delta * delta; - fixture.add(new BasicSegment(start, end)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "400,689", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); - tableBot.header("Duration").click(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "998,001", 0, 2)); - } - - /** - * Test creating a tsv - * - * @throws NoSuchMethodException - * Error creating the tsv - * @throws IOException - * no such file or the file is locked. - */ - @Ignore - @Test - public void testWriteToTsv() throws NoSuchMethodException, IOException { - - List<@NonNull BasicSegment> fixture = new ArrayList<>(); - for (int i = 1; i <= 20; i++) { - int start = i; - final int delta = i; - int end = start + delta * delta; - fixture.add(new BasicSegment(start, end)); - } - assertNotNull(fTable); - fTable.updateModel(fixture); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); - SWTBot bot = new SWTBot(); - bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); - SWTWorkbenchBot swtWorkbenchBot = new SWTWorkbenchBot(); - SWTBotView viewBot = swtWorkbenchBot.viewById(VIEW_ID); - List actionResult = Arrays.asList(testToTsv(viewBot)); - String absolutePath = TmfTraceManager.getTemporaryDirPath() + File.separator + "syscallLatencyTest.testWriteToTsv.tsv"; - TmfFileDialogFactory.setOverrideFiles(absolutePath); - SWTBotMenu menuBot = viewBot.viewMenu().menu("Export to TSV"); - try { - assertTrue(menuBot.isEnabled()); - assertTrue(menuBot.isVisible()); - menuBot.click(); - - try (BufferedReader br = new BufferedReader(new FileReader(absolutePath))) { - List lines = br.lines().collect(Collectors.toList()); - assertEquals("Both reads", actionResult, lines); - } - } finally { - new File(absolutePath).delete(); - } - - } - - private String[] testToTsv(SWTBotView view) throws NoSuchMethodException { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - assertNotNull(os); - Class<@NonNull AbstractSegmentStoreTableView> clazz = AbstractSegmentStoreTableView.class; - Method method = clazz.getDeclaredMethod("exportToTsv", java.io.OutputStream.class); - method.setAccessible(true); - final Exception[] except = new Exception[1]; - UIThreadRunnable.syncExec(() -> { - try { - method.invoke(fLatencyView, os); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - except[0] = e; - } - }); - assertNull(except[0]); - @SuppressWarnings("null") - String[] lines = String.valueOf(os).split(System.getProperty("line.separator")); - assertNotNull(lines); - assertEquals("number of lines", 21, lines.length); - assertEquals("header", "Start Time\tEnd Time\tDuration", lines[0]); - // not a straight up string compare due to time zones. Kathmandu and - // Eucla have 15 minute time zones. - assertTrue("line 1", lines[1].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s001\\t\\d\\d:\\d\\d:00.000 000 002\\t1")); - assertTrue("line 2", lines[2].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s002\\t\\d\\d:\\d\\d:00.000 000 006\\t4")); - assertTrue("line 3", lines[3].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s003\\t\\d\\d:\\d\\d:00.000 000 012\\t9")); - assertTrue("line 4", lines[4].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s004\\t\\d\\d:\\d\\d:00.000 000 020\\t16")); - assertTrue("line 5", lines[5].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s005\\t\\d\\d:\\d\\d:00.000 000 030\\t25")); - assertTrue("line 6", lines[6].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s006\\t\\d\\d:\\d\\d:00.000 000 042\\t36")); - assertTrue("line 7", lines[7].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s007\\t\\d\\d:\\d\\d:00.000 000 056\\t49")); - assertTrue("line 8", lines[8].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s008\\t\\d\\d:\\d\\d:00.000 000 072\\t64")); - assertTrue("line 9", lines[9].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s009\\t\\d\\d:\\d\\d:00.000 000 090\\t81")); - assertTrue("line 10", lines[10].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s010\\t\\d\\d:\\d\\d:00.000 000 110\\t100")); - assertTrue("line 11", lines[11].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s011\\t\\d\\d:\\d\\d:00.000 000 132\\t121")); - assertTrue("line 12", lines[12].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s012\\t\\d\\d:\\d\\d:00.000 000 156\\t144")); - assertTrue("line 13", lines[13].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s013\\t\\d\\d:\\d\\d:00.000 000 182\\t169")); - assertTrue("line 14", lines[14].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s014\\t\\d\\d:\\d\\d:00.000 000 210\\t196")); - assertTrue("line 15", lines[15].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s015\\t\\d\\d:\\d\\d:00.000 000 240\\t225")); - assertTrue("line 16", lines[16].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s016\\t\\d\\d:\\d\\d:00.000 000 272\\t256")); - assertTrue("line 17", lines[17].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s017\\t\\d\\d:\\d\\d:00.000 000 306\\t289")); - assertTrue("line 18", lines[18].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s018\\t\\d\\d:\\d\\d:00.000 000 342\\t324")); - assertTrue("line 19", lines[19].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s019\\t\\d\\d:\\d\\d:00.000 000 380\\t361")); - assertTrue("line 20", lines[20].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s020\\t\\d\\d:\\d\\d:00.000 000 420\\t400")); - return lines; + tableBot.header("Start Time").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "99", 0, 2)); } /** @@ -412,9 +142,13 @@ public class SystemCallLatencyTableAnalysisTest { SWTBotUtils.createProject(PROJECT_NAME); SWTBotUtils.openTrace(PROJECT_NAME, tracePath, TRACE_TYPE); WaitUtils.waitForJobs(); - createTable(); + AbstractSegmentStoreTableView tableView = openTable(); + setTableView(tableView); + AbstractSegmentStoreTableViewer table = tableView.getSegmentStoreViewer(); + assertNotNull(table); + setTable(table); WaitUtils.waitForJobs(); - SWTBotTable tableBot = new SWTBotTable(fTable.getTableViewer().getTable()); + SWTBotTable tableBot = new SWTBotTable(table.getTableViewer().getTable()); bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "24,100", 0, 2)); tableBot.header("Duration").click(); bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1,000", 0, 2)); @@ -423,4 +157,33 @@ public class SystemCallLatencyTableAnalysisTest { bot.closeAllEditors(); SWTBotUtils.deleteProject(PROJECT_NAME, bot); } + + @Override + protected void testTsv(String[] lines) { + assertNotNull(lines); + assertEquals("number of lines", 21, lines.length); + assertEquals("header", "Start Time\tEnd Time\tDuration\tSystem Call", lines[0]); + // not a straight up string compare due to time zones. Kathmandu and + // Eucla have 15 minute time zones. + assertTrue("line 1 : " + lines[1], lines[1].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s001\\t\\d\\d:\\d\\d:00.000 000 002\\t1\\tleftpad")); + assertTrue("line 2 : " + lines[2], lines[2].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s002\\t\\d\\d:\\d\\d:00.000 000 006\\t4\\tleftpad")); + assertTrue("line 3 : " + lines[3], lines[3].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s003\\t\\d\\d:\\d\\d:00.000 000 012\\t9\\trightpad")); + assertTrue("line 4 : " + lines[4], lines[4].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s004\\t\\d\\d:\\d\\d:00.000 000 020\\t16\\tleftpad")); + assertTrue("line 5 : " + lines[5], lines[5].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s005\\t\\d\\d:\\d\\d:00.000 000 030\\t25\\tleftpad")); + assertTrue("line 6 : " + lines[6], lines[6].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s006\\t\\d\\d:\\d\\d:00.000 000 042\\t36\\trightpad")); + assertTrue("line 7 : " + lines[7], lines[7].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s007\\t\\d\\d:\\d\\d:00.000 000 056\\t49\\tleftpad")); + assertTrue("line 8 : " + lines[8], lines[8].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s008\\t\\d\\d:\\d\\d:00.000 000 072\\t64\\tleftpad")); + assertTrue("line 9 : " + lines[9], lines[9].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s009\\t\\d\\d:\\d\\d:00.000 000 090\\t81\\trightpad")); + assertTrue("line 10 : " + lines[10], lines[10].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s010\\t\\d\\d:\\d\\d:00.000 000 110\\t100\\tleftpad")); + assertTrue("line 11 : " + lines[11], lines[11].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s011\\t\\d\\d:\\d\\d:00.000 000 132\\t121\\tleftpad")); + assertTrue("line 12 : " + lines[12], lines[12].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s012\\t\\d\\d:\\d\\d:00.000 000 156\\t144\\trightpad")); + assertTrue("line 13 : " + lines[13], lines[13].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s013\\t\\d\\d:\\d\\d:00.000 000 182\\t169\\tleftpad")); + assertTrue("line 14 : " + lines[14], lines[14].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s014\\t\\d\\d:\\d\\d:00.000 000 210\\t196\\tleftpad")); + assertTrue("line 15 : " + lines[15], lines[15].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s015\\t\\d\\d:\\d\\d:00.000 000 240\\t225\\trightpad")); + assertTrue("line 16 : " + lines[16], lines[16].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s016\\t\\d\\d:\\d\\d:00.000 000 272\\t256\\tleftpad")); + assertTrue("line 17 : " + lines[17], lines[17].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s017\\t\\d\\d:\\d\\d:00.000 000 306\\t289\\tleftpad")); + assertTrue("line 18 : " + lines[18], lines[18].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s018\\t\\d\\d:\\d\\d:00.000 000 342\\t324\\trightpad")); + assertTrue("line 19 : " + lines[19], lines[19].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s019\\t\\d\\d:\\d\\d:00.000 000 380\\t361\\tleftpad")); + assertTrue("line 20 : " + lines[20], lines[20].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s020\\t\\d\\d:\\d\\d:00.000 000 420\\t400\\tleftpad")); + } } diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/META-INF/MANIFEST.MF index b328f0550b..6058908314 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/META-INF/MANIFEST.MF @@ -7,7 +7,8 @@ Bundle-Localization: plugin Bundle-SymbolicName: org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests;singleton:=true Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Export-Package: org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.flamegraph;x-internal:=true +Export-Package: org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.flamegraph;x-internal:=true, + org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.table Require-Bundle: org.apache.log4j, org.eclipse.core.resources, org.eclipse.core.runtime, @@ -27,6 +28,7 @@ Require-Bundle: org.apache.log4j, org.eclipse.ui.views, org.junit, org.eclipse.tracecompass.analysis.timing.core.tests, - org.eclipse.tracecompass.tmf.ui.tests + org.eclipse.tracecompass.tmf.ui.tests, + org.eclipse.tracecompass.segmentstore.core Import-Package: com.google.common.collect, org.swtchart diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/build.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/build.properties index 3f7a01bf09..d2c81f5925 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/build.properties +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/build.properties @@ -14,6 +14,7 @@ source.. = src/ bin.includes = META-INF/,\ .,\ plugin.properties,\ - about.html + about.html,\ + plugin.xml additional.bundles = org.eclipse.jdt.annotation jars.extra.classpath = platform:/plugin/org.eclipse.jdt.annotation diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/plugin.xml new file mode 100644 index 0000000000..6d23f44af8 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/plugin.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/timing/ui/swtbot/tests/table/SegmentTableTest.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/timing/ui/swtbot/tests/table/SegmentTableTest.java new file mode 100644 index 0000000000..57df8f22d3 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests/src/org/eclipse/tracecompass/analysis/timing/ui/swtbot/tests/table/SegmentTableTest.java @@ -0,0 +1,552 @@ +/******************************************************************************* + * 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.analysis.timing.ui.swtbot.tests.table; + +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.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.Logger; +import org.apache.log4j.SimpleLayout; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +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.results.Result; +import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableView; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableViewer; +import org.eclipse.tracecompass.segmentstore.core.BasicSegment; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; +import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory; +import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory.SegmentStoreType; +import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.ui.dialog.TmfFileDialogFactory; +import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers; +import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils; +import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Tests of the latency table to extend it to custom tables, 4 steps are needed. + *
    + *
  1. Override {@link #createSegment(long, long)}
  2. + *
  3. Override {@link #openTable()} to open the desired table view
  4. + *
  5. Override {@link #getSegStoreProvider()} to retrieve the segment store + * provider with the desirable aspects
  6. + *
  7. Override {@link #testTsv(String[])} to test the content of the output to + * TSV
  8. + *
+ * + * Feel free to override any test and add additional tests but remember to call + * super.test() before. + * + * @author Matthew Khouzam + */ +public class SegmentTableTest { + + /** + * Test table + * + * @author Matthew Khouzam + */ + public static final class TestSegmentStoreTableView extends AbstractSegmentStoreTableView { + /** + * ID of this view + */ + public static final String ID = "org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.table.TestSegmentStoreTableView"; //$NON-NLS-1$ + + /** + * Constructor + */ + public TestSegmentStoreTableView() { + } + + SegmentTableTest fTest; + + /** + * Set the parent test + * + * @param test + * the test + */ + public void setTest(SegmentTableTest test) { + fTest = test; + } + + @Override + protected @NonNull AbstractSegmentStoreTableViewer createSegmentStoreViewer(@NonNull TableViewer tableViewer) { + return new AbstractSegmentStoreTableViewer(tableViewer) { + + @Override + protected @Nullable ISegmentStoreProvider getSegmentStoreProvider(@NonNull ITmfTrace trace) { + return fTest.getSegStoreProvider(); + } + }; + } + } + + private final class SimpleSegmentStoreProvider implements ISegmentStoreProvider { + @Override + public void removeListener(@NonNull IAnalysisProgressListener listener) { + // do nothing + } + + @Override + public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() { + return fSs; + } + + @Override + public @NonNull Iterable<@NonNull ISegmentAspect> getSegmentAspects() { + return Collections.emptyList(); + } + + @Override + public void addListener(@NonNull IAnalysisProgressListener listener) { + // do nothing + } + } + + private AbstractSegmentStoreTableView fTableView; + private AbstractSegmentStoreTableViewer fTable; + private ISegmentStoreProvider fSsp; + private final ISegmentStore<@NonNull ISegment> fSs = SegmentStoreFactory.createSegmentStore(SegmentStoreType.Fast); + + /** The Log4j logger instance. */ + private static final Logger fLogger = Logger.getRootLogger(); + + /** + * Before class, call by all subclassed + */ + @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(); + final List openViews = bot.views(); + for (SWTBotView view : openViews) { + if (view.getTitle().equals("Welcome")) { + view.close(); + bot.waitUntil(ConditionHelpers.ViewIsClosed(view)); + } + } + /* Switch perspectives */ + SWTBotUtils.switchToTracingPerspective(); + /* Finish waiting for eclipse to load */ + WaitUtils.waitForJobs(); + } + + /** + * Opens a latency table + */ + @Before + public void init() { + setTableView(openTable()); + assertNotNull(getTableView()); + setTable(getTableView().getSegmentStoreViewer()); + assertNotNull(getTable()); + ISegmentStoreProvider segStoreProvider = getSegStoreProvider(); + assertNotNull(segStoreProvider); + UIThreadRunnable.syncExec(() -> getTable().setSegmentProvider(segStoreProvider)); + } + + /** + * Close the table + */ + @After + public void finish() { + new SWTWorkbenchBot().viewById(getTableView().getSite().getId()).close(); + } + + /** + * Create the table viewer to test + * + * @return the table viewer bot + */ + protected AbstractSegmentStoreTableView openTable() { + AbstractSegmentStoreTableView tableView = getTableView(); + if (tableView != null) { + return tableView; + } + IViewPart vp = null; + final IWorkbench workbench = PlatformUI.getWorkbench(); + vp = UIThreadRunnable.syncExec((Result) () -> { + try { + return workbench.getActiveWorkbenchWindow().getActivePage().showView(TestSegmentStoreTableView.ID); + } catch (PartInitException e) { + return null; + } + }); + assertNotNull(vp); + assertTrue(vp instanceof TestSegmentStoreTableView); + TestSegmentStoreTableView testSegmentStoreTableView = (TestSegmentStoreTableView) vp; + testSegmentStoreTableView.setTest(this); + fTableView = testSegmentStoreTableView; + + return fTableView; + } + + /** + * Create a segment of the type supported by the table under test, with the + * requested start and end time + * + * @param start + * start time + * @param end + * end time + * @return the segment + */ + protected @NonNull ISegment createSegment(long start, long end) { + return new BasicSegment(start, end); + } + + /** + * Test a climbing data structure. + *

+ * Create segments that are progressively larger and start later. Test that + * the "duration" column sorts well + */ + @Test + public void climbTest() { + List<@NonNull ISegment> fixture = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + fixture.add(createSegment(i, 2 * i)); + } + + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "99", 0, 2)); + } + + /** + * Test a decrementing data structure. + *

+ * Create segments that are progressively shorter and start sooner, + * effectively the inverse sorted {@link #climbTest()} datastructure. Test + * that the "duration" column sorts well + */ + @Test + public void decrementingTest() { + List<@NonNull ISegment> fixture = new ArrayList<>(); + for (int i = 100; i >= 0; i--) { + fixture.add(createSegment(i, 2 * i)); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2)); + } + + /** + * Test small table + *

+ * Test table with 2 segments. Duration sort is tested. + */ + @Test + public void smallTest() { + List<@NonNull ISegment> fixture = new ArrayList<>(); + for (int i = 1; i >= 0; i--) { + fixture.add(createSegment(i, 2 * i)); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); + } + + /** + * Test large table + *

+ * Test table with over 9000 segments. Duration sort is tested. + */ + @Test + public void largeTest() { + final int size = 1000000; + ISegment[] fixture = new ISegment[size]; + for (int i = 0; i < size; i++) { + fixture[i] = createSegment(i, 2 * i); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2)); + } + + /** + * Test table with segments that have durations spread into a random (white + * noise) distribution + *

+ * Test table with a random distribution of segments. Duration sort is + * tested. + */ + @Test + public void noiseTest() { + Random rnd = new Random(); + rnd.setSeed(1234); + final int size = 1000000; + ISegment[] fixture = new ISegment[size]; + for (int i = 0; i < size; i++) { + int start = Math.abs(rnd.nextInt(100000000)); + int end = start + Math.abs(rnd.nextInt(1000000)); + fixture[i] = (createSegment(start, end)); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "894,633", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2)); + } + + /** + * Test table with segments that have durations spread into a gaussian + * (normal) distribution + *

+ * Test table with a gaussian distribution of segments. Duration sort is + * tested. + */ + @Test + public void gaussianNoiseTest() { + Random rnd = new Random(); + rnd.setSeed(1234); + List<@NonNull ISegment> fixture = new ArrayList<>(); + for (int i = 1; i <= 1000000; i++) { + int start = Math.abs(rnd.nextInt(100000000)); + final int delta = Math.abs(rnd.nextInt(1000)); + int end = start + delta * delta; + fixture.add(createSegment(start, end)); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "400,689", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2)); + tableBot.header("Duration").click(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "998,001", 0, 2)); + } + + /** + * Test creating a tsv + * + * @throws NoSuchMethodException + * Error creating the tsv + * @throws IOException + * no such file or the file is locked. + */ + @Test + public void testWriteToTsv() throws NoSuchMethodException, IOException { + + List<@NonNull ISegment> fixture = new ArrayList<>(); + for (int i = 1; i <= 20; i++) { + int start = i; + final int delta = i; + int end = start + delta * delta; + fixture.add(createSegment(start, end)); + } + assertNotNull(getTable()); + getTable().updateModel(fixture); + SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable()); + SWTBot bot = new SWTBot(); + bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2)); + SWTWorkbenchBot swtWorkbenchBot = new SWTWorkbenchBot(); + SWTBotView viewBot = swtWorkbenchBot.viewById(getTableView().getSite().getId()); + String[] lines = extractTsv(viewBot); + testTsv(lines); + List actionResult = Arrays.asList(lines); + String absolutePath = TmfTraceManager.getTemporaryDirPath() + File.separator + "syscallLatencyTest.testWriteToTsv.tsv"; + TmfFileDialogFactory.setOverrideFiles(absolutePath); + SWTBotMenu menuBot = viewBot.viewMenu().menu("Export to TSV"); + try { + assertTrue(menuBot.isEnabled()); + assertTrue(menuBot.isVisible()); + menuBot.click(); + + try (BufferedReader br = new BufferedReader(new FileReader(absolutePath))) { + List actual = br.lines().collect(Collectors.toList()); + assertEquals("Both reads", actionResult, actual); + } + } finally { + new File(absolutePath).delete(); + } + + } + + private String[] extractTsv(SWTBotView viewBot) throws NoSuchMethodException, SecurityException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + assertNotNull(os); + Class<@NonNull AbstractSegmentStoreTableView> clazz = AbstractSegmentStoreTableView.class; + Method method = clazz.getDeclaredMethod("exportToTsv", java.io.OutputStream.class); + method.setAccessible(true); + final Exception[] except = new Exception[1]; + UIThreadRunnable.syncExec(() -> { + try { + method.invoke(getTableView(), os); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + except[0] = e; + } + }); + assertNull(except[0]); + @SuppressWarnings("null") + String[] lines = String.valueOf(os).split(System.getProperty("line.separator")); + return lines; + } + + /** + * Test the TSV generated. For each line, including the header, it should be + * asserted that it is equal to the expected line + * + * @param lines + * every entry, starting with the header + */ + protected void testTsv(String[] lines) { + assertNotNull(lines); + assertEquals("number of lines", 21, lines.length); + assertEquals("header", "Start Time\tEnd Time\tDuration", lines[0]); + // not a straight up string compare due to time zones. Kathmandu and + // Eucla have 15 minute time zones. + assertTrue("line 1", lines[1].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s001\\t\\d\\d:\\d\\d:00.000 000 002\\t1")); + assertTrue("line 2", lines[2].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s002\\t\\d\\d:\\d\\d:00.000 000 006\\t4")); + assertTrue("line 3", lines[3].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s003\\t\\d\\d:\\d\\d:00.000 000 012\\t9")); + assertTrue("line 4", lines[4].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s004\\t\\d\\d:\\d\\d:00.000 000 020\\t16")); + assertTrue("line 5", lines[5].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s005\\t\\d\\d:\\d\\d:00.000 000 030\\t25")); + assertTrue("line 6", lines[6].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s006\\t\\d\\d:\\d\\d:00.000 000 042\\t36")); + assertTrue("line 7", lines[7].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s007\\t\\d\\d:\\d\\d:00.000 000 056\\t49")); + assertTrue("line 8", lines[8].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s008\\t\\d\\d:\\d\\d:00.000 000 072\\t64")); + assertTrue("line 9", lines[9].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s009\\t\\d\\d:\\d\\d:00.000 000 090\\t81")); + assertTrue("line 10", lines[10].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s010\\t\\d\\d:\\d\\d:00.000 000 110\\t100")); + assertTrue("line 11", lines[11].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s011\\t\\d\\d:\\d\\d:00.000 000 132\\t121")); + assertTrue("line 12", lines[12].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s012\\t\\d\\d:\\d\\d:00.000 000 156\\t144")); + assertTrue("line 13", lines[13].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s013\\t\\d\\d:\\d\\d:00.000 000 182\\t169")); + assertTrue("line 14", lines[14].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s014\\t\\d\\d:\\d\\d:00.000 000 210\\t196")); + assertTrue("line 15", lines[15].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s015\\t\\d\\d:\\d\\d:00.000 000 240\\t225")); + assertTrue("line 16", lines[16].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s016\\t\\d\\d:\\d\\d:00.000 000 272\\t256")); + assertTrue("line 17", lines[17].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s017\\t\\d\\d:\\d\\d:00.000 000 306\\t289")); + assertTrue("line 18", lines[18].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s018\\t\\d\\d:\\d\\d:00.000 000 342\\t324")); + assertTrue("line 19", lines[19].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s019\\t\\d\\d:\\d\\d:00.000 000 380\\t361")); + assertTrue("line 20", lines[20].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s020\\t\\d\\d:\\d\\d:00.000 000 420\\t400")); + } + + /** + * Gets the table view + * + * @return the table view + */ + protected AbstractSegmentStoreTableView getTableView() { + return fTableView; + } + + /** + * Sets the table view + * + * @param tableView + * the table view + */ + protected void setTableView(AbstractSegmentStoreTableView tableView) { + fTableView = tableView; + } + + /** + * Gets the table viewer + * + * @return the table viewer + */ + protected AbstractSegmentStoreTableViewer getTable() { + return fTable; + } + + /** + * Set the table viewer + * + * @param table + * the table viewer + */ + protected void setTable(AbstractSegmentStoreTableViewer table) { + fTable = table; + } + + /** + * get the segment store provider + * + * @return the segment store provider + */ + protected ISegmentStoreProvider getSegStoreProvider() { + ISegmentStoreProvider ssp = fSsp; + if (ssp == null) { + ssp = new SimpleSegmentStoreProvider(); + fSsp = ssp; + } + return ssp; + } +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/table/AbstractSegmentStoreTableViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/table/AbstractSegmentStoreTableViewer.java index a3484bbcde..75df3d42db 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/table/AbstractSegmentStoreTableViewer.java +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/table/AbstractSegmentStoreTableViewer.java @@ -30,6 +30,7 @@ import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; @@ -54,6 +55,8 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.tmf.ui.viewers.table.TmfSimpleTableViewer; +import com.google.common.annotations.VisibleForTesting; + /** * Displays the segment store provider data in a column table * @@ -154,6 +157,32 @@ public abstract class AbstractSegmentStoreTableViewer extends TmfSimpleTableView // Operations // ------------------------------------------------------------------------ + /** + * Sets the segment provider, use only in test, only run in display thread + * + * @param segmentProvider + * the segment provider + * @since 1.2 + */ + @VisibleForTesting + public void setSegmentProvider(ISegmentStoreProvider segmentProvider) { + fSegmentProvider = segmentProvider; + // Sort order of the content provider is by start time by default + getTableViewer().setContentProvider(new SegmentStoreContentProvider()); + + Table table = getTableViewer().getTable(); + table.setRedraw(false); + while (table.getColumnCount() > 0) { + table.getColumn(0).dispose(); + } + createColumns(); + createProviderColumns(); + getTableViewer().getTable().addSelectionListener(new TableSelectionListener()); + addPackListener(); + fListener = new SegmentStoreProviderProgressListener(); + table.setRedraw(true); + } + /** * Create default columns for start time, end time and duration */ -- 2.34.1