diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml index 11ac1c4c46..bd5aa28967 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/plugin.xml @@ -16,5 +16,14 @@ class="org.eclipse.tracecompass.tmf.analysis.xml.core.tests.stubs.XmlSchemaParserStub"> - + + + + + + + diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java new file mode 100644 index 0000000000..28dcba7c3b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core.tests/src/org/eclipse/tracecompass/tmf/analysis/xml/core/tests/module/XmlUtilsWithTraceTest.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2025 Ericsson + * + * 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.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.annotation.NonNull; +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.tmf.analysis.xml.core.tests.Activator; +import org.eclipse.tracecompass.tmf.analysis.xml.core.tests.common.TmfXmlTestFiles; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.TmfProjectNature; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.event.TmfEvent; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException; +import org.eclipse.tracecompass.tmf.core.io.ResourceUtil; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStubNs; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +/** + * Test the XML Utils delete supplementary directory + * + * @author Geneviève Bastien + */ +public class XmlUtilsWithTraceTest { + + private static final @NonNull String TEST_TRACE_NAME = "testTrace4.xml"; + + private static final @NonNull String TEST_TRACE = "test_traces/" + TEST_TRACE_NAME; + + private static final @NonNull String ANALYSIS_ID = "xml.core.tests.simple.pattern"; + + private static IProject sfProject; + + /** + * Class setup + * + * @throws CoreException + * if an error occurs + */ + @BeforeClass + public static void startUp() throws CoreException { + IProject project = ResourcesPlugin.getWorkspace().getRoot() + .getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME); + if (!project.exists()) { + project.create(null); + if (!project.isOpen()) { + project.open(null); + } + IProjectDescription description = project.getDescription(); + description.setNatureIds(new String[] { TmfProjectNature.ID }); + project.setDescription(description, null); + } + if (!project.isOpen()) { + project.open(null); + } + + IFolder tracesFolder = project.getFolder("Traces"); //$NON-NLS-1$ + if (!tracesFolder.exists()) { + tracesFolder.create(true, true, null); + } + + IFolder supplRootFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME); + if (!supplRootFolder.exists()) { + supplRootFolder.create(true, true, null); + } + sfProject = project; + } + + /** + * Class tear down + * + * @throws CoreException + * if an error occurs + */ + @AfterClass + public static void tearDown() throws CoreException { + if (sfProject != null) { + sfProject.delete(true, null); + } + } + + /** + * Load the XML files for the current test + */ + @Before + public void setUp() { + XmlUtils.addXmlFile(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile()); + XmlAnalysisModuleSource.notifyModuleChange(); + } + + /** + * Clean + */ + @After + public void cleanUp() { + XmlUtils.deleteFiles(ImmutableList.of( + TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName())); + XmlAnalysisModuleSource.notifyModuleChange(); + } + + private ITmfTrace getTrace() throws CoreException { + TmfXmlTraceStubNs trace = new TmfXmlTraceStubNs(); + String absolutePath = Activator.getAbsolutePath(new Path(TEST_TRACE)).toOSString(); + IStatus status = trace.validate(null, absolutePath); + if (!status.isOK()) { + fail(status.getException().getMessage()); + } + + IResource resource = createResource(absolutePath); + try { + trace.initTrace(resource, absolutePath, TmfEvent.class); + } catch (TmfTraceException e) { + trace.dispose(); + fail(e.getMessage()); + } + + // Initialize the trace and module + TmfTraceOpenedSignal signal = new TmfTraceOpenedSignal(this, trace, null); + trace.traceOpened(signal); + // The data provider manager uses opened traces from the manager + TmfTraceManager.getInstance().traceOpened(signal); + return trace; + } + + @SuppressWarnings("null") + private static IResource createResource(String path) throws CoreException { + IPath targetLocation = new Path(path); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IProject project = root.getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + IFolder tracesFolder = project.getFolder("Traces"); + IResource resource = tracesFolder.getFile(TEST_TRACE_NAME); + ResourceUtil.createSymbolicLink(resource, targetLocation, true, null); + + IFolder supplRootFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME); + IFolder supplFolder = supplRootFolder.getFolder(resource.getProjectRelativePath().removeFirstSegments(1)); + if (!supplFolder.exists()) { + supplFolder.create(true, true, null); + } + resource.setPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER, supplFolder.getLocation().toOSString()); + + return resource; + } + + private static void runModule(ITmfTrace trace) { + IAnalysisModule module = trace.getAnalysisModule(ANALYSIS_ID); + assertNotNull(module); + module.schedule(); + assertTrue(module.waitForCompletion()); + } + + /** + * Test delete supplementary dir when trace is open + * + * @throws CoreException + * if an error occurs + */ + @Test + public void testDeleteSupplDirWithTraceOpen() throws CoreException { + ITmfTrace trace = getTrace(); + assertNotNull(trace); + try { + runModule(trace); + String supplPathString = TmfTraceManager.getSupplementaryFileDir(trace); + IPath path = new Path(supplPathString); + IPath ssFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("ht"); + IPath segFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("dat"); + assertTrue(ssFile.toFile().exists()); + assertTrue(segFile.toFile().exists()); + XmlUtils.deleteSupplementaryResources(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName(), null); + assertFalse(ssFile.toFile().exists()); + assertFalse(segFile.toFile().exists()); + } finally { + trace.dispose(); + TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace)); + } + } + + /** + * Test delete supplementary dir when trace is open + * + * @throws CoreException + * Exception thrown by analyses + */ + @Test + public void testDeleteSupplDirWithTraceClosed() throws CoreException { + ITmfTrace trace = getTrace(); + assertNotNull(trace); + try { + runModule(trace); + String supplPathString = TmfTraceManager.getSupplementaryFileDir(trace); + IPath path = new Path(supplPathString); + IPath ssFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("ht"); + IPath segFile = path.addTrailingSeparator().append(ANALYSIS_ID).addFileExtension("dat"); + assertTrue(ssFile.toFile().exists()); + assertTrue(segFile.toFile().exists()); + + TmfTraceClosedSignal signal = new TmfTraceClosedSignal(this, trace); + TmfTraceManager.getInstance().traceClosed(signal); + trace.dispose(); + + XmlUtils.deleteSupplementaryResources(TmfXmlTestFiles.VALID_PATTERN_SIMPLE_FILE.getFile().getName(), null); + assertFalse(ssFile.toFile().exists()); + assertFalse(segFile.toFile().exists()); + } finally { + trace.dispose(); + TmfTraceManager.getInstance().traceClosed(new TmfTraceClosedSignal(this, trace)); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF index ee16dadf3f..a3ceb66c5e 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF @@ -17,7 +17,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.tracecompass.analysis.profiling.core, org.eclipse.core.commands, com.google.guava, - org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional + org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional, + org.eclipse.core.resources Export-Package: org.eclipse.tracecompass.internal.tmf.analysis.xml.core;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests", org.eclipse.tracecompass.internal.tmf.analysis.xml.core.callstack;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests", org.eclipse.tracecompass.internal.tmf.analysis.xml.core.config;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests", diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java index 8e91ced31f..948d37903a 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/config/XmlConfigurationSource.java @@ -108,7 +108,7 @@ public ITmfConfiguration update(String id, Map parameters) throw if (!XmlUtils.listFiles().containsKey(id)) { return null; } - + XmlUtils.deleteSupplementaryResources(id, null); XmlUtils.deleteFiles(ImmutableList.of(id)); XmlUtils.saveFilesStatus(); XmlAnalysisModuleSource.notifyModuleChange(); diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java index db31bb23e9..8179231d4d 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/module/XmlUtils.java @@ -42,12 +42,20 @@ import javax.xml.validation.SchemaFactory; import org.apache.commons.io.FilenameUtils; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; @@ -61,6 +69,11 @@ import org.eclipse.tracecompass.tmf.analysis.xml.core.module.ITmfXmlSchemaParser; 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.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.TmfProjectNature; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.osgi.framework.Bundle; import org.osgi.service.prefs.BackingStoreException; import org.w3c.dom.Document; @@ -722,4 +735,65 @@ public static String createXmlFileString(String baseName) { }); return enabledFiles; } + + /** + * Deletes all supplementary resources created by an XML analysis file + * + * @param xmlFileName + * the file name of xml analysis + * @param monitor + * a progress monitor + */ + public static void deleteSupplementaryResources(String xmlFileName, @Nullable IProgressMonitor monitor) { + final IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor); + // Get unique list of analysis IDs + Set analysisIds = new HashSet<>(); + analysisIds.addAll(XmlUtils.getAnalysisIdsFromFile(xmlFileName)); + + // Delete persistent data of all open traces (this will close the file before deleting it) + for (ITmfTrace trace : TmfTraceManager.getInstance().getOpenedTraces()) { + for (ITmfTrace tr : TmfTraceManager.getTraceSetWithExperiment(trace)) { + analysisIds.forEach(analysisId -> { + IAnalysisModule module = tr.getAnalysisModule(analysisId); + if (module != null) { + module.clearPersistentData(); + } + }); + } + if (mon.isCanceled()) { + return; + } + } + // Delete applicable persistent data of non-opened traces + for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { + try { + if (project.hasNature(TmfProjectNature.ID)) { + project.refreshLocal(IResource.DEPTH_INFINITE, monitor); + IFolder supplFolder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME); + if (supplFolder != null && supplFolder.exists()) { + supplFolder.accept((IResourceVisitor) resource -> { + if (mon.isCanceled()) { + return false; + } + if (resource instanceof IFile) { + analysisIds.forEach(analysisId -> { + if (resource.getName().startsWith(analysisId)) { + try { + resource.delete(true, null); + } catch (CoreException e) { + Activator.logError("Can't delete supplementary resource " + resource.getName(), e); //$NON-NLS-1$ + } + } + }); + } + return true; + }, IResource.DEPTH_INFINITE, IResource.NONE); + } + } + } catch (CoreException e) { + Activator.logError("Can't delete supplementary resources for XML analyses", e); //$NON-NLS-1$ + } + } + } + } diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java index fc1cb34bc7..c8c2b28e95 100644 --- a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java +++ b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/internal/tmf/analysis/xml/core/pattern/stateprovider/XmlPatternAnalysis.java @@ -381,4 +381,10 @@ public boolean waitForCompletion(@NonNull IProgressMonitor monitor) { return properties; } + @Override + public void clearPersistentData() { + super.clearPersistentData(); + fSegmentStoreModule.clearPersistentData(); + fStateSystemModule.clearPersistentData(); + } }