/** * <copyright> Copyright (c) 2008-2009 Jonas Helming, Maximilian Koegel. 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 </copyright> */ package org.eclipse.emf.emfstore.client.test.conflictDetection; import static org.junit.Assert.assertEquals; import java.util.List; import java.util.Set; import org.eclipse.emf.emfstore.client.model.ProjectSpace; import org.eclipse.emf.emfstore.client.model.util.EMFStoreCommand; import org.eclipse.emf.emfstore.client.test.model.bug.BugFactory; import org.eclipse.emf.emfstore.client.test.model.bug.BugReport; import org.eclipse.emf.emfstore.client.test.model.document.DocumentFactory; import org.eclipse.emf.emfstore.client.test.model.document.LeafSection; import org.eclipse.emf.emfstore.client.test.model.requirement.Actor; import org.eclipse.emf.emfstore.client.test.model.requirement.RequirementFactory; import org.eclipse.emf.emfstore.client.test.model.requirement.UseCase; import org.eclipse.emf.emfstore.client.test.model.task.Milestone; import org.eclipse.emf.emfstore.client.test.model.task.TaskFactory; import org.eclipse.emf.emfstore.client.test.model.task.WorkPackage; import org.eclipse.emf.emfstore.common.model.ModelElementId; import org.eclipse.emf.emfstore.common.model.Project; import org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetector; import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation; import org.junit.Test; /** * Tests conflict detection behaviour on attributes. * * @author chodnick */ public class ConflictDetectionDeleteTest extends ConflictDetectionTest { /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDelete() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final Actor actor = RequirementFactory.eINSTANCE.createActor(); actor.setName("old name"); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); section.getModelElements().add(actor); getProjectSpace().getOperations().clear(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); Project project2 = ps2.getProject(); ModelElementId actorId = getProject().getModelElementId(actor); final Actor actor1 = (Actor) getProject().getModelElement(actorId); final Actor actor2 = (Actor) project2.getModelElement(actorId); new EMFStoreCommand() { @Override protected void doRun() { getProject().deleteModelElement(actor1); actor2.setName("change to the deleted object on another working copy"); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); assertEquals(conflicts.size(), 1); } /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDeleteAttributeChangesInDeltree() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final Actor actor = RequirementFactory.eINSTANCE.createActor(); actor.setName("old name"); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); section.getModelElements().add(actor); getProjectSpace().getOperations().clear(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); Project project2 = ps2.getProject(); ModelElementId section1Id = getProject().getModelElementId(section); ModelElementId actorId = getProject().getModelElementId(actor); final LeafSection section1 = (LeafSection) getProject().getModelElement(section1Id); final Actor actor2 = (Actor) project2.getModelElement(actorId); new EMFStoreCommand() { @Override protected void doRun() { getProject().deleteModelElement(section1); actor2.setName("change to object inside deltree on another working copy"); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); assertEquals(conflicts.size(), 1); } /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDeleteAttributeChangesInDelObject() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); getProjectSpace().getOperations().clear(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); Project project2 = ps2.getProject(); ModelElementId sectionId = getProject().getModelElementId(section); final LeafSection section1 = (LeafSection) getProject().getModelElement(sectionId); final LeafSection section2 = (LeafSection) project2.getModelElement(sectionId); new EMFStoreCommand() { @Override protected void doRun() { getProject().deleteModelElement(section1); section2.setName("change to object inside deltree on another working copy"); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); assertEquals(conflicts.size(), 1); } /** * Tests if deleting an object is detected as conflict. */ @Test public void noConflictDeleteUnrelated() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final Actor actor = RequirementFactory.eINSTANCE.createActor(); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); getProject().addModelElement(actor); getProjectSpace().getOperations().clear(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); final Project project2 = ps2.getProject(); ModelElementId actorId = getProject().getModelElementId(actor); ModelElementId sectionId = getProject().getModelElementId(section); final Actor actor1 = (Actor) getProject().getModelElement(actorId); final LeafSection section2 = (LeafSection) project2.getModelElement(sectionId); new EMFStoreCommand() { @Override protected void doRun() { actor1.setName("change to unrelated object on another working copy"); project2.deleteModelElement(section2); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); assertEquals(conflicts.size(), 0); } /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDeleteContainmentChangesInDeltree() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final WorkPackage pack = TaskFactory.eINSTANCE.createWorkPackage(); final BugReport br = BugFactory.eINSTANCE.createBugReport(); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); getProject().addModelElement(pack); getProject().addModelElement(br); section.getModelElements().add(pack); clearOperations(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); final Project project2 = ps2.getProject(); ModelElementId brId = getProject().getModelElementId(br); ModelElementId packId = getProject().getModelElementId(pack); ModelElementId sectionId = getProject().getModelElementId(section); final BugReport br1 = (BugReport) getProject().getModelElement(brId); final WorkPackage pack1 = (WorkPackage) getProject().getModelElement(packId); final LeafSection section2 = (LeafSection) project2.getModelElement(sectionId); new EMFStoreCommand() { @Override protected void doRun() { br1.setContainingWorkpackage(pack1); project2.deleteModelElement(section2); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); assertEquals(conflicts.size(), 1); } /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDeleteNonContainmentChangesInDeltree() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final UseCase useCase = RequirementFactory.eINSTANCE.createUseCase(); final Milestone mileStone = TaskFactory.eINSTANCE.createMilestone(); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); getProject().addModelElement(useCase); getProject().addModelElement(mileStone); section.getModelElements().add(useCase); clearOperations(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); final Project project2 = ps2.getProject(); ModelElementId mileStoneId = getProject().getModelElementId(mileStone); ModelElementId useCaseId = getProject().getModelElementId(useCase); ModelElementId sectionId = getProject().getModelElementId(section); final Milestone mileStone1 = (Milestone) getProject().getModelElement(mileStoneId); final UseCase useCase1 = (UseCase) getProject().getModelElement(useCaseId); final LeafSection section2 = (LeafSection) project2.getModelElement(sectionId); new EMFStoreCommand() { @Override protected void doRun() { useCase1.getAnnotations().add(mileStone1); project2.deleteModelElement(section2); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); // technically no conflict, since annotated milestone will not be deleted, // but there is no way to tell containment from non-containment changes, // therefore it is expected that this will be detected as a hard conflict assertEquals(conflicts.size(), 1); } /** * Tests if deleting an object is detected as conflict. */ @Test public void conflictDeleteMoveChangesInDeltree() { final LeafSection section = DocumentFactory.eINSTANCE.createLeafSection(); final WorkPackage pack = TaskFactory.eINSTANCE.createWorkPackage(); final BugReport br1 = BugFactory.eINSTANCE.createBugReport(); final BugReport br2 = BugFactory.eINSTANCE.createBugReport(); new EMFStoreCommand() { @Override protected void doRun() { getProject().addModelElement(section); getProject().addModelElement(pack); getProject().addModelElement(br1); br1.setContainingWorkpackage(pack); br2.setContainingWorkpackage(pack); } }.run(false); assertEquals(pack.getContainedWorkItems().get(0), br1); assertEquals(pack.getContainedWorkItems().get(1), br2); new EMFStoreCommand() { @Override protected void doRun() { section.getModelElements().add(pack); clearOperations(); } }.run(false); ProjectSpace ps2 = cloneProjectSpace(getProjectSpace()); final Project project2 = ps2.getProject(); ModelElementId packId = getProject().getModelElementId(pack); ModelElementId sectionId = getProject().getModelElementId(section); final WorkPackage pack1 = (WorkPackage) getProject().getModelElement(packId); final LeafSection section2 = (LeafSection) project2.getModelElement(sectionId); new EMFStoreCommand() { @Override protected void doRun() { pack1.getContainedWorkItems().move(1, 0); project2.deleteModelElement(section2); } }.run(false); List<AbstractOperation> ops1 = getProjectSpace().getLocalOperations().getOperations(); List<AbstractOperation> ops2 = ps2.getLocalOperations().getOperations(); ConflictDetector cd = new ConflictDetector(getConflictDetectionStrategy()); Set<AbstractOperation> conflicts = cd.getConflicting(ops1, ops2); assertEquals(cd.getConflicting(ops1, ops2).size(), cd.getConflicting(ops2, ops1).size()); // a move change is a change... from users perspective it should not be lost, probably.. // currently considered to be a hard conflict, because the user should know assertEquals(1, conflicts.size()); } }