/******************************************************************************* * Copyright (c) 2008, 2017 Wind River Systems, Inc. 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: * Martin Oberhuber (Wind River) - initial API and implementation for [232426] * Szymon Ptaszkiewicz (IBM) - Symlink test failures on Windows 7 [331716] * Sergey Prigogin (Google) - ongoing development *******************************************************************************/ package org.eclipse.core.tests.internal.localstore; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Path; /** * */ public class SymlinkResourceTest extends LocalStoreTest { public SymlinkResourceTest() { super(); } public SymlinkResourceTest(String name) { super(name); } public static Test suite() { return new TestSuite(SymlinkResourceTest.class); } protected void mkLink(IFileStore dir, String src, String tgt, boolean isDir) { try { createSymLink(dir.toLocalFile(EFS.NONE, getMonitor()), src, tgt, isDir); } catch (CoreException e) { fail("mkLink", e); } } protected void createBug232426Structure(IFileStore rootDir) throws CoreException { IFileStore folderA = rootDir.getChild("a"); IFileStore folderB = rootDir.getChild("b"); IFileStore folderC = rootDir.getChild("c"); folderA.mkdir(EFS.NONE, getMonitor()); folderB.mkdir(EFS.NONE, getMonitor()); folderC.mkdir(EFS.NONE, getMonitor()); /* create symbolic links */ mkLink(folderA, "link", new Path("../b").toOSString(), true); mkLink(folderB, "linkA", new Path("../a").toOSString(), true); mkLink(folderB, "linkC", new Path("../c").toOSString(), true); mkLink(folderC, "link", new Path("../b").toOSString(), true); } protected void createBug358830Structure(IFileStore rootDir) throws CoreException { IFileStore folderA = rootDir.getChild("a"); folderA.mkdir(EFS.NONE, getMonitor()); /* create trivial recursive symbolic link */ mkLink(folderA, "link", new Path("../").toOSString(), true); } /** * Test a very specific case of mutually recursive symbolic links: * <pre> * a/link -> ../b * b/link1 -> ../a, b/link2 -> ../c * c/link -> ../b * </pre> * In the specific bug, the two links in b were followed in an alternated * fashion while walking down the tree. A correct implementation should * stop following symbolic links as soon as a node is reached that has * been visited before. * See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=232426">bug 232426</a> */ public void testBug232426() throws Exception { // Only activate this test if testing of symbolic links is possible. if (!canCreateSymLinks()) { return; } /* Re-use projects which are cleaned up automatically */ final IProject project = projects[0]; getWorkspace().run((IWorkspaceRunnable) monitor -> { /* delete open project because we must re-open with BACKGROUND_REFRESH */ project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, getMonitor()); project.create(null); createBug232426Structure(EFS.getStore(project.getLocationURI())); //Bug only happens with BACKGROUND_REFRESH. project.open(IResource.BACKGROUND_REFRESH, getMonitor()); }, null); //wait for BACKGROUND_REFRESH to complete. waitForRefresh(); project.accept(new IResourceVisitor() { int resourceCount = 0; @Override public boolean visit(IResource resource) { resourceCount++; //We have 1 root + 3 folders + 4 elements --> 8 elements to visit at most assertTrue(resourceCount <= 8); return true; } }); } public void testBug358830() throws Exception { // Only activate this test if testing of symbolic links is possible. if (!canCreateSymLinks()) { return; } /* Re-use projects which are cleaned up automatically */ final IProject project = projects[0]; getWorkspace().run((IWorkspaceRunnable) monitor -> { /* delete open project because we must re-open with BACKGROUND_REFRESH */ project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, getMonitor()); project.create(null); createBug358830Structure(EFS.getStore(project.getLocationURI())); project.open(IResource.BACKGROUND_REFRESH, getMonitor()); }, null); //wait for BACKGROUND_REFRESH to complete. waitForRefresh(); final int resourceCount[] = new int[] {0}; project.accept(resource -> { resourceCount[0]++; return true; }); //We have 1 root + 1 folder + 1 file (.project) --> 3 elements to visit assertEquals(3, resourceCount[0]); } }