--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson, EfficiOS Inc. and others
+ *
+ * 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.statesystem.core.tests.backend;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HistoryTreeBackend;
+import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
+import org.junit.After;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test the {@link HistoryTreeBackend} class.
+ *
+ * @author Patrick Tasse
+ * @author Alexandre Montplaisir
+ */
+@RunWith(Parameterized.class)
+public class HistoryTreeBackendTest extends StateHistoryBackendTestBase {
+
+ /** State system ID */
+ protected static final @NonNull String SSID = "test";
+ /** Provider version */
+ protected static final int PROVIDER_VERSION = 0;
+
+ /** Default maximum number of children nodes */
+ protected static final int MAX_CHILDREN = 2;
+ /** Default block size */
+ protected static final int BLOCK_SIZE = 4096;
+
+ /** ReOpen test parameter */
+ protected final boolean fReOpen;
+
+ /** Set of created history tree files */
+ protected Set<File> fHistoryTreeFiles = new HashSet<>();
+ /** Map of backends to history tree file */
+ protected Map<IStateHistoryBackend, File> fBackendMap = new HashMap<>();
+ /** Maximum number of children nodes */
+ protected int fMaxChildren = MAX_CHILDREN;
+ /** Block size */
+ protected int fBlockSize = BLOCK_SIZE;
+
+ /**
+ * @return the test parameters
+ */
+ @Parameters(name = "ReOpen={0}")
+ public static Collection<Boolean> parameters() {
+ return Arrays.asList(Boolean.FALSE, Boolean.TRUE);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param reOpen
+ * True if the backend should be disposed and re-opened as a new
+ * backend from the file, or false to use the backend as-is
+ */
+ public HistoryTreeBackendTest(Boolean reOpen) {
+ fReOpen = reOpen;
+ }
+
+ /**
+ * Test cleanup
+ */
+ @After
+ public void teardown() {
+ for (IStateHistoryBackend backend : fBackendMap.keySet()) {
+ backend.dispose();
+ }
+ for (File historyTreeFile : fHistoryTreeFiles) {
+ historyTreeFile.delete();
+ }
+ }
+
+ @Override
+ protected IStateHistoryBackend getBackendForBuilding(long startTime) throws IOException {
+ File historyTreeFile = File.createTempFile("HistoryTreeBackendTest", ".ht");
+ fHistoryTreeFiles.add(historyTreeFile);
+ HistoryTreeBackend backend = new HistoryTreeBackend(SSID, historyTreeFile, PROVIDER_VERSION, startTime, fBlockSize, fMaxChildren);
+ fBackendMap.put(backend, historyTreeFile);
+ return backend;
+ }
+
+ @Override
+ protected IStateHistoryBackend getBackendForQuerying(IStateHistoryBackend backend) throws IOException {
+ if (!fReOpen) {
+ return backend;
+ }
+ File historyTreeFile = fBackendMap.remove(backend);
+ backend.dispose();
+ HistoryTreeBackend reOpenedBackend = new HistoryTreeBackend(SSID, historyTreeFile, PROVIDER_VERSION);
+ fBackendMap.put(reOpenedBackend, historyTreeFile);
+ return reOpenedBackend;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson, EfficiOS Inc. and others
+ *
+ * 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.statesystem.core.tests.backend;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.interval.TmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.junit.Test;
+
+/**
+ * Abstract class to test implementations of the {@link IStateHistoryBackend} interface.
+ *
+ * @author Patrick Tasse
+ * @author Alexandre Montplaisir
+ */
+public abstract class StateHistoryBackendTestBase {
+
+ /**
+ * Gets the backend to be used for building.
+ *
+ * @param startTime
+ * The start time of the history
+ *
+ * @return The backend to be used for building.
+ * @throws IOException
+ * if an exception occurs
+ */
+ protected abstract IStateHistoryBackend getBackendForBuilding(long startTime) throws IOException;
+
+ /**
+ * Gets the backend to be used for querying. The default implementation
+ * returns the backend that was used for building.
+ * <p>
+ * Only the returned backend should be used after calling this method. The
+ * one sent in parameter might have been disposed.
+ *
+ * @param backend
+ * The backend that was used for building
+ * @return The backend to be used for querying.
+ * @throws IOException
+ * if an exception occurs
+ */
+ @SuppressWarnings("unused")
+ protected IStateHistoryBackend getBackendForQuerying(IStateHistoryBackend backend) throws IOException {
+ return backend;
+ }
+
+ /**
+ * Prepares a backend to be used in tests. The specified intervals will be
+ * inserted in the backend, and then the backend will be closed.
+ *
+ * @param startTime
+ * The start time of the history
+ * @param endTime
+ * The end time at which to close the history
+ * @param intervals
+ * The intervals to insert in the history backend
+ * @return The backend to be used for querying.
+ */
+ protected final IStateHistoryBackend prepareBackend(long startTime, long endTime,
+ List<ITmfStateInterval> intervals) {
+
+ try {
+ IStateHistoryBackend backend = getBackendForBuilding(startTime);
+ insertIntervals(backend, intervals);
+ backend.finishedBuilding(Math.max(endTime, backend.getEndTime()));
+ return getBackendForQuerying(backend);
+ } catch (IOException e) {
+ fail(e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Insert the specified intervals in the provided backend.
+ *
+ * @param backend
+ * The backend to be used
+ * @param intervals
+ * The intervals to insert in the history backend
+ */
+ protected static void insertIntervals(IStateHistoryBackend backend, List<ITmfStateInterval> intervals) {
+ for (ITmfStateInterval interval : intervals) {
+ backend.insertPastState(interval.getStartTime(), interval.getEndTime(), interval.getAttribute(), interval.getStateValue());
+ }
+ }
+
+ /**
+ * Test the integrity of a backend by first building the backend with the
+ * specified intervals, closing it, and then querying at every single
+ * timestamp, making sure that all returned intervals intersect with the
+ * query time. The backend start and end time will be checked.
+ * <p>
+ * If <code>allowNull</code> is false, the specified intervals must cover
+ * the full range for all attributes. The method will make sure that no null
+ * intervals are returned.
+ *
+ * @param startTime
+ * The start time of the history
+ * @param endTime
+ * The end time of the history
+ * @param nbAttr
+ * The number of attributes
+ * @param intervals
+ * The list of intervals to insert
+ * @param allowNull
+ * True if null intervals are allowed, false otherwise
+ * @return The backend to be used for querying.
+ */
+ protected final IStateHistoryBackend buildAndQueryFullRange(long startTime, long endTime, int nbAttr, List<ITmfStateInterval> intervals, boolean allowNull) {
+
+ final IStateHistoryBackend backend = prepareBackend(startTime, endTime, intervals);
+
+ try {
+ /*
+ * Query at every valid time stamp, making sure only the expected
+ * intervals are returned.
+ */
+ for (long t = backend.getStartTime(); t <= backend.getEndTime(); t++) {
+ List<@Nullable ITmfStateInterval> stateInfo = new ArrayList<>(nbAttr);
+ for (int i = 0; i < nbAttr; i++) {
+ stateInfo.add(null);
+ }
+ backend.doQuery(stateInfo, t);
+ for (int attr = 0; attr < stateInfo.size(); attr++) {
+ ITmfStateInterval interval = stateInfo.get(attr);
+ if (!allowNull) {
+ assertTrue("null interval at t=" + t + " for attr=" + attr, interval != null);
+ }
+ if (interval != null) {
+ assertTrue(interval + " does not intersect t=" + t, interval.intersects(t));
+ }
+ }
+ }
+
+ assertEquals(startTime, backend.getStartTime());
+ assertEquals(endTime, backend.getEndTime());
+ } catch (StateSystemDisposedException e) {
+ fail(e.getMessage());
+ return null;
+ }
+ return backend;
+ }
+
+ /**
+ * Test the full query method by filling a small backend with intervals
+ * placed in a "stair-like" fashion, like this:
+ *
+ * <pre>
+ * |x----x----x---x|
+ * |xx----x----x--x|
+ * |x-x----x----x-x|
+ * |x--x----x----xx|
+ * | ... |
+ * </pre>
+ *
+ * and then querying at every single timestamp, making sure all, and only,
+ * the expected intervals are returned.
+ */
+ @Test
+ public void testCascadingIntervals() {
+ final int nbAttr = 10;
+ final long duration = 10;
+ final long startTime = 0;
+ final long endTime = 1000;
+
+ List<ITmfStateInterval> intervals = new ArrayList<>();
+ for (long t = startTime + 1; t <= endTime + duration; t++) {
+ intervals.add(new TmfStateInterval(
+ Math.max(startTime, t - duration),
+ Math.min(endTime, t - 1),
+ (int) t % nbAttr,
+ TmfStateValue.newValueLong(t)));
+ }
+
+ buildAndQueryFullRange(startTime, endTime, nbAttr, intervals, false);
+ }
+
+ /**
+ * Test the full query method by filling a small backend with intervals that
+ * take the full time range, like this:
+ *
+ * <pre>
+ * |x-------------x|
+ * |x-------------x|
+ * |x-------------x|
+ * |x-------------x|
+ * | ... |
+ * </pre>
+ *
+ * and then querying at every single timestamp, making sure all, and only,
+ * the expected intervals are returned.
+ */
+ @Test
+ public void testFullIntervals() {
+ final int nbAttr = 1000;
+ final long startTime = 0;
+ final long endTime = 1000;
+
+ List<ITmfStateInterval> intervals = new ArrayList<>();
+ for (int attr = 0; attr < nbAttr; attr++) {
+ intervals.add(new TmfStateInterval(
+ startTime,
+ endTime,
+ attr,
+ TmfStateValue.newValueLong(attr)));
+ }
+
+ buildAndQueryFullRange(startTime, endTime, nbAttr, intervals, false);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson, EfficiOS Inc. and others
+ *
+ * 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.statesystem.core.tests.backend;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.ThreadedHistoryTreeBackend;
+import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
+
+/**
+ * Test the {@link ThreadedHistoryTreeBackend} class.
+ *
+ * @author Patrick Tasse
+ * @author Alexandre Montplaisir
+ */
+public class ThreadedHistoryTreeBackendTest extends HistoryTreeBackendTest {
+
+ private static final int QUEUE_SIZE = 10;
+
+ /**
+ * Constructor
+ *
+ * @param reOpen
+ * True if the backend should be disposed and re-opened as a new
+ * backend from the file, or false to use the backend as-is
+ */
+ public ThreadedHistoryTreeBackendTest(Boolean reOpen) {
+ super(reOpen);
+ }
+
+ @Override
+ protected IStateHistoryBackend getBackendForBuilding(long startTime) throws IOException {
+ File historyTreeFile = File.createTempFile("ThreadedHistoryTreeBackendTest", ".ht");
+ fHistoryTreeFiles.add(historyTreeFile);
+ ThreadedHistoryTreeBackend backend = new ThreadedHistoryTreeBackend(SSID, historyTreeFile, PROVIDER_VERSION, startTime, QUEUE_SIZE, fBlockSize, fMaxChildren);
+ fBackendMap.put(backend, historyTreeFile);
+ return backend;
+ }
+}