Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 9c6ec019982853a96a798a572bcbe5f65b2afa45 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/*******************************************************************************
 * Copyright (c) 2015, 2019 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
 *
 * Contributors:
 *   Matthew Khouzam - Initial API and implementation
 *******************************************************************************/

package org.eclipse.tracecompass.tmf.ui.swtbot.tests.viewers.events;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.matchers.WidgetOfType;
import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
import org.eclipse.swtbot.swt.finder.widgets.AbstractSWTBot;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotRootMenu;
import org.eclipse.tracecompass.internal.tmf.ui.views.TmfAlignmentSynchronizer;
import org.eclipse.tracecompass.tmf.core.io.BufferedRandomAccessFile;
import org.eclipse.tracecompass.tmf.ui.project.wizards.NewTmfProjectWizard;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotSash;
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.swtbot.tests.shared.TestingPerspectiveFactory;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.views.TimeGraphViewStub;
import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils;
import org.eclipse.tracecompass.tmf.ui.views.histogram.HistogramView;
import org.eclipse.tracecompass.tmf.ui.views.timechart.TimeChartView;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
import org.eclipse.ui.IFolderLayout;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Test common time axis for views
 *
 * @author Matthew Khouzam
 */
@RunWith(SWTBotJunit4ClassRunner.class)
public class TmfAlignTimeAxisTest {

    /**
     * wait for throttler (2x the throttler time)
     */
    private static final String TRACE_START = "<trace>";
    private static final String EVENT_BEGIN = "<event timestamp=\"";
    private static final String EVENT_MIDDLE = " \" name=\"event\"><field name=\"field\" value=\"";
    private static final String EVENT_END = "\" type=\"int\" />" + "</event>";
    private static final String TRACE_END = "</trace>";

    private static final String PROJET_NAME = "TestAxisAlignment";
    private static final int NUM_EVENTS = 100;

    private static final String ALIGN_VIEWS_ACTION_NAME = "Align Views";

    /**
     * Using a small ratio for the editor so that other views have enough space
     * to be drawn, even when a low screen resolution is used.
     */
    private static final float EDITOR_AREA_RATIO = 0.10f;

    /** The Log4j logger instance. */
    private static final Logger fLogger = Logger.getRootLogger();
    private static SWTWorkbenchBot fBot;

    private static String makeEvent(int ts, int val) {
        return EVENT_BEGIN + Integer.toString(ts) + EVENT_MIDDLE + Integer.toString(val) + EVENT_END + "\n";
    }

    private static File fLocation;

    /**
     * Initialization, creates a temp trace
     *
     * @throws IOException
     *             should not happen
     */
    @BeforeClass
    public static void init() throws IOException {
        SWTBotUtils.initialize();
        Thread.currentThread().setName("SWTBot Thread"); // for the debugger
        /* set up for swtbot */
        SWTBotPreferences.TIMEOUT = 20000; /* 20 second timeout */
        fLogger.removeAllAppenders();
        fLogger.addAppender(new ConsoleAppender(new SimpleLayout()));
        SWTWorkbenchBot bot = new SWTWorkbenchBot();

        /* finish waiting for eclipse to load */
        WaitUtils.waitForJobs();
        fLocation = File.createTempFile("sample", ".xml");
        try (BufferedRandomAccessFile braf = new BufferedRandomAccessFile(fLocation, "rw")) {
            braf.writeBytes(TRACE_START);
            for (int i = 0; i < NUM_EVENTS; i++) {
                braf.writeBytes(makeEvent(i * 100, i % 4));
            }
            braf.writeBytes(TRACE_END);
        }
        SWTBotUtils.createProject(PROJET_NAME);
        SWTBotUtils.selectTracesFolder(bot, PROJET_NAME);
    }

    /**
     * Delete file
     */
    @AfterClass
    public static void cleanup() {
        fBot.perspectiveById(TestingPerspectiveFactory.ID).close();
        fBot.perspectiveById(AlignPerspectiveFactory1.ID).close();
        fBot.perspectiveById(AlignPerspectiveFactory2.ID).close();
        fBot.perspectiveById(AlignPerspectiveFactory3.ID).close();
        SWTBotUtils.deleteProject(PROJET_NAME, new SWTWorkbenchBot());
        fLocation.delete();
        fLogger.removeAllAppenders();
    }

