/********************************************************************** * Copyright (c) 2004, 2014 QNX Software Systems Ltd and others. * 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: * QNX Software Systems Ltd - initial API and implementation * Anton Leherbauer (Wind River Systems) * James Blackburn (Broadcom Corp.) * Marc-Andre Laperle (Ericsson) ***********************************************************************/ package org.eclipse.cdt.core.cdescriptor.tests; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CDescriptorEvent; import org.eclipse.cdt.core.CProjectNature; import org.eclipse.cdt.core.ICDescriptor; import org.eclipse.cdt.core.ICDescriptorListener; import org.eclipse.cdt.core.ICDescriptorOperation; import org.eclipse.cdt.core.ICExtensionReference; import org.eclipse.cdt.core.ICOwnerInfo; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.testplugin.CTestPlugin; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.internal.core.pdom.PDOMManager; import org.eclipse.core.resources.IFile; 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.IWorkspaceRunnable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.junit.Assert; public class CDescriptorTests extends BaseTestCase { static String projectId = CTestPlugin.PLUGIN_ID + ".TestProject"; static IProject fProject; static CDescriptorListener listener = new CDescriptorListener(); static volatile CDescriptorEvent fLastEvent; /** * Constructor for CDescriptorTest. * * @param name */ public CDescriptorTests(String name) { super(name); } public static Test suite() { TestSuite suite = new TestSuite(CDescriptorTests.class); return suite; } @Override protected void setUp() throws Exception { CTestPlugin.getWorkspace().run(new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { IWorkspaceRoot root = CTestPlugin.getWorkspace().getRoot(); IProject project = root.getProject("testDescriptorProject"); if (!project.exists()) { project.create(null); } else { project.refreshLocal(IResource.DEPTH_INFINITE, null); } if (!project.isOpen()) { project.open(null); } CCorePlugin.getDefault().getCDescriptorManager().addDescriptorListener(listener); if (!project.hasNature(CProjectNature.C_NATURE_ID)) { addNatureToProject(project, CProjectNature.C_NATURE_ID, null); } fProject = project; CTestPlugin.getWorkspace().run(new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { CCorePlugin.getDefault().mapCProjectOwner(fProject, projectId, false); } }, null); } }, null); } @Override protected void tearDown() throws Exception { fProject.delete(true, true, null); } private static void addNatureToProject(IProject proj, String natureId, IProgressMonitor monitor) throws CoreException { IProjectDescription description = proj.getDescription(); String[] prevNatures = description.getNatureIds(); String[] newNatures = new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); newNatures[prevNatures.length] = natureId; description.setNatureIds(newNatures); proj.setDescription(description, monitor); } static public class CDescriptorListener implements ICDescriptorListener { @Override public void descriptorChanged(CDescriptorEvent event) { fLastEvent = event; } } public void testDescriptorCreation() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_ADDED); Assert.assertEquals(fLastEvent.getFlags(), 0); fLastEvent = null; Assert.assertEquals(fProject, desc.getProject()); Assert.assertEquals("*", desc.getPlatform()); } public void testDescriptorOwner() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICOwnerInfo owner = desc.getProjectOwner(); Assert.assertEquals(projectId, owner.getID()); Assert.assertEquals("*", owner.getPlatform()); Assert.assertEquals("C/C++ Test Project", owner.getName()); } // Disabled this test because it fails every now and then and it tests deprecated API // https://bugs.eclipse.org/bugs/show_bug.cgi?id=340123 public void _testConcurrentDescriptorCreation() throws Exception { for (int i = 0; i < 100 ; i++) { fProject.close(null); fProject.open(null); Thread t= new Thread() { @Override public void run() { try { CCorePlugin.getDefault().getCProjectDescription(fProject, true); } catch (CoreException exc) { fail(); } } }; t.start(); ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); try { t.join(); } catch (InterruptedException e) { } ICStorageElement data = desc.getProjectStorageElement("testElement0"); data.createChild("test"); desc.saveProjectData(); fLastEvent = null; } } /* * This tests concurrent descriptor modification inside of a ICDescriptor operation run * with * CConfigBasedDescriptorManager.runDescriptorOperation(IProject project, ICDescriptorOperation op, IProgressMonitor monitor) */ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185930 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=193503 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=196118 public void testConcurrentDescriptorModification() throws Exception { int lastLength = 0; for (int i= 0; i < 100; ++i) { final int indexi = i; PDOMManager pdomMgr= (PDOMManager)CCorePlugin.getIndexManager(); pdomMgr.shutdown(); fProject.close(null); fProject.open(null); pdomMgr.startup().schedule(); final ICDescriptor fdesc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); if (lastLength == 0) lastLength = fdesc.getProjectStorageElement("testElement").getChildren().length; final Throwable[] exception= new Throwable[10]; Thread[] threads= new Thread[10]; for (int j = 0; j < 10; j++) { final int indexj = j; Thread t= new Thread() { @Override public void run() { try { ICDescriptorOperation operation= new ICDescriptorOperation() { @Override public void execute(ICDescriptor descriptor, IProgressMonitor monitor) throws CoreException { // assertFalse(descriptor.getConfigurationDescription().isReadOnly()); ICStorageElement data = fdesc.getProjectStorageElement("testElement"); String test = "test"+(indexi*10 + indexj); data.createChild(test); // assertFalse(descriptor.getConfigurationDescription().isReadOnly()); descriptor.saveProjectData(); // System.out.println("Saved " + test); }}; CCorePlugin.getDefault().getCDescriptorManager().runDescriptorOperation(fProject, operation, null); } catch (Throwable exc) { exception[indexj]= exc; exc.printStackTrace(); } } }; t.start(); threads[j] = t; } for (int j = 0; j < threads.length; j++) { if (threads[j] != null) { try { threads[j].join(); } catch (InterruptedException e) { } } assertNull("Exception occurred: "+exception[j], exception[j]); } ICDescriptor desc= CCorePlugin.getDefault().getCProjectDescription(fProject, true); int lengthAfter = desc.getProjectStorageElement("testElement").getChildren().length; lastLength += threads.length; // Update last lengths to what we expect assertEquals("Iteration count: " + i, lastLength, lengthAfter); fLastEvent = null; } } /* * This test should pass as two threads, operating on the different storage elements * (outside of an operation) should be safe. */ public void testConcurrentDifferentStorageElementModification() throws Exception { for (int i= 0; i < 100; ++i) { Thread t= new Thread() { @Override public void run() { try { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement4"); data.createChild("test"); desc.saveProjectData(); } catch (CoreException exc) { fail(exc.getMessage()); } } }; t.start(); ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement5"); data.createChild("test"); desc.saveProjectData(); try { t.join(); } catch (InterruptedException e) { } fLastEvent = null; } Assert.assertEquals(100, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement4").getChildren().length); Assert.assertEquals(100, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement5").getChildren().length); } /* * Tests that (non-structural) changes to the storage element tree work as expected. */ public void testConcurrentSameStorageElementModification() throws Exception { for (int i= 0; i < 100; ++i) { Thread t= new Thread() { @Override public void run() { try { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement6"); data.createChild("test"); desc.saveProjectData(); } catch (CoreException exc) { fail(exc.getMessage()); } } }; t.start(); ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement6"); data.createChild("test"); desc.saveProjectData(); try { t.join(); } catch (InterruptedException e) { } fLastEvent = null; } Assert.assertEquals(200, CCorePlugin.getDefault().getCProjectDescription(fProject, false).getProjectStorageElement("testElement6").getChildren().length); } /* * Tests deadlock when accessing c project description concurrently from two threads */ public void testDeadlockDuringProjectCreation() throws Exception { for (int i= 0; i < 10; ++i) { tearDown(); setUp(); Thread t= new Thread() { @Override public void run() { try { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement0"); data.createChild("test"); desc.saveProjectData(); } catch (Exception exc) { } } }; t.start(); ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement0"); data.createChild("test"); desc.saveProjectData(); try { t.join(); } catch (InterruptedException e) { } fLastEvent = null; } } public void testDescriptorConversion() { } public void testExtensionCreation() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICExtensionReference extRef = desc.create("org.eclipse.cdt.testextension", "org.eclipse.cdt.testextensionID"); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); Assert.assertEquals(fLastEvent.getFlags(), CDescriptorEvent.EXTENSION_CHANGED); fLastEvent = null; Assert.assertEquals("org.eclipse.cdt.testextension", extRef.getExtension()); Assert.assertEquals("org.eclipse.cdt.testextensionID", extRef.getID()); } public void testExtensionGet() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); desc.create("org.eclipse.cdt.testextension", "org.eclipse.cdt.testextensionID"); ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); Assert.assertEquals("org.eclipse.cdt.testextension", extRef[0].getExtension()); Assert.assertEquals("org.eclipse.cdt.testextensionID", extRef[0].getID()); } public void testExtensionData() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); desc.create("org.eclipse.cdt.testextension", "org.eclipse.cdt.testextensionID"); ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); extRef[0].setExtensionData("testKey", "testValue"); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); Assert.assertEquals(fLastEvent.getFlags(), 0); fLastEvent = null; Assert.assertEquals("testValue", extRef[0].getExtensionData("testKey")); extRef[0].setExtensionData("testKey", null); Assert.assertEquals(null, extRef[0].getExtensionData("testKey")); } public void testExtensionRemove() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); desc.create("org.eclipse.cdt.testextension", "org.eclipse.cdt.testextensionID"); ICExtensionReference extRef[] = desc.get("org.eclipse.cdt.testextension"); desc.remove(extRef[0]); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); Assert.assertEquals(fLastEvent.getFlags(), CDescriptorEvent.EXTENSION_CHANGED); fLastEvent = null; } public void testProjectDataCreate() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement"); data.createChild("test"); desc.saveProjectData(); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); Assert.assertEquals(fLastEvent.getFlags(), 0); fLastEvent = null; } public void testProjectDataDelete() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement"); data.createChild("test"); ICStorageElement[] list = data.getChildrenByName("test"); Assert.assertEquals(1, list.length); data.removeChild(list[0]); desc.saveProjectData(); Assert.assertNotNull(fLastEvent); Assert.assertEquals(fLastEvent.getDescriptor(), desc); Assert.assertEquals(fLastEvent.getType(), CDescriptorEvent.CDTPROJECT_CHANGED); Assert.assertEquals(fLastEvent.getFlags(), 0); fLastEvent = null; } public void testCProjectDescriptionDescriptorInteraction() throws Exception { for (int i = 1; i < 100 ; i++) { // Create a descriptor with some test data ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("descDescInteraction"); data.createChild("dataItem1"); // Get the CProjectDescription ICProjectDescription projDesc = CCorePlugin.getDefault().getProjectDescription(fProject); data = desc.getProjectStorageElement("descDescInteraction"); data.createChild("dataItem2"); data = desc.getProjectStorageElement("descDescInteraction2"); data.createChild("dataItem3"); // save the descriptor desc.saveProjectData(); // save the project description CCorePlugin.getDefault().setProjectDescription(fProject, projDesc); fProject.close(null); assertTrue(CCorePlugin.getDefault().getCProjectDescription(fProject, false) == null); fProject.open(null); // Check that the descriptor added data is still there desc = CCorePlugin.getDefault().getCProjectDescription(fProject, false); data = desc.getProjectStorageElement("descDescInteraction"); assertEquals(2 * i, data.getChildren().length); data = desc.getProjectStorageElement("descDescInteraction2"); assertEquals(1 * i, data.getChildren().length); } } public void testAccumulatingBlankLinesInProjectData() throws Exception { ICDescriptor desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); ICStorageElement data = desc.getProjectStorageElement("testElement"); data.createChild("test"); desc.saveProjectData(); fProject.close(null); fProject.open(null); String dotCProject1 = readDotCProjectFile(fProject); long mtime1 = fProject.getFile(".cproject").getLocalTimeStamp(); desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); data = desc.getProjectStorageElement("testElement"); for (ICStorageElement child : data.getChildren()) { data.removeChild(child); } data.createChild("test"); desc.saveProjectData(); String dotCProject2 = readDotCProjectFile(fProject); long mtime2 = fProject.getFile(".cproject").getLocalTimeStamp(); assertEquals("Difference in .cproject file", dotCProject1, dotCProject2); assertTrue(".cproject file has been written", mtime1 == mtime2); // do it a second time - just to be sure fProject.close(null); fProject.open(null); desc = CCorePlugin.getDefault().getCProjectDescription(fProject, true); data = desc.getProjectStorageElement("testElement"); for (ICStorageElement child : data.getChildren()) { data.removeChild(child); } data.createChild("test"); desc.saveProjectData(); String dotCProject3 = readDotCProjectFile(fProject); long mtime3 = fProject.getFile(".cproject").getLocalTimeStamp(); assertEquals("Difference in .cproject file", dotCProject2, dotCProject3); assertTrue(".cproject file has been written", mtime2 == mtime3); } /** * Read .cproject file. * * @param project * @return content of .cproject file * @throws CoreException * @throws IOException */ private static String readDotCProjectFile(IProject project) throws CoreException, IOException { IFile cProjectFile = project.getFile(".cproject"); InputStream in = cProjectFile.getContents(); try { Reader reader = new InputStreamReader(in, "UTF-8"); StringBuilder sb = new StringBuilder(); char[] b = new char[4096]; int n; while ((n = reader.read(b)) > 0) { sb.append(b, 0, n); } return sb.toString(); } finally { in.close(); } } }