tmf.tests: Add tests for TmfStateSystemModule#isQueryable(long)
authorGeneviève Bastien <gbastien+lttng@versatic.net>
Mon, 4 Apr 2016 20:00:23 +0000 (16:00 -0400)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Mon, 9 May 2016 17:10:08 +0000 (13:10 -0400)
This forces to add behavior to the test state provider so it is possible to
fine tune the event processing by adding a method to process events one at a
time and signal the provider to process the next event.

Change-Id: I999ccd8494c90efce42ba1dc9d59d73b8d018a84
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Reviewed-on: https://git.eclipse.org/r/71153
Reviewed-by: Hudson CI
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
tmf/org.eclipse.tracecompass.tmf.core.tests/plugin.xml
tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/statesystem/StateSystemAnalysisModuleTest.java
tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestStateSystemModule.java
tmf/org.eclipse.tracecompass.tmf.core.tests/stubs/org/eclipse/tracecompass/tmf/tests/stubs/analysis/TestStateSystemProvider.java
tmf/org.eclipse.tracecompass.tmf.core.tests/testfiles/stub_xml_traces/valid/analysis_dependency.xml [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/statesystem/AbstractTmfStateProvider.java

index 771c08f1be264c812881209a8855436abd3dfabd..7e7ec520c5fb5761b5ccff4e93eba9518188b45f 100644 (file)
@@ -54,6 +54,9 @@
          <tracetype
                class="org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub">
          </tracetype>
+         <tracetype
+               class="org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub">
+         </tracetype>
       </module>
       <module
             analysis_module="org.eclipse.tracecompass.tmf.tests.stubs.analysis.TestExperimentAnalysis"
index 55d8a51b3ef409285adf5568adbdbf296e429a09..2e4a0b6dedcfc0ae934ffe10b48619ed3755c9d1 100644 (file)
@@ -1,34 +1,36 @@
 /*******************************************************************************
- * 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;
@@ -49,19 +51,21 @@ public class StateSystemAnalysisModuleTest {
 
     /** 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);
     }
 
     /**
@@ -69,7 +73,7 @@ public class StateSystemAnalysisModuleTest {
      */
     @After
     public void cleanupTraces() {
-        TmfTestTrace.A_TEST_10K.dispose();
+        fTrace.dispose();
     }
 
     /**
@@ -77,11 +81,11 @@ public class StateSystemAnalysisModuleTest {
      */
     @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");
@@ -94,11 +98,11 @@ public class StateSystemAnalysisModuleTest {
      */
     @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());
     }
 
     /**
@@ -107,13 +111,164 @@ public class StateSystemAnalysisModuleTest {
     @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));
+    }
 }
index 2ddc53bab7f407d74c5cf0b2eba549c73794ea30..fa265303d5efd46a2dea5599c88a3e0fd94f008b 100644 (file)
@@ -15,6 +15,7 @@ package org.eclipse.tracecompass.tmf.tests.stubs.analysis;
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
 import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
 
@@ -26,9 +27,17 @@ import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModul
 @NonNullByDefault
 public class TestStateSystemModule extends TmfStateSystemAnalysisModule {
 
+    private @Nullable TestStateSystemProvider fProvider = null;
+    private boolean fThrottleEvents = false;
+
     @Override
     protected ITmfStateProvider createStateProvider() {
-        return new TestStateSystemProvider(checkNotNull(getTrace()));
+
+        TestStateSystemProvider provider = new TestStateSystemProvider(checkNotNull(getTrace()));
+        fProvider = provider;
+        boolean throttle = fThrottleEvents;
+        provider.setThrottling(throttle);
+        return provider;
     }
 
     @Override
@@ -45,4 +54,28 @@ public class TestStateSystemModule extends TmfStateSystemAnalysisModule {
         return StateSystemBackendType.INMEM.name();
     }
 
+    /**
+     * Set whether events are processed one at a time
+     *
+     * @param throttleEvent A value of <code>true</code> will have the events processed one a time instead of adding them all to the queue. To process the next event, one must call the {@link #signalNextEvent()} method. A value of <code>false</code> will return to default behavior.
+     */
+    public void setPerEventSignalling(boolean throttleEvent) {
+        fThrottleEvents = throttleEvent;
+        TestStateSystemProvider provider = fProvider;
+        if (provider != null) {
+            provider.setThrottling(throttleEvent);
+        }
+    }
+
+    /**
+     * Signal for the next event to be processed. This makes sense only if
+     * {@link #setPerEventSignalling(boolean)} method has been set to true
+     */
+    public void signalNextEvent() {
+        TestStateSystemProvider provider = fProvider;
+        if (provider != null) {
+            provider.signalNextEvent();
+        }
+    }
+
 }
index 87292b9d1f4318e524b173eb7e6a6a1bee1dd246..bfc692ac6d7604535b50455d24f122452d98d6b6 100644 (file)
@@ -1,20 +1,22 @@
 /*******************************************************************************
- * 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;
@@ -32,9 +34,59 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
  */
 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
@@ -59,20 +111,72 @@ public class TestStateSystemProvider extends AbstractTmfStateProvider {
     @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();
         }
     }
 
diff --git a/tmf/org.eclipse.tracecompass.tmf.core.tests/testfiles/stub_xml_traces/valid/analysis_dependency.xml b/tmf/org.eclipse.tracecompass.tmf.core.tests/testfiles/stub_xml_traces/valid/analysis_dependency.xml
new file mode 100644 (file)
index 0000000..ab726a6
--- /dev/null
@@ -0,0 +1,27 @@
+<trace>
+<event timestamp="1" name="noise">
+<field name="noise1" value="1" type="int" />
+<field name="noise2" value="3" type="int" />
+</event>
+<event timestamp="5" name="noise">
+<field name="noise1" value="5" type="int" />
+<field name="noise2" value="2" type="int" />
+</event>
+<event timestamp="5" name="noise">
+<field name="noise1" value="11" type="int" />
+<field name="noise2" value="31" type="int" />
+</event>
+<event timestamp="5" name="crucialEvent">
+<field name="crucialInfo" value="I am important" type="string" />
+</event>
+<event timestamp="7" name="crucialEvent">
+<field name="crucialInfo" value="I am also important" type="string" />
+</event>
+<event timestamp="7" name="noise">
+<field name="noise1" value="1" type="int" />
+<field name="noise2" value="3" type="int" />
+</event>
+<event timestamp="10" name="crucialEvent">
+<field name="crucialInfo" value="The end" type="string" />
+</event>
+</trace>
\ No newline at end of file
index 319f620c0a7a0a3232b86def800081b2885628e4..f6cd62006cf0b2d92a5138423895c967f09d4e69 100644 (file)
@@ -123,7 +123,7 @@ public abstract class AbstractTmfStateProvider implements ITmfStateProvider {
     }
 
     @Override
-    public final void processEvent(ITmfEvent event) {
+    public void processEvent(ITmfEvent event) {
         /* Make sure the target state system has been assigned */
         if (!fStateSystemAssigned) {
             Activator.logError("Cannot process event without a target state system"); //$NON-NLS-1$
This page took 0.033145 seconds and 5 git commands to generate.