blob: f1e9659ce8d6905057f8a972bb5693af2a35270f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.statesystem.core.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
/**
* Test the 2D State System queries
*
* @author Loïc Prieur-Drevon
*/
public class StateSystem2DTest {
private static final long START_TIME = 50L;
private static final @NonNull String STRING_ATTRIBUTE = "String";
private static final @NonNull String INTEGER_ATTRIBUTE = "Integer";
private ITmfStateSystemBuilder fStateSystem;
/**
* Build a small state history tree
*
* @throws IOException
* If the state system file could not be created
*/
@Before
public void setupStateSystem() throws IOException {
IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendNewFile("test",
NonNullUtils.checkNotNull(File.createTempFile("2Dtest", "ht")), 0, START_TIME, 0);
fStateSystem = StateSystemFactory.newStateSystem(NonNullUtils.checkNotNull(backend));
int stringQuark = fStateSystem.getQuarkAbsoluteAndAdd(STRING_ATTRIBUTE);
int integerQuark = fStateSystem.getQuarkAbsoluteAndAdd(INTEGER_ATTRIBUTE);
fStateSystem.modifyAttribute(60L, "String1", stringQuark);
fStateSystem.modifyAttribute(70L, 0, integerQuark);
fStateSystem.modifyAttribute(80L, 1, integerQuark);
fStateSystem.modifyAttribute(90L, "String2", stringQuark);
fStateSystem.modifyAttribute(100L, 2, integerQuark);
fStateSystem.modifyAttribute(110L, 3, integerQuark);
fStateSystem.modifyAttribute(130L, "String3", stringQuark);
fStateSystem.modifyAttribute(140L, "String4", stringQuark);
fStateSystem.modifyAttribute(160L, 4, integerQuark);
fStateSystem.closeHistory(200L);
}
/**
* Clean-up
*/
@After
public void tearDown() {
fStateSystem.dispose();
fStateSystem.removeFiles();
}
private static void testContinuous(Iterable<ITmfStateInterval> iterable, Collection<Integer> quarks, long start, long end, int totalCount) {
Multimap<Integer, ITmfStateInterval> treeMap = TreeMultimap.create(Comparator.naturalOrder(),
Comparator.comparing(ITmfStateInterval::getStartTime));
iterable.forEach(interval -> assertTrue("Interval: " + interval + " was already returned: " + treeMap,
treeMap.put(interval.getAttribute(), interval)));
assertEquals("Wrong number of intervals returned", totalCount, treeMap.size());
assertEquals("There should only be as many Sets of intervals as quarks",
quarks.size(), treeMap.keySet().size());
for (Integer quark : quarks) {
Collection<ITmfStateInterval> orderedSet = treeMap.get(quark);
assertFalse("There should be intervals for quark: " + quark, orderedSet.isEmpty());
ITmfStateInterval previous = null;
for (ITmfStateInterval interval : orderedSet) {
if (previous == null) {
assertTrue("The first interval: " + interval + "should intersect start: " + start, interval.intersects(start));
} else {
assertEquals("Current interval: " + interval + " should have been contiguous to the previous one " + previous,
previous.getEndTime() + 1, interval.getStartTime());
}
previous = interval;
}
assertNotNull("There should have been at least one interval for quark " + quark, previous);
assertTrue("last interval: " + previous + " should intersect end " + end, previous.intersects(end));
}
}
/**
* Test the continuous 2D query method.
*
* @throws AttributeNotFoundException
* if the requested attribute simply did not exist in the system.
* @throws StateSystemDisposedException
* If the query is sent after the state system has been disposed
* @throws TimeRangeException
* If the smallest time is before the state system start time.
* @throws IndexOutOfBoundsException
* If the smallest attribute is <0 or if the largest is >= to the
* number of attributes.
*/
@Test
public void testContinuous2DQuery() throws AttributeNotFoundException, IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
long end = ss.getCurrentEndTime();
/* Make sure all and only the String intervals are returned */
int stringQuark = fStateSystem.getQuarkAbsolute(STRING_ATTRIBUTE);
Iterable<ITmfStateInterval> iterable = ss.query2D(Collections.singleton(stringQuark), START_TIME, end);
testContinuous(iterable, Collections.singleton(stringQuark), START_TIME, end, 5);
/* Make sure all and only the Integer intervals are returned */
int integerQuark = fStateSystem.getQuarkAbsolute(INTEGER_ATTRIBUTE);
iterable = ss.query2D(Collections.singleton(integerQuark), START_TIME, end);
testContinuous(iterable, Collections.singleton(integerQuark), START_TIME, end, 6);
/* Make sure all intervals are returned */
Collection<Integer> quarks = ImmutableList.of(stringQuark, integerQuark);
iterable = ss.query2D(quarks, START_TIME, end);
testContinuous(iterable, quarks, START_TIME, end, 11);
}
private static void testDiscrete(Iterable<ITmfStateInterval> iterable, Collection<Integer> quarks, Collection<Long> times, int totalCount) {
Set<ITmfStateInterval> set = new HashSet<>();
int countTimeStamps = 0;
for (ITmfStateInterval interval : iterable) {
assertTrue(quarks.contains(interval.getAttribute()));
assertTrue("interval: " + interval + " was returned twice", set.add(interval));
int timeStamps = (int) times.stream().filter(interval::intersects).count();
assertTrue("interval: " + interval + " does not intersect any time stamp: " + times, timeStamps > 0);
countTimeStamps += timeStamps;
}
assertEquals("incorrect number of intervals returned", totalCount, set.size());
assertEquals("All the queried time stamps were not covered", times.size() * quarks.size(), countTimeStamps);
}
/**
* Test the discrete 2D query method.
*
* @throws AttributeNotFoundException
* if the requested attribute simply did not exist in the system.
* @throws StateSystemDisposedException
* If the query is sent after the state system has been disposed
* @throws TimeRangeException
* If the smallest time is before the state system start time.
* @throws IndexOutOfBoundsException
* If the smallest attribute is <0 or if the largest is >= to the
* number of attributes.
*/
@Test
public void testDiscrete2DQuery() throws AttributeNotFoundException,
IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
long end = ss.getCurrentEndTime();
Collection<Long> times = StateSystemUtils.getTimes(START_TIME, end, 30L);
assertEquals(6, times.size());
assertTrue(Ordering.natural().isStrictlyOrdered(times));
/* Make sure all and only the String intervals are returned */
int stringQuark = fStateSystem.getQuarkAbsolute(STRING_ATTRIBUTE);
Iterable<ITmfStateInterval> iterable = ss.query2D(Collections.singleton(stringQuark), times);
testDiscrete(iterable, Collections.singleton(stringQuark), times, 4);
/* Make sure all and only the Integer intervals are returned */
int integerQuark = fStateSystem.getQuarkAbsolute(INTEGER_ATTRIBUTE);
iterable = ss.query2D(Collections.singleton(integerQuark), times);
testDiscrete(iterable, Collections.singleton(integerQuark), times, 4);
/* Make sure all intervals are returned */
Collection<Integer> quarks = ImmutableList.of(stringQuark, integerQuark);
iterable = ss.query2D(quarks, times);
testDiscrete(iterable, quarks, times, 8);
}
/**
* Test index out of bound queries
*
* @throws StateSystemDisposedException
* ss was closed
* @throws TimeRangeException
* time was out of range
* @throws IndexOutOfBoundsException
* queried an attribute that was out of bounds
*/
@Test(expected = IndexOutOfBoundsException.class)
public void testIOOB2DQuery() throws IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
Collection<Long> times = Collections.singleton(77L);
int stringQuark = Integer.MAX_VALUE;
ss.query2D(Collections.singleton(stringQuark), times);
}
/**
* Test a too low time range exception on continuous queries
*
* @throws StateSystemDisposedException
* ss was closed
* @throws TimeRangeException
* time was out of range
* @throws IndexOutOfBoundsException
* queried an attribute that was out of bounds
*/
@Test(expected = TimeRangeException.class)
public void testTimeRangeException2DContinous() throws IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
ss.query2D(Collections.singleton(0), 0L, 77L);
}
/**
* Test a too low time range exception on discrete queries
*
* @throws StateSystemDisposedException
* ss was closed
* @throws TimeRangeException
* time was out of range
* @throws IndexOutOfBoundsException
* queried an attribute that was out of bounds
*/
@Test(expected = TimeRangeException.class)
public void testTimeRangeException2DDiscrete() throws IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
ss.query2D(Collections.singleton(0), Collections.singleton(Long.MIN_VALUE));
}
/**
* Test Empty queries
*
* @throws StateSystemDisposedException
* ss was closed
* @throws TimeRangeException
* time was out of range
* @throws IndexOutOfBoundsException
* queried an attribute that was out of bounds
*/
@Test
public void testEmpty2DQuery() throws IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
/* Test on a discrete query */
Iterable<ITmfStateInterval> iterable = ss.query2D(Collections.emptyList(), Collections.singleton(77L));
assertNotNull(iterable);
assertTrue(Iterables.isEmpty(iterable));
/* Test on an empty time sample */
iterable = ss.query2D(Collections.singleton(0), Collections.emptyList());
assertNotNull(iterable);
assertTrue(Iterables.isEmpty(iterable));
/* Test on a continuous query */
iterable = ss.query2D(Collections.emptyList(), 77L, 78L);
assertNotNull(iterable);
assertTrue(Iterables.isEmpty(iterable));
}
/**
* Test the continuous 2D query method when start time > end time. Since
* this state system only has one node, it does not compare behavior between
* reverse and not reverse queries.
*
* @throws AttributeNotFoundException
* if the requested attribute simply did not exist in the
* system.
* @throws StateSystemDisposedException
* If the query is sent after the state system has been disposed
* @throws TimeRangeException
* If the smallest time is before the state system start time.
* @throws IndexOutOfBoundsException
* If the smallest attribute is <0 or if the largest is >= to
* the number of attributes.
*/
@Test
public void testReverse2DQuery() throws AttributeNotFoundException, IndexOutOfBoundsException, TimeRangeException, StateSystemDisposedException {
ITmfStateSystem ss = fStateSystem;
assertNotNull(ss);
long end = ss.getCurrentEndTime();
/* Make sure all and only the String intervals are returned */
int stringQuark = fStateSystem.getQuarkAbsolute(STRING_ATTRIBUTE);
Iterable<ITmfStateInterval> iterable = ss.query2D(Collections.singleton(stringQuark), end, START_TIME);
testContinuous(iterable, Collections.singleton(stringQuark), START_TIME, end, 5);
/* Make sure all and only the Integer intervals are returned */
int integerQuark = fStateSystem.getQuarkAbsolute(INTEGER_ATTRIBUTE);
iterable = ss.query2D(Collections.singleton(integerQuark), end, START_TIME);
testContinuous(iterable, Collections.singleton(integerQuark), START_TIME, end, 6);
/* Make sure all intervals are returned */
Collection<Integer> quarks = ImmutableList.of(stringQuark, integerQuark);
iterable = ss.query2D(quarks, end, START_TIME);
testContinuous(iterable, quarks, START_TIME, end, 11);
}
}