    /**
     * Open the trace
     */
    @Before
    public void before() {
        SWTBotUtils.openTrace(PROJET_NAME, fLocation.getAbsolutePath(), "org.eclipse.linuxtools.tmf.core.tests.xmlstub");
    }

    /**
     * Close the trace
     */
    @After
    public void after() {
        SWTWorkbenchBot bot = new SWTWorkbenchBot();
        SWTBotUtils.activeEventsEditor(bot).close();
        /* Switch back to Testing perspective since several tests change the perspective */
        SWTBotUtils.switchToPerspective(TestingPerspectiveFactory.ID);
        SWTBotUtils.closeSecondaryShells(fBot);
    }

    /**
     * Test 3 views, none overlap, the histogram, time graph stub and timechart are
     * aligned. The histogram is moved, we check that the time graph stub and
     * timechart follow.
     */
    @Test
    public void testMoveHistogramOthersFollow() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory1.ID);
        testAligned(HistogramView.ID, TimeGraphViewStub.ID, TimeChartView.ID);
    }

    /**
     * Test 3 views, none overlap, the histogram, time graph stub and timechart are
     * aligned. The time graph stub is moved, we check that the histogram and
     * timechart follow.
     */
    @Test
    public void testMoveTgStubOthersFollow() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory1.ID);
        testAligned(TimeGraphViewStub.ID, HistogramView.ID, TimeChartView.ID);
    }

    /**
     * Test 3 views, overlap on the resizing view. The histogram and timechart
     * are overlapping, and the time graph stub is aligned. The histogram is moved, we
     * check that the time graph stub follows. The hidden timechart is not checked.
     */
    @Test
    public void testOverlappingHistogramMove() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory2.ID);
        testAligned(HistogramView.ID, TimeGraphViewStub.ID);
    }

    /**
     * Test 3 views, overlap on the resizing view. The histogram and timechart are
     * overlapping, and the time graph stub is aligned. The time graph stub is
     * moved, we check that the histogram follows. The hidden timechart is not
     * checked.
     */
    @Test
    public void testOverlappingTgStubMove() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory2.ID);
        testAligned(TimeGraphViewStub.ID, HistogramView.ID);
    }

    /**
     * Test 3 views. No overlap. The histogram and timechart are aligned, but
     * the time graph stub is not aligned. The histogram is moved, we check that the
     * timechart follows and that the time graph stub does NOT follow.
     */
    @Test
    public void testNotOverlappingHistogramMove() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory3.ID);
        testAligned(HistogramView.ID, TimeChartView.ID);
        testNotAligned(HistogramView.ID, TimeGraphViewStub.ID);
    }

    /**
     * Test 3 views. No overlap. The histogram and timechart are aligned, but
     * the time graph stub is not aligned. The time graph stub is moved, we check that the
     * histogram and timechart do NOT follow.
     */
    @Test
    public void testNotOverlappingTgStubMove() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory3.ID);
        testNotAligned(TimeGraphViewStub.ID, HistogramView.ID, TimeChartView.ID);
    }

    /**
     * Test for the "Align Views" menu item
     */
    @Test
    public void testMenuItem() {
        fBot = new SWTWorkbenchBot();
        switchToPerspective(AlignPerspectiveFactory1.ID);
        SWTBotView viewBot = fBot.viewById(TimeGraphViewStub.ID);
        SWTBotRootMenu viewMenu = viewBot.viewMenu();

        SWTBotMenu menuItems = viewMenu.menu(ALIGN_VIEWS_ACTION_NAME);
        assertTrue("Align views", menuItems.isChecked());
    }

    private static void switchToPerspective(String id) {
        // switch to the proper perspective and wait for views to align
        SWTBotUtils.switchToPerspective(id);
        // the PerspectiveSwitcher triggers a deferred layout
        Display.getDefault().syncExec(() -> {});
        // the TmfView control listener triggers a deferred alignment
        Display.getDefault().syncExec(() -> {});
        // the TmfAlignmentSynchronizer queues the alignment
        SWTBotUtils.waitUntil(synchronizer -> !synchronizer.isBusy() , TmfAlignmentSynchronizer.getInstance(), "Alignment synchronizer is busy");
    }

    private static AbstractSWTBot<?> getAlignmentControl(String viewId) {
        SWTBotView viewBot = fBot.viewById(viewId);
        switch (viewId) {
        case HistogramView.ID:
            return new SWTBotSash(viewBot.bot().widget(WidgetOfType.widgetOfType(Sash.class)));
        case TimeGraphViewStub.ID:
        case TimeChartView.ID:
            return new SWTBotTimeGraph(viewBot.bot().widget(WidgetOfType.widgetOfType(TimeGraphControl.class)));
        default:
            return null;
        }
    }

    private static void testAligned(String masterView, String... slaveViews) {
        final int offset = 50;

        // select alignment controls and get their original alignment positions
        AbstractSWTBot<?> master = getAlignmentControl(masterView);
        int masterOrigin = getAlignmentPosition(master);
        Map<AbstractSWTBot<?>, Integer> slaveMap = new HashMap<>();
        for (String slaveView : slaveViews) {
            AbstractSWTBot<?> slave = getAlignmentControl(slaveView);
            int slaveOrigin = getAlignmentPosition(slave);
            slaveMap.put(slave, slaveOrigin);
        }

        // change master position
        setAlignmentPosition(master, masterOrigin + offset);

        // check resulting alignment positions, slaves follow
        assertEquals(masterOrigin + offset, getAlignmentPosition(master), 2);
        for (Entry<AbstractSWTBot<?>, Integer> slave : slaveMap.entrySet()) {
            assertEquals(slave.getValue() + offset, getAlignmentPosition(slave.getKey()), 2);
        }

        // reset original alignment position
        setAlignmentPosition(master, masterOrigin);
    }

    private static void testNotAligned(String masterView, String... nonSlaveViews) {
        final int offset = 50;

        // select alignment controls and get their original alignment positions
        AbstractSWTBot<?> master = getAlignmentControl(masterView);
        int masterOrigin = getAlignmentPosition(master);
        Map<AbstractSWTBot<?>, Integer> nonSlaveMap = new HashMap<>();
        for (String nonSlaveView : nonSlaveViews) {
            AbstractSWTBot<?> nonSlave = getAlignmentControl(nonSlaveView);
            int nonSlaveOrigin = getAlignmentPosition(nonSlave);
            nonSlaveMap.put(nonSlave, nonSlaveOrigin);
        }

        // change master position
        setAlignmentPosition(master, masterOrigin + offset);

        // check resulting alignment positions, non-slaves do not follow
        assertEquals(masterOrigin + offset, getAlignmentPosition(master), 2);
        for (Entry<AbstractSWTBot<?>, Integer> nonSlave : nonSlaveMap.entrySet()) {
            assertEquals((int) nonSlave.getValue(), getAlignmentPosition(nonSlave.getKey()));
        }

        // reset original alignment position
        setAlignmentPosition(master, masterOrigin);
    }

    private static int getAlignmentPosition(AbstractSWTBot<?> control) {
        if (control instanceof SWTBotSash) {
            Rectangle bounds = ((SWTBotSash) control).getBounds();
            return bounds.x + bounds.width / 2;
        } else if (control instanceof SWTBotTimeGraph) {
            return ((SWTBotTimeGraph) control).getNameSpace();
        }
        return 0;
    }

    private static void setAlignmentPosition(AbstractSWTBot<?> control, int position) {
        if (control instanceof SWTBotSash) {
            SWTBotSash sash = (SWTBotSash) control;
            Rectangle bounds = sash.getBounds();
            Point dst = new Point(position, bounds.y + bounds.height / 2);
            sash.drag(dst);
        } else if (control instanceof SWTBotTimeGraph) {
            ((SWTBotTimeGraph) control).setNameSpace(position);
        }
        // the TmfAlignmentSynchronizer queues the alignment
        SWTBotUtils.waitUntil(synchronizer -> !synchronizer.isBusy() , TmfAlignmentSynchronizer.getInstance(), "Alignment synchronizer is busy");
    }

    /**
     * Histogram, time graph stub and timechart aligned but in different sites
     */
    public static class AlignPerspectiveFactory1 implements IPerspectiveFactory {

        /** The Perspective ID */
        public static final String ID = "org.eclipse.linuxtools.tmf.test.align.1"; //$NON-NLS-1$

        @Override
        public void createInitialLayout(IPageLayout layout) {
            if (layout == null) {
                return;
            }

            // Editor area
            layout.setEditorAreaVisible(true);

            // Editor area
            layout.setEditorAreaVisible(true);

            // Create the top left folder
            IFolderLayout topLeftFolder = layout.createFolder("topLeftFolder", IPageLayout.LEFT, 0.4f, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            topLeftFolder.addView(IPageLayout.ID_PROJECT_EXPLORER);

            // Create the top right folder
            IFolderLayout topRightFolder = layout.createFolder("topRightFolder", IPageLayout.BOTTOM, EDITOR_AREA_RATIO, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            topRightFolder.addView(HistogramView.ID);

            // Create the middle right folder
            IFolderLayout middleRightFolder = layout.createFolder("middleRightFolder", IPageLayout.BOTTOM, 0.50f, "topRightFolder"); //$NON-NLS-1$
            middleRightFolder.addView(TimeGraphViewStub.ID);

            // Create the bottom right folder
            IFolderLayout bottomRightFolder = layout.createFolder("bottomRightFolder", IPageLayout.BOTTOM, 0.65f, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
            bottomRightFolder.addView(TimeChartView.ID);

            // Populate menus, etc
            layout.addPerspectiveShortcut(ID);
            layout.addNewWizardShortcut(NewTmfProjectWizard.ID);
        }

    }

    /**
     * Timechart and Histogram share a site, all views aligned
     */
    public static class AlignPerspectiveFactory2 implements IPerspectiveFactory {

        /** The Perspective ID */
        public static final String ID = "org.eclipse.linuxtools.tmf.test.align.2"; //$NON-NLS-1$

        @Override
        public void createInitialLayout(IPageLayout layout) {
            if (layout == null) {
                return;
            }

            // Editor area
            layout.setEditorAreaVisible(true);

            // Editor area
            layout.setEditorAreaVisible(true);

            // Create the top left folder
            IFolderLayout topLeftFolder = layout.createFolder("topLeftFolder", IPageLayout.LEFT, 0.4f, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            topLeftFolder.addView(IPageLayout.ID_PROJECT_EXPLORER);

            // Create the middle right folder
            IFolderLayout middleRightFolder = layout.createFolder("middleRightFolder", IPageLayout.BOTTOM, EDITOR_AREA_RATIO, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            middleRightFolder.addView(HistogramView.ID);
            middleRightFolder.addView(TimeChartView.ID);

            // Create the bottom right folder
            IFolderLayout bottomRightFolder = layout.createFolder("bottomRightFolder", IPageLayout.BOTTOM, 0.65f, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
            bottomRightFolder.addView(TimeGraphViewStub.ID);

            // Populate menus, etc
            layout.addPerspectiveShortcut(ID);
            layout.addNewWizardShortcut(NewTmfProjectWizard.ID);
        }

    }

    /**
     * Histogram and timechart aligned, time graph stub not aligned
     */
    public static class AlignPerspectiveFactory3 implements IPerspectiveFactory {

        /** The Perspective ID */
        public static final String ID = "org.eclipse.linuxtools.tmf.test.align.3"; //$NON-NLS-1$

        @Override
        public void createInitialLayout(IPageLayout layout) {
            if (layout == null) {
                return;
            }

            // Editor area
            layout.setEditorAreaVisible(true);

            // Editor area
            layout.setEditorAreaVisible(true);

            // Create the top left folder
            IFolderLayout topLeftFolder = layout.createFolder("topLeftFolder", IPageLayout.LEFT, 0.4f, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            topLeftFolder.addView(IPageLayout.ID_PROJECT_EXPLORER);

            IFolderLayout bottomLeftFolder = layout.createFolder("bottomLeftFolder", IPageLayout.BOTTOM, 0.5f, "topLeftFolder"); //$NON-NLS-1$
            bottomLeftFolder.addView(TimeGraphViewStub.ID);

            // Create the middle right folder
            IFolderLayout middleRightFolder = layout.createFolder("middleRightFolder", IPageLayout.BOTTOM, EDITOR_AREA_RATIO, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
            middleRightFolder.addView(HistogramView.ID);

            // Create the bottom right folder
            IFolderLayout bottomRightFolder = layout.createFolder("bottomRightFolder", IPageLayout.BOTTOM, 0.65f, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
            bottomRightFolder.addView(TimeChartView.ID);

            // Populate menus, etc
            layout.addPerspectiveShortcut(ID);
            layout.addNewWizardShortcut(NewTmfProjectWizard.ID);
        }

    }

}

Back to the top