| /******************************************************************************* |
| * Copyright (c) 2000, 2013 IBM Corporation and others. |
| * |
| * 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 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.tests.ccvs.core.mappings; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InterruptedIOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.internal.resources.mapping.SimpleResourceMapping; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceVisitor; |
| import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; |
| import org.eclipse.core.resources.mapping.ResourceMapping; |
| import org.eclipse.core.resources.mapping.ResourceMappingContext; |
| import org.eclipse.core.resources.mapping.ResourceTraversal; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.jface.util.Util; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.team.core.TeamException; |
| import org.eclipse.team.core.TeamStatus; |
| import org.eclipse.team.core.diff.IDiff; |
| import org.eclipse.team.core.diff.IThreeWayDiff; |
| import org.eclipse.team.core.mapping.IResourceDiffTree; |
| import org.eclipse.team.core.mapping.provider.ResourceDiffTree; |
| import org.eclipse.team.core.synchronize.FastSyncInfoFilter; |
| import org.eclipse.team.core.synchronize.SyncInfo; |
| import org.eclipse.team.core.synchronize.SyncInfoTree; |
| import org.eclipse.team.core.variants.CachedResourceVariant; |
| import org.eclipse.team.core.variants.IResourceVariant; |
| import org.eclipse.team.internal.ccvs.core.CVSException; |
| import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; |
| import org.eclipse.team.internal.ccvs.core.CVSTag; |
| import org.eclipse.team.internal.ccvs.core.ICVSFile; |
| import org.eclipse.team.internal.ccvs.core.ICVSFolder; |
| import org.eclipse.team.internal.ccvs.core.ICVSRemoteFile; |
| import org.eclipse.team.internal.ccvs.core.ICVSResource; |
| import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; |
| import org.eclipse.team.internal.ccvs.core.connection.CVSCommunicationException; |
| import org.eclipse.team.internal.ccvs.core.resources.RemoteFolderTree; |
| import org.eclipse.team.internal.ccvs.core.resources.RemoteFolderTreeBuilder; |
| import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; |
| import org.eclipse.team.internal.ccvs.ui.operations.CacheBaseContentsOperation; |
| import org.eclipse.team.internal.ccvs.ui.operations.CacheRemoteContentsOperation; |
| import org.eclipse.team.internal.core.ResourceVariantCache; |
| import org.eclipse.team.internal.core.ResourceVariantCacheEntry; |
| import org.eclipse.team.internal.core.mapping.SyncInfoToDiffConverter; |
| import org.eclipse.team.tests.ccvs.core.EclipseTest; |
| import org.eclipse.team.tests.ccvs.core.TeamCVSTestPlugin; |
| |
| import junit.framework.Test; |
| |
| /** |
| * Tests for using CVS operations with deep and shallow resource mappings. |
| */ |
| public class ResourceMapperTests extends EclipseTest { |
| |
| |
| public ResourceMapperTests() { |
| super(); |
| } |
| |
| public ResourceMapperTests(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| return suite(ResourceMapperTests.class); |
| } |
| |
| /** |
| * Update the resources contained in the given mappers and ensure that the |
| * update was performed properly by comparing the result with the reference projects. |
| * @throws Exception |
| */ |
| protected void update(ResourceMapping mapper, LocalOption[] options) throws Exception { |
| SyncInfoTree incomingSet = getIncoming(mapper.getProjects()); |
| update(new ResourceMapping[] { mapper }, options); |
| assertUpdate(mapper, incomingSet); |
| } |
| |
| /** |
| * Replace the resources contained in the given mappers and ensure that the |
| * update was performed properly by comparing the result with the reference projects. |
| * @throws Exception |
| */ |
| protected void replace(ResourceMapping mapper) throws Exception { |
| SyncInfoTree incomingSet = getIncoming(mapper.getProjects()); |
| replace(new ResourceMapping[] { mapper }); |
| assertUpdate(mapper, incomingSet); |
| } |
| |
| /** |
| * Commit and check that all resources in containing project that should have been committed were and |
| * that any not contained by the mappers were not. |
| * @throws CoreException |
| * @see org.eclipse.team.tests.ccvs.core.EclipseTest#commit(org.eclipse.core.resources.mapping.IResourceMapper[], java.lang.String) |
| */ |
| protected void commit(ResourceMapping mapper, String message) throws CoreException { |
| SyncInfoTree set = getOutgoing(mapper.getProjects()); |
| commit(new ResourceMapping[] { mapper }, message); |
| assertCommit(mapper, set); |
| } |
| |
| /** |
| * Tag the given resource mappings and assert that only the resources |
| * within the mapping were tagged. |
| * @throws CoreException |
| */ |
| protected void tag(ResourceMapping mapping, CVSTag tag) throws CoreException { |
| tag(new ResourceMapping[] { mapping }, tag, false); |
| assertTagged(mapping, tag); |
| } |
| |
| /** |
| * Branch the resources in the given mapping. |
| * @throws CoreException |
| * @throws IOException |
| */ |
| protected void branch(ResourceMapping mapping, CVSTag branch) throws CoreException, IOException { |
| CVSTag version = new CVSTag("Root_" + branch.getName(), CVSTag.VERSION); |
| branch(new ResourceMapping[] { mapping }, version, branch, true /* update */); |
| assertTagged(mapping, version); |
| assertBranched(mapping, branch); |
| } |
| |
| /** |
| * Add any resources contained by the mapping |
| * @param mapping |
| * @throws CoreException |
| */ |
| protected void add(ResourceMapping mapping) throws CoreException { |
| SyncInfoTree set = getUnaddedResource(mapping); |
| add(new ResourceMapping[] { mapping }); |
| assertAdded(mapping, set); |
| } |
| |
| private void assertAdded(ResourceMapping mapping, final SyncInfoTree set) throws CoreException { |
| // Assert that all resources covered by the mapping are now under version control (i.e. are in-sync) |
| // Remove the resources contained in the mapping from the set of unadded resources. |
| visit(mapping, ResourceMappingContext.LOCAL_CONTEXT, (IResourceVisitor) resource -> { |
| ICVSResource cvsResource = getCVSResource(resource); |
| assertTrue("Resource was not added but should have been: " + resource.getFullPath(), |
| (cvsResource.isManaged() |
| || (cvsResource.isFolder() |
| && ((ICVSFolder)cvsResource).isCVSFolder()))); |
| set.remove(resource); |
| return true; |
| }); |
| // Assert that the remaining unadded resources are still unadded |
| SyncInfo[] infos = set.getSyncInfos(); |
| for (SyncInfo info : infos) { |
| ICVSResource cvsResource = getCVSResource(info.getLocal()); |
| assertTrue("Resource was added but should not have been: " + info.getLocal().getFullPath(), !cvsResource.isManaged()); |
| } |
| } |
| |
| /* |
| * Need to ensure that only the resources contained in the mapping |
| * have the branch tag associated with them. |
| */ |
| private void assertBranched(ResourceMapping mapping, CVSTag branch) throws CoreException { |
| // First, make sure the proper resources are tagged in the repo |
| assertTagged(mapping, branch); |
| // Now make sure the proper local files are tagged |
| final Map<String, ICVSResource> remotes = getTaggedRemoteFilesByPath(mapping, branch); |
| final Map<String, ICVSFile> locals = getTaggedLocalFilesByPath(mapping, branch); |
| for (Iterator<String> iter = remotes.keySet().iterator(); iter.hasNext();) { |
| String key = iter.next(); |
| ICVSRemoteFile remote = (ICVSRemoteFile)remotes.get(key); |
| ICVSFile local = locals.get(key); |
| assertNotNull("Remotely tagged resource was not tagged locally: " + remote.getRepositoryRelativePath(), local); |
| assertEquals(local.getIResource().getParent().getFullPath(), remote, local, false, false /* include tags */); |
| assertEquals("Remotely tagged resource was not tagged locally: " + remote.getRepositoryRelativePath(), branch, local.getSyncInfo().getTag()); |
| locals.remove(key); |
| iter.remove(); |
| } |
| // The remote map should be empty after traversal |
| for (Object element : remotes.keySet()) { |
| String path = (String) element; |
| fail("Remote file " + path + " was tagged remotely but not locally."); |
| } |
| // The local map should be empty after traversal |
| for (Object element : locals.keySet()) { |
| String path = (String) element; |
| fail("Local file " + path + " was tagged locally but not remotely."); |
| } |
| } |
| |
| private void assertTagged(ResourceMapping mapping, final CVSTag tag) throws CoreException { |
| final Map<String, ICVSResource> tagged = getTaggedRemoteFilesByPath(mapping, tag); |
| // Visit all the resources in the traversal and ensure that they are tagged |
| visit(mapping, ResourceMappingContext.LOCAL_CONTEXT, (IResourceVisitor) resource -> { |
| if (resource.getType() == IResource.FILE) { |
| ICVSRemoteFile file = popRemote(resource, tagged); |
| assertNotNull("Resource was not tagged: " + resource.getFullPath(), file); |
| } |
| return true; |
| }); |
| |
| for (String path : tagged.keySet()) { |
| fail("Remote file " + path + " was tagged but should not have been."); |
| } |
| } |
| |
| private Map<String, ICVSFile> getTaggedLocalFilesByPath(ResourceMapping mapping, final CVSTag branch) |
| throws CoreException { |
| final Map<String, ICVSFile> tagged = new HashMap<>(); |
| IProject[] projects = mapping.getProjects(); |
| for (IProject project : projects) { |
| project.accept(resource -> { |
| if (resource.getType() == IResource.FILE) { |
| ICVSFile file = (ICVSFile)getCVSResource(resource); |
| ResourceSyncInfo info = file.getSyncInfo(); |
| if (info != null && info.getTag() != null && info.getTag().equals(branch)) { |
| tagged.put(file.getRepositoryRelativePath(), file); |
| } |
| } |
| return true; |
| }); |
| } |
| return tagged; |
| } |
| |
| private Map<String, ICVSResource> getTaggedRemoteFilesByPath(ResourceMapping mapping, final CVSTag tag) |
| throws CVSException { |
| IProject[] projects = mapping.getProjects(); |
| ICVSResource[] remotes = getRemoteTrees(projects, tag); |
| final Map<String, ICVSResource> tagged = getFilesByPath(remotes); |
| return tagged; |
| } |
| |
| private ICVSResource[] getRemoteTrees(IProject[] projects, CVSTag tag) throws CVSException { |
| List<ICVSResource> result = new ArrayList<>(); |
| for (IProject project : projects) { |
| RemoteFolderTree tree = RemoteFolderTreeBuilder.buildRemoteTree(getRepository(), project, tag, DEFAULT_MONITOR); |
| result.add(tree); |
| } |
| return result.toArray(new ICVSResource[result.size()]); |
| } |
| |
| private Map<String, ICVSResource> getFilesByPath(ICVSResource[] remotes) throws CVSException { |
| Map<String, ICVSResource> result = new HashMap<>(); |
| for (ICVSResource resource : remotes) { |
| collectFiles(resource, result); |
| } |
| return result; |
| } |
| |
| private void collectFiles(ICVSResource resource, Map<String, ICVSResource> result) throws CVSException { |
| if (resource.isFolder()) { |
| ICVSResource[] members = ((ICVSFolder)resource).members(ICVSFolder.ALL_EXISTING_MEMBERS); |
| for (ICVSResource member : members) { |
| collectFiles(member, result); |
| } |
| } else { |
| result.put(resource.getRepositoryRelativePath(), resource); |
| } |
| } |
| |
| private ICVSRemoteFile popRemote(IResource resource, Map<String, ICVSResource> tagged) throws CVSException { |
| ICVSResource cvsResource = getCVSResource(resource); |
| ICVSRemoteFile remote = (ICVSRemoteFile)tagged.get(cvsResource.getRepositoryRelativePath()); |
| if (remote != null) { |
| tagged.remove(remote.getRepositoryRelativePath()); |
| } |
| return remote; |
| } |
| |
| private ResourceMapping asResourceMapping(final IResource[] resources, final int depth) { |
| return new ResourceMapping() { |
| private Object object = new Object(); |
| @Override |
| public Object getModelObject() { |
| return object; |
| } |
| @Override |
| public IProject[] getProjects() { |
| return getProjects(resources); |
| } |
| private IProject[] getProjects(IResource[] resources) { |
| Set<IProject> projects = new HashSet<>(); |
| for (IResource resource : resources) { |
| projects.add(resource.getProject()); |
| } |
| return projects.toArray(new IProject[projects.size()]); |
| } |
| @Override |
| public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException { |
| return new ResourceTraversal[] { |
| new ResourceTraversal(resources, depth, IResource.NONE) |
| }; |
| } |
| @Override |
| public String getModelProviderId() { |
| return "org.eclipse.team.tests.cvs.core.modelProvider"; |
| } |
| }; |
| } |
| |
| private void assertUpdate(ResourceMapping mapper, final SyncInfoTree set) throws Exception { |
| final Exception[] exception = new Exception[] { null }; |
| visit(mapper, new SyncInfoSetTraveralContext(set), (IResourceVisitor) resource -> { |
| SyncInfo info = set.getSyncInfo(resource); |
| if (info != null) { |
| set.remove(resource); |
| try { |
| // Assert that the local sync info matches the remote info |
| assertEquals(resource.getParent().getFullPath(), getCVSResource(resource), (ICVSResource)info.getRemote(), false, false); |
| } catch (CVSException e1) { |
| exception[0] = e1; |
| } catch (CoreException e2) { |
| exception[0] = e2; |
| } catch (IOException e3) { |
| exception[0] = e3; |
| } |
| } |
| return true; |
| }); |
| if (exception[0] != null) throw exception[0]; |
| |
| // check the the state of the remaining resources has not changed |
| assertUnchanged(set); |
| } |
| |
| private void assertCommit(ResourceMapping mapper, final SyncInfoTree set) throws CoreException { |
| visit(mapper, new SyncInfoSetTraveralContext(set), (IResourceVisitor) resource -> { |
| SyncInfo info = set.getSyncInfo(resource); |
| if (info != null) { |
| set.remove(resource); |
| assertTrue("Committed resource is not in-sync: " + resource.getFullPath(), getSyncInfo(resource).getKind() == SyncInfo.IN_SYNC); |
| } |
| return true; |
| }); |
| // check the the state of the remaining resources has not changed |
| assertUnchanged(set); |
| } |
| |
| /* |
| * Assert that the state of the resources in the set have not changed |
| */ |
| private void assertUnchanged(SyncInfoTree set) throws TeamException { |
| //TODO: Need to refresh the subscriber since flush of remote state is deep |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().refresh(set.getResources(), IResource.DEPTH_ZERO, DEFAULT_MONITOR); |
| SyncInfo[] infos = set.getSyncInfos(); |
| for (SyncInfo info : infos) { |
| assertUnchanged(info); |
| } |
| } |
| |
| private void assertUnchanged(SyncInfo info) throws TeamException { |
| SyncInfo current = getSyncInfo(info.getLocal()); |
| assertEquals("The sync info changed for " + info.getLocal().getFullPath(), info, current); |
| } |
| |
| private SyncInfo getSyncInfo(IResource local) throws TeamException { |
| return CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().getSyncInfo(local); |
| } |
| |
| private SyncInfoTree getIncoming(IProject[] projects) throws TeamException { |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().refresh(projects, IResource.DEPTH_INFINITE, DEFAULT_MONITOR); |
| SyncInfoTree set = getAllOutOfSync(projects); |
| set.removeOutgoingNodes(); |
| set.removeConflictingNodes(); |
| return set; |
| } |
| |
| private SyncInfoTree getOutgoing(IProject[] projects) { |
| SyncInfoTree set = getAllOutOfSync(projects); |
| set.removeIncomingNodes(); |
| set.removeConflictingNodes(); |
| return set; |
| } |
| |
| private SyncInfoTree getUnaddedResource(ResourceMapping mapping) { |
| SyncInfoTree set = getAllOutOfSync(mapping.getProjects()); |
| set.selectNodes(new FastSyncInfoFilter() { |
| @Override |
| public boolean select(SyncInfo info) { |
| try { |
| if (info.getLocal().getType() != IResource.PROJECT && info.getRemote() == null && info.getBase() == null) { |
| ICVSResource resource = getCVSResource(info.getLocal()); |
| return !resource.isManaged(); |
| } |
| } catch (CVSException e) { |
| fail(e.getMessage()); |
| } |
| return false; |
| } |
| }); |
| return set; |
| } |
| |
| private SyncInfoTree getAllOutOfSync(IProject[] projects) { |
| SyncInfoTree set = new SyncInfoTree(); |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().collectOutOfSync(projects, IResource.DEPTH_INFINITE, set, DEFAULT_MONITOR); |
| return set; |
| } |
| |
| private IResourceDiffTree getAllDiffs(IProject[] projects) throws CoreException { |
| final ResourceDiffTree tree = new ResourceDiffTree(); |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().accept(projects, IResource.DEPTH_INFINITE, delta -> { |
| tree.add(delta); |
| return true; |
| }); |
| return tree; |
| } |
| |
| private void visit(ResourceMapping mapper, ResourceMappingContext context, IResourceVisitor visitor) throws CoreException { |
| ResourceTraversal[] traversals = mapper.getTraversals(context, null); |
| for (ResourceTraversal traversal : traversals) { |
| visit(traversal, context, visitor); |
| } |
| } |
| |
| private void visit(ResourceTraversal traversal, ResourceMappingContext context, IResourceVisitor visitor) throws CoreException { |
| IResource[] resources = traversal.getResources(); |
| for (IResource resource : resources) { |
| visit(resource, visitor, context, traversal.getDepth()); |
| } |
| } |
| |
| private void visit(IResource resource, IResourceVisitor visitor, ResourceMappingContext context, int depth) |
| throws CoreException { |
| if (!visitor.visit(resource) || depth == IResource.DEPTH_ZERO || resource.getType() == IResource.FILE) |
| return; |
| Set<IResource> members = new HashSet<>(); |
| members.addAll(Arrays.asList(((IContainer) resource).members(false))); |
| if (context instanceof RemoteResourceMappingContext) { |
| RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext) context; |
| members.addAll(Arrays.asList(remoteContext.fetchMembers((IContainer) resource, DEFAULT_MONITOR))); |
| } |
| for (IResource member : members) { |
| visit(member, visitor, context, |
| depth == IResource.DEPTH_ONE ? IResource.DEPTH_ZERO : IResource.DEPTH_INFINITE); |
| } |
| } |
| |
| private boolean isTimeout(Throwable e) { |
| if (e == null) { |
| return false; |
| } |
| |
| if (e instanceof InterruptedIOException |
| && e.getMessage() != null |
| && e.getMessage().contains("Timeout while writing to output stream")) { |
| return true; |
| } |
| |
| if (e instanceof CoreException) { |
| CoreException ce = (CoreException) e; |
| if (ce.getStatus() != null && ce.getStatus().isMultiStatus()) { |
| MultiStatus multistatus = (MultiStatus) ce.getStatus(); |
| for (int i = 0; i < multistatus.getChildren().length; i++) { |
| if (isTimeout(multistatus.getChildren()[i].getException())) { |
| return true; |
| } |
| } |
| } |
| |
| } |
| |
| return isTimeout(e.getCause()); |
| } |
| |
| public void testUpdate() throws Exception { |
| try{ |
| // Create a test project, import it into cvs and check it out |
| IProject project = createProject("testUpdate", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| |
| // Check the project out under a different name |
| IProject copy = checkoutCopy(project, "-copy"); |
| |
| // Perform some operations on the copy and commit them all |
| addResources(copy, new String[] { "added.txt", "folder2/", "folder2/added.txt" }, false); |
| setContentsAndEnsureModified(copy.getFile("changed.txt")); |
| deleteResources(new IResource[] {copy.getFile("deleted.txt")}); |
| setContentsAndEnsureModified(copy.getFile("folder1/a.txt")); |
| setContentsAndEnsureModified(copy.getFile("folder1/subfolder1/c.txt")); |
| commit(asResourceMapping(new IResource[] { copy }, IResource.DEPTH_INFINITE), "A commit message"); |
| |
| // Update the project using depth one and ensure we got only what was asked for |
| update(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE), null); |
| |
| // Update a subfolder using depth one and ensure we got only what was asked for |
| update(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE), null); |
| |
| // Update the specific file |
| update(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO), null); |
| |
| // Update the remaining resources |
| update(asResourceMapping(new IResource[] { project.getFolder("folder2") }, IResource.DEPTH_INFINITE), null); |
| assertEquals(project, copy); |
| } catch (Exception e) { |
| if (isTimeout(e)) { |
| //TODO see Bug 399375 |
| System.err.println("Timeout while testUpdate"); |
| e.printStackTrace(); |
| return; |
| } |
| throw e; |
| } |
| } |
| |
| public void testReplace() throws Exception { |
| try{ |
| // Create a test project, import it into cvs and check it out |
| IProject project = createProject("testReplace", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| |
| // Check the project out under a different name |
| IProject copy = checkoutCopy(project, "-copy"); |
| |
| // Perform some operations on the copy and commit them all |
| addResources(copy, new String[] { "added.txt", "folder2/", "folder2/added.txt" }, false); |
| setContentsAndEnsureModified(copy.getFile("changed.txt")); |
| deleteResources(new IResource[] {copy.getFile("deleted.txt")}); |
| setContentsAndEnsureModified(copy.getFile("folder1/a.txt")); |
| setContentsAndEnsureModified(copy.getFile("folder1/subfolder1/c.txt")); |
| commit(asResourceMapping(new IResource[] { copy }, IResource.DEPTH_INFINITE), "A commit message"); |
| |
| // Update the project using depth one and ensure we got only what was asked for |
| replace(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE)); |
| |
| // Update a subfolder using depth one and ensure we got only what was asked for |
| deleteResources(new IResource[] {project.getFile("folder1/b.txt")}); |
| replace(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE)); |
| |
| // Update the specific file |
| replace(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO)); |
| |
| // Update the remaining resources |
| replace(asResourceMapping(new IResource[] { project.getFolder("folder2") }, IResource.DEPTH_INFINITE)); |
| assertEquals(project, copy); |
| } catch (Exception e) { |
| if (isTimeout(e)) { |
| //TODO see Bug 399375 |
| System.err.println("Timeout while testReplace"); |
| e.printStackTrace(); |
| return; |
| } |
| throw e; |
| } |
| } |
| |
| public void testCommit() throws Exception { |
| if (TeamCVSTestPlugin.IS_UNSTABLE_TEST && Util.isMac()) |
| return; |
| |
| // Create a test project, import it into cvs and check it out |
| IProject project = createProject("testCommit", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| |
| // Perform some operations on the copy and commit only the top level |
| addResources(project, new String[] { "added.txt", "folder2/", "folder2/added.txt" }, false); |
| setContentsAndEnsureModified(project.getFile("changed.txt")); |
| deleteResources(new IResource[] {project.getFile("deleted.txt")}); |
| setContentsAndEnsureModified(project.getFile("folder1/a.txt")); |
| setContentsAndEnsureModified(project.getFile("folder1/subfolder1/c.txt")); |
| |
| // Commit the project shallow |
| commit(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE), "A commit message"); |
| |
| // Commit a subfolder shallow |
| commit(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE), "A commit message"); |
| |
| // Now commit the file specifically |
| commit(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO), "A commit message"); |
| |
| // Now commit the rest |
| commit(asResourceMapping(new IResource[] { project.getFolder("folder2") }, IResource.DEPTH_INFINITE), "A commit message"); |
| |
| // Check the project out under a different name |
| IProject copy = checkoutCopy(project, "-copy"); |
| assertEquals(project, copy); |
| } |
| |
| public void testTag() throws Exception { |
| // Create a test project, import it into cvs and check it out |
| IProject project = createProject("testTag", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| |
| tag(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE), new CVSTag("v1", CVSTag.VERSION)); |
| tag(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE), new CVSTag("v2", CVSTag.VERSION)); |
| tag(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO), new CVSTag("v3", CVSTag.VERSION)); |
| tag(asResourceMapping(new IResource[] { project}, IResource.DEPTH_INFINITE), new CVSTag("v4", CVSTag.VERSION)); |
| } |
| |
| public void testBranch() throws Exception { |
| |
| if (TeamCVSTestPlugin.IS_UNSTABLE_TEST) |
| return; |
| |
| // Create a test project, import it into cvs and check it out |
| IProject project = createProject("testBranch", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| |
| branch(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE), new CVSTag("b1", CVSTag.BRANCH)); |
| branch(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE), new CVSTag("b2", CVSTag.BRANCH)); |
| branch(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO), new CVSTag("b3", CVSTag.BRANCH)); |
| branch(asResourceMapping(new IResource[] { project }, IResource.DEPTH_INFINITE), new CVSTag("b4", CVSTag.BRANCH)); |
| } |
| |
| public void testAdd() throws TeamException, CoreException { |
| // Create an empty project |
| IProject project = createProject("testAdd", new String[] { }); |
| // add some resources |
| buildResources(project, new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }, false); |
| // add them to CVS |
| add(asResourceMapping(new IResource[] { project }, IResource.DEPTH_ONE)); |
| add(asResourceMapping(new IResource[] { project.getFolder("folder1") }, IResource.DEPTH_ONE)); |
| add(asResourceMapping(new IResource[] { project.getFile("folder1/subfolder1/c.txt") }, IResource.DEPTH_ZERO)); |
| add(asResourceMapping(new IResource[] { project }, IResource.DEPTH_INFINITE)); |
| } |
| |
| public void testCacheBase() throws TeamException, CoreException { |
| if (TeamCVSTestPlugin.IS_UNSTABLE_TEST && Util.isMac()) |
| return; |
| |
| IProject project = createProject("testCacheBase", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| IProject copy = checkoutCopy(project, "-copy"); |
| |
| // First, make some local changes and then cache the bases |
| setContentsAndEnsureModified(project.getFile("changed.txt"), "Uncommitted text"); |
| setContentsAndEnsureModified(project.getFile("folder1/b.txt")); |
| project.getFile("deleted.txt").delete(false, true, null); |
| try { |
| cacheBase(project, true /* cache for outgoing and conflicting */); |
| cacheBase(project, false /* cache for conflicting only*/); |
| |
| // Next, retry after releasing some changes (to ensure proper contents are fetched) |
| setContentsAndEnsureModified(copy.getFile("changed.txt"), "Text comited from the copy"); |
| commitProject(copy); |
| cacheBase(project, true /* cache for outgoing and conflicting */); |
| cacheBase(project, false /* cache for conflicting only */); |
| } catch (TeamException e) { |
| // see bug 325553 |
| logIfCausedByInterruptedIOException(e); |
| } |
| } |
| |
| private void logIfCausedByInterruptedIOException(TeamException e) |
| throws TeamException { |
| IStatus status = e.getStatus(); |
| if (status.isMultiStatus()) { |
| MultiStatus mstatus = (MultiStatus) status; |
| status = mstatus.getChildren()[0]; |
| if (status instanceof TeamStatus) { |
| Throwable ex = status.getException(); |
| if (ex instanceof CVSCommunicationException) { |
| CVSCommunicationException cce = (CVSCommunicationException) ex; |
| status = cce.getStatus(); |
| if (status.isMultiStatus()) { |
| if (status.getException() instanceof InterruptedIOException) { |
| // Prevent the test from failing but log the exception |
| log("org.eclipse.team.tests.cvs.core", e.getStatus()); |
| return; |
| } |
| } |
| } |
| } |
| } |
| throw e; |
| } |
| |
| public void testCacheRemote() throws TeamException, CoreException { |
| IProject project = createProject("testCacheRemote", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder1/subfolder1/c.txt" }); |
| IProject copy = checkoutCopy(project, "-copy"); |
| |
| // Make some remote changes |
| setContentsAndEnsureModified(copy.getFile("changed.txt"), "Uncommitted text"); |
| setContentsAndEnsureModified(copy.getFile("folder1/b.txt")); |
| commitProject(copy); |
| // Delete a local file |
| project.getFile("deleted.txt").delete(false, true, null); |
| cacheRemote(project); |
| } |
| |
| private void cacheRemote(IProject project) throws CoreException { |
| clearCache(project); |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().refresh(new IProject[] { project }, IResource.DEPTH_INFINITE, DEFAULT_MONITOR); |
| IResourceDiffTree tree = getAllDiffs(new IProject[] { project }); |
| ResourceMapping[] mappings = new ResourceMapping[] {new SimpleResourceMapping(project)}; |
| CacheRemoteContentsOperation op = new CacheRemoteContentsOperation(null, mappings, tree); |
| executeHeadless(op); |
| ensureRemoteCached(tree); |
| } |
| |
| private void cacheBase(IProject project, boolean includeOutgoing) throws CoreException { |
| clearCache(project); |
| CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().refresh(new IProject[] { project }, IResource.DEPTH_INFINITE, DEFAULT_MONITOR); |
| IResourceDiffTree tree = getAllDiffs(new IProject[] { project }); |
| ResourceMapping[] mappings = new ResourceMapping[] {new SimpleResourceMapping(project)}; |
| CacheBaseContentsOperation op = new CacheBaseContentsOperation(null, mappings, tree, includeOutgoing); |
| executeHeadless(op); |
| ensureBaseCached(tree, includeOutgoing); |
| } |
| |
| private void ensureRemoteCached(IResourceDiffTree tree) { |
| IResource[] resources = tree.getAffectedResources(); |
| for (IResource resource : resources) { |
| IDiff node = tree.getDiff(resource); |
| if (node instanceof IThreeWayDiff) { |
| IThreeWayDiff twd = (IThreeWayDiff) node; |
| IResourceVariant remote = SyncInfoToDiffConverter.getRemoteVariant(twd); |
| if (remote != null) { |
| boolean isCached = ((CachedResourceVariant)remote).isContentsCached(); |
| int direction = twd.getDirection(); |
| if (direction == IThreeWayDiff.CONFLICTING || direction == IThreeWayDiff.INCOMING) { |
| assertTrue(NLS.bind("The remote contents should be cached for {0}", new String[] {resource.getFullPath().toString()}), isCached); |
| } else { |
| assertFalse(NLS.bind("The base contents should NOT be cached for {0}", new String[] {resource.getFullPath().toString()}), isCached); |
| } |
| } |
| } |
| } |
| } |
| |
| private void ensureBaseCached(IResourceDiffTree tree, boolean includeOutgoing) throws TeamException, CoreException { |
| IResource[] resources = tree.getAffectedResources(); |
| for (IResource resource : resources) { |
| IDiff node = tree.getDiff(resource); |
| if (node instanceof IThreeWayDiff) { |
| IThreeWayDiff twd = (IThreeWayDiff) node; |
| IResourceVariant base = SyncInfoToDiffConverter.getBaseVariant(twd); |
| if (base != null) { |
| boolean isCached = ((CachedResourceVariant)base).isContentsCached(); |
| int direction = twd.getDirection(); |
| if (direction == IThreeWayDiff.CONFLICTING || (includeOutgoing && direction == IThreeWayDiff.OUTGOING)) { |
| assertTrue(NLS.bind("The base contents should be cached for {0}", new String[] {resource.getFullPath().toString()}), isCached); |
| // For conflicts, ensure that the cache contents do not match the remote |
| if (direction == SyncInfo.CONFLICTING) { |
| IResourceVariant remote = SyncInfoToDiffConverter.getRemoteVariant(twd); |
| if (remote != null) { |
| InputStream baseIn = base.getStorage(DEFAULT_MONITOR).getContents(); |
| if (baseIn == null) { |
| fail(NLS.bind("Base was not fetched for {0}", new String[] {resource.getFullPath().toString()})); |
| } |
| InputStream remoteIn = remote.getStorage(DEFAULT_MONITOR).getContents(); |
| if (compareContent(baseIn, remoteIn)) { |
| fail(NLS.bind("The remote was fetched instead of the base for {0}", new String[] {resource.getFullPath().toString()})); |
| } |
| } |
| } |
| } else { |
| // assertFalse(NLS.bind("The base contents should NOT be cached for {0}", new String[] {resource.getFullPath().toString()}), isCached); |
| } |
| } |
| } |
| } |
| } |
| |
| private void clearCache(IProject project) { |
| ResourceVariantCache cache = ResourceVariantCache.getCache(CVSProviderPlugin.ID); |
| if (cache != null) { |
| ResourceVariantCacheEntry[] entries = cache.getEntries(); |
| for (ResourceVariantCacheEntry entry : entries) { |
| entry.dispose(); |
| } |
| } |
| } |
| |
| public void testBug134517() throws Exception { |
| IProject project = createProject("testBug134517", new String[] { "file1.txt", "file2.txt"}); |
| IProject copy = checkoutCopy(project, "-copy"); |
| addResources(copy, new String[] { "file0.txt", |
| "new_folder1/", "new_folder1/file2.txt", "new_folder1/new_folder2/", |
| "new_folder1/new_folder2/new_folder3/", "new_folder1/new_folder2/new_folder3/file3.txt" }, true); |
| IResource[] resources = new IResource[] { |
| project.getFile("file0.txt"), |
| project.getFile("file1.txt"), |
| project.getFile("new_folder1/file2.txt"), |
| project.getFile("new_folder1/new_folder2/new_folder3/file3.txt") |
| }; |
| update(asResourceMapping(resources, IResource.DEPTH_ZERO), null); |
| assertEquals(project, copy); |
| } |
| |
| public void testDeepNewFolder() throws Exception { |
| IProject project = createProject("testBug134517", new String[] { "file1.txt", "file2.txt"}); |
| IProject copy = checkoutCopy(project, "-copy"); |
| addResources(copy, new String[] { |
| "new_folder1/", |
| "new_folder1/new_folder2/", |
| "new_folder1/new_folder2/new_folder3/", |
| "new_folder1/new_folder2/new_folder3/file3.txt" }, true); |
| IResource[] resources = new IResource[] { |
| project.getFolder("new_folder1/new_folder2/new_folder3/") |
| }; |
| update(asResourceMapping(resources, IResource.DEPTH_INFINITE), null); |
| assertEquals(project, copy); |
| } |
| } |