/*******************************************************************************
- * Copyright (c) 2013, 2014 École Polytechnique de Montréal
+ * Copyright (c) 2013, 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 v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Geneviève Bastien - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.tests.statesystem;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
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.util.Map;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
-import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
import org.eclipse.tracecompass.tmf.core.statesystem.Messages;
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
-import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestTrace;
+import org.eclipse.tracecompass.tmf.core.tests.TmfCoreTestPlugin;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.tests.stubs.analysis.TestStateSystemModule;
-import org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub;
+import org.eclipse.tracecompass.tmf.tests.stubs.analysis.TestStateSystemProvider;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
/** ID of the test state system analysis module */
public static final String MODULE_SS = "org.eclipse.linuxtools.tmf.core.tests.analysis.sstest";
+ private static final String XML_TRACE = "testfiles/stub_xml_traces/valid/analysis_dependency.xml";
- private TmfStateSystemAnalysisModule module;
+ private TestStateSystemModule fModule;
+ private ITmfTrace fTrace;
/**
* Setup test trace
*/
@Before
public void setupTraces() {
- TmfTraceStub trace = (TmfTraceStub) TmfTestTrace.A_TEST_10K.getTrace();
- TmfSignalManager.deregister(trace);
+ TmfXmlTraceStub trace = TmfXmlTraceStub.setupTrace(TmfCoreTestPlugin.getAbsoluteFilePath(XML_TRACE));
trace.traceOpened(new TmfTraceOpenedSignal(this, trace, null));
+ fTrace = trace;
- module = (TmfStateSystemAnalysisModule) trace.getAnalysisModule(MODULE_SS);
+ fModule = (TestStateSystemModule) trace.getAnalysisModule(MODULE_SS);
}
/**
*/
@After
public void cleanupTraces() {
- TmfTestTrace.A_TEST_10K.dispose();
+ fTrace.dispose();
}
/**
*/
@Test
public void testSsModule() {
- ITmfStateSystem ss = module.getStateSystem();
+ ITmfStateSystem ss = fModule.getStateSystem();
assertNull(ss);
- module.schedule();
- if (module.waitForCompletion()) {
- ss = module.getStateSystem();
+ fModule.schedule();
+ if (fModule.waitForCompletion()) {
+ ss = fModule.getStateSystem();
assertNotNull(ss);
} else {
fail("Module did not complete properly");
*/
@Test
public void testInitialization() {
- assertNull(module.getStateSystem());
- module.schedule();
+ assertNull(fModule.getStateSystem());
+ fModule.schedule();
- assertTrue("Initialization succeeded", module.waitForInitialization());
- assertNotNull(module.getStateSystem());
+ assertTrue("Initialization succeeded", fModule.waitForInitialization());
+ assertNotNull(fModule.getStateSystem());
}
/**
@Test
public void testProperties() {
- assertTrue(module instanceof TestStateSystemModule);
- TestStateSystemModule mod = (TestStateSystemModule) module;
-
/* The stub state system has in mem backend 2 properties */
- Map<String, String> properties = mod.getProperties();
- assertEquals(mod.getBackendName(), properties.get(Messages.TmfStateSystemAnalysisModule_PropertiesBackend));
- assertEquals(mod.getId(), properties.get(org.eclipse.tracecompass.tmf.core.analysis.Messages.TmfAbstractAnalysisModule_LabelId));
+ Map<String, String> properties = fModule.getProperties();
+ assertEquals(fModule.getBackendName(), properties.get(Messages.TmfStateSystemAnalysisModule_PropertiesBackend));
+ assertEquals(fModule.getId(), properties.get(org.eclipse.tracecompass.tmf.core.analysis.Messages.TmfAbstractAnalysisModule_LabelId));
+ }
+
+ private static final String CRUCIAL_EVENT = "crucialEvent";
+ private static final String CRUCIAL_FIELD = "crucialInfo";
+
+ private static void setupDependentAnalysisHandler(CyclicBarrier barrier) {
+ TestStateSystemProvider.setEventHandler((ss, event) -> {
+ try {
+ /* Wait before processing the current event */
+ barrier.await();
+ if (event.getName().equals(CRUCIAL_EVENT)) {
+ String crucialInfo = (String) event.getContent().getField(CRUCIAL_FIELD).getValue();
+ int quark = ss.getQuarkAbsoluteAndAdd(CRUCIAL_FIELD);
+ try {
+ ss.modifyAttribute(event.getTimestamp().toNanos(), TmfStateValue.newValueString(crucialInfo), quark);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+ /* Wait before processing the next event */
+ barrier.await();
+ return true;
+ } catch (InterruptedException | BrokenBarrierException e1) {
+ return false;
+ }
+
+ });
+ }
+
+ /**
+ * Test the {@link TmfStateSystemAnalysisModule#isQueryable(long)} method
+ */
+ @Test
+ public void testIsQueryable() {
+
+ CyclicBarrier barrier = new CyclicBarrier(2);
+ setupDependentAnalysisHandler(barrier);
+
+ TestStateSystemModule module = fModule;
+ assertNotNull(module);
+
+ /* Module is not started, it should be queriable */
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertTrue(module.isQueryable(7));
+ assertTrue(module.isQueryable(10));
+
+ module.schedule();
+
+ assertTrue(module.waitForInitialization());
+
+ assertFalse(module.isQueryable(1));
+
+ try {
+ /* 2 waits for a barrier for one event */
+ // event 1
+ barrier.await();
+ barrier.await();
+ // event 2
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertFalse(module.isQueryable(5));
+ barrier.await();
+ // event 3
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertFalse(module.isQueryable(5));
+ barrier.await();
+ // event 4
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertFalse(module.isQueryable(5));
+ barrier.await();
+ // event 5
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertFalse(module.isQueryable(7));
+ barrier.await();
+ // event 6
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertFalse(module.isQueryable(7));
+ barrier.await();
+ // event 7
+ barrier.await();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertTrue(module.isQueryable(7));
+ assertFalse(module.isQueryable(10));
+ barrier.await();
+
+ fModule.waitForCompletion();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertTrue(module.isQueryable(7));
+ assertTrue(module.isQueryable(10));
+
+ // Should return true only if later than trace time
+ assertTrue(module.isQueryable(100));
+
+ } catch (InterruptedException | BrokenBarrierException e1) {
+ fail(e1.getMessage());
+ fModule.cancel();
+ } finally {
+ TestStateSystemProvider.setEventHandler(null);
+ }
}
+ /**
+ * Test the {@link TmfStateSystemAnalysisModule#isQueryable(long)} method
+ * when the analysis is cancelled
+ */
+ @Test
+ public void testIsQueryableCancel() {
+
+ TestStateSystemModule module = fModule;
+ assertNotNull(module);
+ /* Set the queue to 1 to limit the number of events buffered */
+ module.setPerEventSignalling(true);
+
+ /* Module is not started, it should be queriable */
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertTrue(module.isQueryable(7));
+ assertTrue(module.isQueryable(10));
+
+ fModule.schedule();
+
+ assertTrue(module.waitForInitialization());
+
+ assertFalse(module.isQueryable(1));
+
+ // Process 2 events, then cancel
+ module.signalNextEvent();
+ module.signalNextEvent();
+ module.cancel();
+ module.setPerEventSignalling(false);
+
+ fModule.waitForCompletion();
+ assertTrue(module.isQueryable(1));
+ assertTrue(module.isQueryable(4));
+ assertTrue(module.isQueryable(5));
+ assertTrue(module.isQueryable(7));
+ assertTrue(module.isQueryable(10));
+ }
}
/*******************************************************************************
- * Copyright (c) 2013, 2015 École Polytechnique de Montréal
+ * Copyright (c) 2013, 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 v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Geneviève Bastien - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.tmf.tests.stubs.analysis;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
*/
public class TestStateSystemProvider extends AbstractTmfStateProvider {
+ /**
+ * This interface allows unit tests to provide only the event handling part
+ * of the state provider, without having to extend the analysis and the
+ * classes
+ */
+ @FunctionalInterface
+ public static interface TestStateProviderHandler {
+ /**
+ * Handles the event
+ *
+ * @param ss
+ * The state system builder
+ * @param event
+ * The event to handler
+ * @return <code>true</code> if everything went fine, or <code>false</code> to cancel
+ */
+ boolean eventHandle(@NonNull ITmfStateSystemBuilder ss, ITmfEvent event);
+ }
+
private static final int VERSION = 1;
- private final String fString = "[]";
- private int fCount = 0;
+ private static final String fString = "[]";
+ private static int fCount = 0;
+ private static final @NonNull TestStateProviderHandler DEFAULT_HANDLER = (ss, event) -> {
+ /* Just need something to fill the state system */
+ if (fString.equals(event.getContent().getValue())) {
+ try {
+ int quarkId = ss.getQuarkAbsoluteAndAdd("String");
+ int quark = ss.getQuarkRelativeAndAdd(quarkId, fString);
+ ss.modifyAttribute(event.getTimestamp().getValue(), TmfStateValue.newValueInt(fCount++), quark);
+ } catch (TimeRangeException | AttributeNotFoundException | StateValueTypeException e) {
+
+ }
+ }
+ return true;
+ };
+ private static @NonNull TestStateProviderHandler sfHandler = DEFAULT_HANDLER;
+
+ /**
+ * Set the event handler for the state provider
+ *
+ * @param handler
+ * The class containing the event handler for this state provider
+ */
+ public static void setEventHandler(TestStateProviderHandler handler) {
+ if (handler == null) {
+ sfHandler = DEFAULT_HANDLER;
+ return;
+ }
+ sfHandler = handler;
+ }
+
+ private final Lock fLock = new ReentrantLock();
+ private @Nullable Condition fNextEventSignal = null;
/**
* Constructor
@Override
protected void eventHandle(ITmfEvent event) {
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
+ sfHandler.eventHandle(ss, event);
+ }
- /* Just need something to fill the state system */
- if (fString.equals(event.getContent().getValue())) {
- try {
- int quarkId = ss.getQuarkAbsoluteAndAdd("String");
- int quark = ss.getQuarkRelativeAndAdd(quarkId, fString);
- ss.modifyAttribute(event.getTimestamp().getValue(), TmfStateValue.newValueInt(fCount++), quark);
- } catch (TimeRangeException e) {
- } catch (AttributeNotFoundException e) {
- } catch (StateValueTypeException e) {
+ @Override
+ public void processEvent(@NonNull ITmfEvent event) {
+ fLock.lock();
+ try {
+ Condition cond = fNextEventSignal;
+ if (cond != null) {
+ cond.await();
+ }
+ } catch (InterruptedException e) {
+
+ } finally {
+ super.processEvent(event);
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Set the processing of event to be one event at a time instead of the
+ * default behavior. It will block until the next call to
+ * {@link #signalNextEvent()} method call.
+ *
+ * @param throttleEvent
+ * Whether to wait for a signal to process the next event
+ */
+ public void setThrottling(boolean throttleEvent) {
+ fLock.lock();
+ try {
+ if (throttleEvent) {
+ Condition cond = fNextEventSignal;
+ // If called for the first time, create a condition
+ if (cond == null) {
+ cond = fLock.newCondition();
+ fNextEventSignal = cond;
+ }
+
+ } else {
+ Condition cond = fNextEventSignal;
+ if (cond != null) {
+ fNextEventSignal = null;
+ cond.signalAll();
+ }
+ }
+ } finally {
+ fLock.unlock();
+ }
+
+ }
+ /**
+ * Signal for the next event to be processed. Calling this method makes
+ * sense only if {@link #setThrottling(boolean)} has been set to true
+ */
+ public void signalNextEvent() {
+ fLock.lock();
+ try {
+ Condition cond = fNextEventSignal;
+ if (cond != null) {
+ cond.signalAll();
}
+ } finally {
+ fLock.unlock();
}
}