blob: bca503b6b7709fb7a68c4348f733aca0665319aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 É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.tmf.analysis.xml.core.tests.module;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.compile.AnalysisCompilationData;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.compile.TmfXmlOutputEntryCu;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.compile.TmfXmlTimeGraphViewCu;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlAnalysisModuleSource;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.output.DataDrivenOutputEntry;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.output.DataDrivenPresentationState;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.output.DataDrivenTimeGraphDataProvider;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.output.DataDrivenTimeGraphProviderFactory;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.output.XmlDataProviderManager;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlStrings;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlUtils;
import org.eclipse.tracecompass.tmf.analysis.xml.core.tests.common.TmfXmlTestFiles;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphDataProvider;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphRowModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphState;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphEntryModel;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphModel;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
import org.eclipse.tracecompass.tmf.core.response.ITmfResponse;
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Element;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* Test the XML time graph data provider with a simple test
*
* @author Geneviève Bastien
*/
public class XmlTimeGraphDataProviderTest {
private static final @NonNull String TEST_TRACE = "test_traces/testTrace4.xml";
private static final @NonNull String ANALYSIS_ID = "xml.core.tests.simple.pattern";
private static final @NonNull String TIME_GRAPH_VIEW_ID = "xml.core.tests.simple.pattern.timegraph";
private static final @NonNull String TIME_GRAPH_VIEW_ID2 = "xml.core.tests.simple.pattern.timegraph2";
private static final @NonNull IProgressMonitor MONITOR = new NullProgressMonitor();
/**
* Load the XML files for the current test
*/
@Before
public void setUp() {
XmlUtils.addXmlFile(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile());
XmlUtils.addXmlFile(TmfXmlTestFiles.DATA_PROVIDER_SIMPLE_FILE.getFile());
XmlAnalysisModuleSource.notifyModuleChange();
}
/**
* Clean
*/
public void cleanUp() {
XmlUtils.deleteFiles(ImmutableList.of(
TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName(),
TmfXmlTestFiles.DATA_PROVIDER_SIMPLE_FILE.getFile().getName()));
XmlAnalysisModuleSource.notifyModuleChange();
}
private ITmfTrace getTrace() {
// Initialize the trace and module
ITmfTrace trace = XmlUtilsTest.initializeTrace(TEST_TRACE);
TmfTraceOpenedSignal signal = new TmfTraceOpenedSignal(this, trace, null);
((TmfTrace) trace).traceOpened(signal);
// The data provider manager uses opened traces from the manager
TmfTraceManager.getInstance().traceOpened(signal);
return trace;
}
private static void runModule(ITmfTrace trace) {
IAnalysisModule module = trace.getAnalysisModule(ANALYSIS_ID);
assertNotNull(module);
module.schedule();
assertTrue(module.waitForCompletion());
}
/**
* Test getting the XML data provider for one trace, with an analysis that
* applies to a trace
*
* @throws IOException
* Exception thrown by analyses
*/
@Test
public void testTwoLevels() throws IOException {
ITmfTrace trace = getTrace();
assertNotNull(trace);
try {
runModule(trace);
// Get the view element from the file
Element viewElement = TmfXmlUtils.getElementInFile(TmfXmlTestFiles.DATA_PROVIDER_SIMPLE_FILE.getPath().toOSString(), TmfXmlStrings.TIME_GRAPH_VIEW, TIME_GRAPH_VIEW_ID);
assertNotNull(viewElement);
ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> timeGraphProvider = XmlDataProviderManager.getInstance().getTimeGraphProvider(trace, viewElement);
assertNotNull(timeGraphProvider);
List<String> expectedStrings = Files.readAllLines(Paths.get("test_traces/simple_dataprovider/expectedTimeGraphTree"));
Map<Long, String> tree = assertAndGetTree(timeGraphProvider, trace, expectedStrings);
expectedStrings = Files.readAllLines(Paths.get("test_traces/simple_dataprovider/expectedTimeGraphRows"));
assertRows(timeGraphProvider, tree, expectedStrings);
} finally {
trace.dispose();
TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace));
}
}
private static void assertRows(ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> provider, Map<Long, String> tree, List<String> expectedStrings) {
TmfModelResponse<@NonNull TimeGraphModel> rowResponse = provider.fetchRowModel(FetchParametersUtils.selectionTimeQueryToMap(new SelectionTimeQueryFilter(1, 20, 20, tree.keySet())), null);
assertNotNull(rowResponse);
assertEquals(ITmfResponse.Status.COMPLETED, rowResponse.getStatus());
TimeGraphModel timeGraphModel = rowResponse.getModel();
assertNotNull(timeGraphModel);
List<@NonNull ITimeGraphRowModel> rowModel = timeGraphModel.getRows();
// ensure row order
rowModel.sort(Comparator.comparingLong(ITimeGraphRowModel::getEntryID));
assertEquals(expectedStrings.size(), rowModel.size());
for (int i = 0; i < expectedStrings.size(); i++) {
String expectedString = expectedStrings.get(i);
String[] split = expectedString.split(":");
ITimeGraphRowModel row = rowModel.get(i);
assertEquals(split[0], tree.get(row.getEntryID()));
assertEqualsStates(split[0], split[1], row.getStates());
}
}
private static void assertEqualsStates(String name, String string, @NonNull List<@NonNull ITimeGraphState> states) {
String[] stringStates = string.split(",");
for (int i = 0; i < stringStates.length / 4; i++) {
ITimeGraphState state = states.get(i);
assertNotNull("State " + i + " for " + name, state);
assertEquals("Start time of state " + i + " for " + name, Long.parseLong(stringStates[i * 4]), state.getStartTime());
assertEquals("Duration of state " + i + " for " + name, Long.parseLong(stringStates[i * 4 + 1]), state.getDuration());
assertEquals("Value of state " + i + " for " + name, Long.parseLong(stringStates[i * 4 + 2]), state.getValue());
assertEquals("Label of state " + i + " for " + name, stringStates[i * 4 + 3], String.valueOf(state.getLabel()));
}
assertEquals("Expected number of states", stringStates.length / 4, states.size());
}
private static Map<Long, String> assertAndGetTree(ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> timeGraphProvider, ITmfTrace trace, List<String> expectedStrings) {
TmfModelResponse<@NonNull TmfTreeModel<@NonNull TimeGraphEntryModel>> treeResponse = timeGraphProvider.fetchTree(FetchParametersUtils.timeQueryToMap(new TimeQueryFilter(0, Long.MAX_VALUE, 2)), MONITOR);
assertNotNull(treeResponse);
assertEquals(ITmfResponse.Status.COMPLETED, treeResponse.getStatus());
TmfTreeModel<@NonNull TimeGraphEntryModel> treeModel = treeResponse.getModel();
assertNotNull(treeModel);
List<@NonNull TimeGraphEntryModel> xmlEntries = treeModel.getEntries();
Collections.sort(xmlEntries, Comparator.comparingLong(TimeGraphEntryModel::getId));
Map<Long, String> map = new HashMap<>();
for (int i = 0; i < expectedStrings.size(); i++) {
String expectedString = expectedStrings.get(i);
assertTrue("actual entry present at " + i + ": " + expectedString, xmlEntries.size() > i);
String[] split = expectedString.split(",");
TimeGraphEntryModel xmlTgEntry = xmlEntries.get(i);
assertEquals("Checking entry name at " + i, split[0], xmlTgEntry.getName());
assertEquals("Checking entry start time at " + i, Long.parseLong(split[1]), xmlTgEntry.getStartTime());
assertEquals("Checking entry end time at " + i, Long.parseLong(split[2]), xmlTgEntry.getEndTime());
// Check the parent
long parentId = xmlTgEntry.getParentId();
if (parentId < 0) {
assertEquals("Checking empty parent at " + i, split[3], "null");
} else {
String parentName = map.get(parentId);
assertEquals("Checking parent at " + i, split[3], parentName);
}
map.put(xmlTgEntry.getId(), xmlTgEntry.getName());
}
assertEquals("Extra actual entries", expectedStrings.size(), xmlEntries.size());
return map;
}
/**
* Test getting the XML data provider for one trace, with an analysis that
* applies to a trace
*
* @throws IOException
* Exception thrown by analyses
*/
@Test
public void testNoParentDisplay() throws IOException {
ITmfTrace trace = getTrace();
assertNotNull(trace);
try {
runModule(trace);
// Get the view element from the file
Element viewElement = TmfXmlUtils.getElementInFile(TmfXmlTestFiles.DATA_PROVIDER_SIMPLE_FILE.getPath().toOSString(), TmfXmlStrings.TIME_GRAPH_VIEW, TIME_GRAPH_VIEW_ID2);
assertNotNull(viewElement);
ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> timeGraphProvider = XmlDataProviderManager.getInstance().getTimeGraphProvider(trace, viewElement);
assertNotNull(timeGraphProvider);
List<String> expectedStrings = Files.readAllLines(Paths.get("test_traces/simple_dataprovider/expectedTimeGraphTree"));
Map<Long, String> tree = assertAndGetTree(timeGraphProvider, trace, expectedStrings);
expectedStrings = Files.readAllLines(Paths.get("test_traces/simple_dataprovider/expectedTimeGraphRows"));
// The CPU entry does not have entries
expectedStrings.remove(0);
assertRows(timeGraphProvider, tree, expectedStrings);
} finally {
trace.dispose();
TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace));
}
}
/**
* Test the {@link DataDrivenTimeGraphProviderFactory} class
*/
@Test
public void testFactory() {
ITmfTrace trace = getTrace();
assertNotNull(trace);
try {
runModule(trace);
// Get the view element from the file
Element viewElement = TmfXmlUtils.getElementInFile(TmfXmlTestFiles.DATA_PROVIDER_SIMPLE_FILE.getPath().toOSString(), TmfXmlStrings.TIME_GRAPH_VIEW, TIME_GRAPH_VIEW_ID);
assertNotNull(viewElement);
TmfXmlTimeGraphViewCu tgViewCu = TmfXmlTimeGraphViewCu.compile(new AnalysisCompilationData(), viewElement);
assertNotNull(tgViewCu);
DataDrivenTimeGraphProviderFactory timeGraphFactory = tgViewCu.generate();
// Test the factory with a simple trace
ITimeGraphDataProvider<@NonNull TimeGraphEntryModel> provider = timeGraphFactory.create(trace);
assertNotNull(provider);
assertEquals(DataDrivenTimeGraphDataProvider.ID, provider.getId());
// Test the factory with an ID and state system
ITmfAnalysisModuleWithStateSystems module = TmfTraceUtils.getAnalysisModuleOfClass(trace, ITmfAnalysisModuleWithStateSystems.class, ANALYSIS_ID);
assertNotNull(module);
Iterable<@NonNull ITmfStateSystem> stateSystems = module.getStateSystems();
assertNotNull(stateSystems);
provider = DataDrivenTimeGraphProviderFactory.create(trace, Objects.requireNonNull(Lists.newArrayList(stateSystems)), getEntries(new AnalysisCompilationData(), viewElement), getvalues(viewElement), ANALYSIS_ID);
assertNotNull(provider);
assertEquals(ANALYSIS_ID, provider.getId());
} finally {
trace.dispose();
TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace));
}
}
private static List<DataDrivenOutputEntry> getEntries(AnalysisCompilationData compilationData, Element viewElement) {
List<Element> entries = TmfXmlUtils.getChildElements(viewElement, TmfXmlStrings.ENTRY_ELEMENT);
List<TmfXmlOutputEntryCu> entriesCu = new ArrayList<>();
for (Element entry : entries) {
TmfXmlOutputEntryCu entryCu = TmfXmlOutputEntryCu.compile(compilationData, entry);
if (entryCu != null) {
entriesCu.add(entryCu);
}
}
return entriesCu.stream()
.map(TmfXmlOutputEntryCu::generate)
.collect(Collectors.toList());
}
private static List<DataDrivenPresentationState> getvalues(Element viewElement) {
List<DataDrivenPresentationState> values = new ArrayList<>();
List<Element> childElements = TmfXmlUtils.getChildElements(viewElement, TmfXmlStrings.DEFINED_VALUE);
for (Element element : childElements) {
values.add(new DataDrivenPresentationState(element.getAttribute(TmfXmlStrings.VALUE), element.getAttribute(TmfXmlStrings.NAME), element.getAttribute(TmfXmlStrings.COLOR)));
}
return values;
}
}