/******************************************************************************* * 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 *******************************************************************************/ 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.io.File; 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.statesystem.core.statevalue.TmfStateValue; import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; 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.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.analysis.TestStateSystemProvider; import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub; import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStubNs; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.rules.Timeout; /** * Test the {@link TmfStateSystemAnalysisModule} class * * @author Geneviève Bastien */ public class StateSystemAnalysisModuleTest { /** Time-out tests after 1 minute. */ @Rule public TestRule globalTimeout = new Timeout(1, TimeUnit.MINUTES); /** 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 TestStateSystemModule fModule; private ITmfTrace fTrace; /** * Setup test trace */ @Before public void setupTraces() { TmfXmlTraceStub trace = TmfXmlTraceStubNs.setupTrace(TmfCoreTestPlugin.getAbsoluteFilePath(XML_TRACE)); trace.traceOpened(new TmfTraceOpenedSignal(this, trace, null)); fTrace = trace; fModule = (TestStateSystemModule) trace.getAnalysisModule(MODULE_SS); } /** * Some tests use traces, let's clean them here */ @After public void cleanupTraces() { fTrace.dispose(); } /** * Test the state system module execution and result */ @Test public void testSsModule() { ITmfStateSystem ss = fModule.getStateSystem(); assertNull(ss); fModule.schedule(); if (fModule.waitForCompletion()) { ss = fModule.getStateSystem(); assertNotNull(ss); } else { fail("Module did not complete properly"); } } /** * Make sure that the state system is initialized after calling * {@link TmfStateSystemAnalysisModule#waitForInitialization()}. */ @Test public void testInitialization() { assertNull(fModule.getStateSystem()); fModule.schedule(); assertTrue("Initialization succeeded", fModule.waitForInitialization()); assertNotNull(fModule.getStateSystem()); } /** * Test that helper returns the right properties */ @Test public void testProperties() { /* The stub state system has in mem backend 2 properties */ 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 */ @Ignore("Hangs very often") @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)); } /** * Test that an analysis with full backend is re-read correctly * @throws TmfAnalysisException Propagates exceptions */ @Test public void testReReadFullAnalysis() throws TmfAnalysisException { TestStateSystemModule module = new TestStateSystemModule(true); TestStateSystemModule module2 = new TestStateSystemModule(true); try { ITmfTrace trace = fTrace; assertNotNull(trace); module.setTrace(trace); module2.setTrace(trace); // Execute the first module module.schedule(); assertTrue(module.waitForCompletion()); // Execute the second module, it should read the state system file File ssFile = module2.getSsFile(); assertNotNull(ssFile); assertTrue(ssFile.exists()); module2.schedule(); assertTrue(module2.waitForCompletion()); } finally { module.dispose(); module2.dispose(); } } /** * Test that an analysis whose event request throws an exception is failed * correctly * * @throws TmfAnalysisException * Propagates exceptions */ @Test public void testRequestFailure() throws TmfAnalysisException { TestStateSystemModule module = new TestStateSystemModule(); module.setRequestAction(e -> { throw new IllegalArgumentException("This exception is desired and part of the test"); }); try { ITmfTrace trace = fTrace; assertNotNull(trace); module.setTrace(trace); // Execute the module that should throw the exception module.schedule(); assertFalse(module.waitForCompletion()); } finally { module.dispose(); } } }