diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_400311b_Test.java')
-rw-r--r-- | plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_400311b_Test.java | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_400311b_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_400311b_Test.java new file mode 100644 index 0000000000..c9f3da8b3d --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_400311b_Test.java @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2014 Eike Stepper (Berlin, Germany) 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: + * Alex Lagarde - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.CDOObject; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionManager; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.common.branch.CDOBranchVersionImpl; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IModelConfig; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.VAT; +import org.eclipse.emf.cdo.tests.model6.BaseObject; +import org.eclipse.emf.cdo.tests.model6.ContainmentObject; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; + +import java.util.LinkedList; +import java.util.List; + +/** + * Bug 400311 - CDOObject modifies Store even for Touch notifications. + * + * @author Alex Lagarde + */ +public class Bugzilla_400311b_Test extends AbstractCDOTest +{ + private CDOSession session; + + private CDOTransaction transaction; + + private OrderDetail orderDetail1; + + private OrderDetail orderDetail2; + + private Product1 product1; + + private Product1 product2; + + private ContainmentObject containmentObject; + + private BaseObject childObject; + + private int orderDetail1InitialVersion; + + private int product1InitialVersion; + + private int containmentObjectInitialVersion; + + private int childObjectInitialVersion; + + private CDOResource resource; + + @Override + protected void doSetUp() throws Exception + { + super.doSetUp(); + session = openSession(); + transaction = session.openTransaction(); + + orderDetail1 = getModel1Factory().createOrderDetail(); + orderDetail2 = getModel1Factory().createOrderDetail(); + product1 = getModel1Factory().createProduct1(); + product2 = getModel1Factory().createProduct1(); + orderDetail1.setProduct(product1); + product1.getOrderDetails().add(orderDetail1); + product1.getOrderDetails().add(orderDetail2); + product1.setVat(VAT.VAT0); + product1.getOtherVATs().add(VAT.VAT7); + product1.getOtherVATs().add(VAT.VAT15); + containmentObject = getModel6Factory().createContainmentObject(); + containmentObject.getAttributeList().add("attr1"); + containmentObject.getAttributeList().add("attr2"); + childObject = getModel6Factory().createBaseObject(); + containmentObject.getContainmentList().add(childObject); + + resource = transaction.createResource(getResourcePath("/test")); + resource.getContents().add(orderDetail1); + resource.getContents().add(orderDetail2); + resource.getContents().add(product1); + resource.getContents().add(product2); + resource.getContents().add(containmentObject); + + transaction.commit(); + + orderDetail1InitialVersion = CDOUtil.getCDOObject(orderDetail1).cdoRevision().getVersion(); + product1InitialVersion = CDOUtil.getCDOObject(product1).cdoRevision().getVersion(); + containmentObjectInitialVersion = CDOUtil.getCDOObject(containmentObject).cdoRevision().getVersion(); + childObjectInitialVersion = CDOUtil.getCDOObject(childObject).cdoRevision().getVersion(); + } + + @Override + protected void doTearDown() throws Exception + { + // Check that the server never contains 2 adjacent identical revisions + for (EObject element : resource.getContents()) + { + CDOID elementID = CDOUtil.getCDOObject(element).cdoID(); + assertServerDoesNotContainIdenticalAdjacentRevision(elementID, transaction); + } + + transaction.close(); + session.close(); + + super.doTearDown(); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnSingleValuedReference() throws Exception + { + // Step 1: Make touch modification + orderDetail1.setProduct(product1); + assertVersion(orderDetail1InitialVersion, orderDetail1); + + // Step 2: Commit + transaction.commit(); + assertVersion(orderDetail1InitialVersion, orderDetail1); + + // Step 3: make non touch modification + orderDetail1.setProduct(null); + assertDirty(orderDetail1, transaction); + transaction.commit(); + assertVersionIncreased(orderDetail1InitialVersion, orderDetail1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedReference() throws Exception + { + // Step 1: Make touch modification + product1.getOrderDetails().add(orderDetail1); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.getOrderDetails().remove(orderDetail1); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedReferenceMove() throws Exception + { + // Step 1: Make touch modification + product1.getOrderDetails().move(0, orderDetail1); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.getOrderDetails().remove(orderDetail1); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnSingleValuedAttribute() throws Exception + { + // Step 1: Make touch modification + product1.setName(product1.getName()); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.setName(product1.getName() + "-MODIFIED"); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedAttribute() throws Exception + { + // Step 1: Make touch modification + containmentObject.getAttributeList().add("attr2"); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 2: Commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: make non touch modification + containmentObject.getAttributeList().remove("attr2"); + assertDirty(containmentObject, transaction); + transaction.commit(); + assertVersionIncreased(containmentObjectInitialVersion, containmentObject); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedAttributeMove() throws Exception + { + // Step 1: Make touch modification + containmentObject.getAttributeList().move(1, "attr2"); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 2: Commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: make non touch modification + containmentObject.getAttributeList().move(0, "attr2"); + assertDirty(containmentObject, transaction); + transaction.commit(); + assertVersionIncreased(containmentObjectInitialVersion, containmentObject); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnSingleValuedEnum() throws Exception + { + // Step 1: Make touch modification + product1.setVat(VAT.VAT0); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.setVat(VAT.VAT7); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedEnum() throws Exception + { + // Step 1: Make touch modification + product1.getOtherVATs().add(VAT.VAT7); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.getOtherVATs().remove(VAT.VAT7); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testTouchModificationDoNotMakeObjectsDirtyOnMultiValuedEnumMove() throws Exception + { + // Step 1: Make touch modification + product1.getOtherVATs().move(0, VAT.VAT7); + assertVersion(product1InitialVersion, product1); + + // Step 2: Commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + + // Step 3: make non touch modification + product1.getOtherVATs().move(1, VAT.VAT7); + assertDirty(product1, transaction); + transaction.commit(); + assertVersionIncreased(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnSingleValuedReference() throws Exception + { + // Step 1: make modification + orderDetail1.setProduct(product2); + assertDirty(orderDetail1, transaction); + + // Step 2: get back to initial clean state + product1.getOrderDetails().add(0, orderDetail1); + assertVersion(orderDetail1InitialVersion, orderDetail1); + + // Step 3: commit + transaction.commit(); + assertVersion(orderDetail1InitialVersion, orderDetail1); + } + + public void testUndoRevertsToCleanStateOnMultiValuedReference() throws Exception + { + // Step 1: make modification + product1.getOrderDetails().remove(orderDetail1); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.getOrderDetails().add(0, orderDetail1); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnMultiValuedReferenceMove() throws Exception + { + // Step 1: make modification + int oldIndex = product1.getOrderDetails().indexOf(orderDetail1); + product1.getOrderDetails().move(1, orderDetail1); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.getOrderDetails().move(oldIndex, orderDetail1); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnSingleValuedAttribute() throws Exception + { + // Step 1: make modification + String initialValue = product1.getName(); + product1.setName("New name"); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.setName(initialValue); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnMultiValuedAttribute() throws Exception + { + // Step 1: make modification + containmentObject.getAttributeList().add("attr3"); + assertDirty(containmentObject, transaction); + + // Step 2: get back to initial clean state + containmentObject.getAttributeList().remove("attr3"); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + } + + public void testUndoRevertsToCleanStateOnMultiValuedAttributeMove() throws Exception + { + // Step 1: make modification + int oldIndex = containmentObject.getAttributeList().indexOf("attr2"); + containmentObject.getAttributeList().move(0, "attr2"); + assertDirty(containmentObject, transaction); + + // Step 2: get back to initial clean state + containmentObject.getAttributeList().move(oldIndex, "attr2"); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + } + + public void testUndoRevertsToCleanStateOnSingleValuedEnum() throws Exception + { + // Step 1: make modification + product1.setVat(VAT.VAT7); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.setVat(VAT.VAT0); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnMultiValuedEnum() throws Exception + { + // Step 1: make modification + product1.getOtherVATs().add(VAT.VAT0); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.getOtherVATs().remove(VAT.VAT0); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnMultiValuedEnumMove() throws Exception + { + // Step 1: make modification + int oldIndex = product1.getOtherVATs().indexOf(VAT.VAT7); + product1.getOtherVATs().move(1, VAT.VAT7); + assertDirty(product1, transaction); + + // Step 2: get back to initial clean state + product1.getOtherVATs().move(oldIndex, VAT.VAT7); + assertVersion(product1InitialVersion, product1); + + // Step 3: commit + transaction.commit(); + assertVersion(product1InitialVersion, product1); + } + + public void testUndoRevertsToCleanStateOnObjectCreation() throws Exception + { + EList<BaseObject> containmentList = containmentObject.getContainmentList(); + + // Step 1: create a new object + BaseObject newObject = getModel6Factory().createBaseObject(); + containmentList.add(newObject); + assertDirty(containmentObject, transaction); + + // Step 2: delete the created object + containmentList.remove(newObject); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + } + + /** + * CDOLegacyAdapter creates (bogus?) CONTAINER deltas that aren't detected. + */ + @Skips(IModelConfig.CAPABILITY_LEGACY) + public void testUndoRevertsToCleanStateOnObjectDeletion() throws Exception + { + CDOID elementToDeleteID = CDOUtil.getCDOObject(childObject).cdoID(); + EList<BaseObject> containmentList = containmentObject.getContainmentList(); + + // For better debugging: + // Map<InternalCDOObject, InternalCDORevision> cleanRevisions = ((InternalCDOTransaction)transaction) + // .getCleanRevisions(); + // CDOSavepoint savepoint = transaction.getLastSavepoint(); + // Collection<CDORevisionDelta> revisionDeltas = savepoint.getRevisionDeltas2().values(); + + // Step 1: delete object + containmentList.remove(childObject); + assertDirty(containmentObject, transaction); + assertEquals("Element should be detached", true, transaction.getDetachedObjects().containsKey(elementToDeleteID)); + + // Step 2: undo deletion + containmentList.add(childObject); + assertVersion(containmentObjectInitialVersion, containmentObject); + assertVersion(childObjectInitialVersion, childObject); + assertEquals("Element should not be detached", false, + transaction.getDetachedObjects().containsKey(elementToDeleteID)); + + // Step 3: commit + transaction.commit(); + assertVersion(containmentObjectInitialVersion, containmentObject); + assertVersion(childObjectInitialVersion, childObject); + } + + /** + * CDOLegacyAdapter creates (bogus?) CONTAINER deltas that aren't detected. + */ + @Skips(IModelConfig.CAPABILITY_LEGACY) + public void testUndoRevertsToCleanStateOnComplexModifications() throws Exception + { + String oldContainmentObjectAttributeValue = containmentObject.getAttributeOptional(); + CDOID elementToDeleteID = CDOUtil.getCDOObject(childObject).cdoID(); + EList<BaseObject> containmentList = containmentObject.getContainmentList(); + + // Step 1: make several modifications (modifying several features on the same object and several objects) + containmentList.remove(childObject); + BaseObject newObject = getModel6Factory().createBaseObject(); + containmentList.add(newObject); + containmentObject.setAttributeOptional("MODIFIED"); + + String oldProduct1Name = product1.getName(); + product1.setName("New name"); + int oldVATIndexForProduct1 = product1.getOtherVATs().indexOf(VAT.VAT7); + product1.getOtherVATs().move(1, VAT.VAT7); + + orderDetail1.setProduct(product2); + + // Check that all modified objects are dirty/detached + assertDirty(containmentObject, transaction); + assertDirty(product1, transaction); + assertDirty(orderDetail1, transaction); + assertEquals("Element should be detached", true, transaction.getDetachedObjects().containsKey(elementToDeleteID)); + + // Step 2: get back to initial clean state step by step + product1.getOrderDetails().add(0, orderDetail1); + assertVersion(orderDetail1InitialVersion, orderDetail1, true); + + product1.getOtherVATs().move(oldVATIndexForProduct1, VAT.VAT7); + assertDirty(product1, transaction); + + product1.setName(oldProduct1Name); + assertVersion(product1InitialVersion, product1, true); + + containmentList.add(childObject); + assertDirty(containmentObject, transaction); + + containmentList.remove(newObject); + assertDirty(containmentObject, transaction); + + containmentObject.setAttributeOptional(oldContainmentObjectAttributeValue); + assertVersion(containmentObjectInitialVersion, containmentObject); + + // Step 3: commit + transaction.commit(); + assertVersion(orderDetail1InitialVersion, orderDetail1); + assertVersion(product1InitialVersion, product1); + assertVersion(containmentObjectInitialVersion, containmentObject); + } + + /** + * Ensures that the given object is clean and that its version was not increased compared to the given initial version. + * @param initalVersion the initial version of the object before it was modified + * @param element the EObject to test + */ + private void assertVersion(int expectedVersion, EObject element) + { + assertVersion(expectedVersion, element, false); + } + + private void assertVersion(int expectedVersion, EObject element, boolean expectedDirtyTransaction) + { + CDOObject cdoElement = CDOUtil.getCDOObject(element); + assertClean(cdoElement, ((CDOResource)cdoElement.eResource()).cdoView()); + assertEquals(expectedVersion, cdoElement.cdoRevision().getVersion()); + assertEquals("Transaction is not expected to contain revision deltas on the given object", null, transaction + .getRevisionDeltas().get(cdoElement.cdoID())); + + if (expectedDirtyTransaction) + { + assertNotSame("Transaction is expected to contain revision deltas", CDOIDUtil.createMap(), + transaction.getRevisionDeltas()); + } + else + { + assertEquals("Transaction is not expected to contain revision deltas", CDOIDUtil.createMap(), + transaction.getRevisionDeltas()); + } + + assertEquals("Transaction is expected to be " + (expectedDirtyTransaction ? "dirty" : "clean"), + expectedDirtyTransaction, transaction.isDirty()); + } + + /** + * Ensures that the given object is dirty and that its version was increased compared to the given initial version. + * @param initalVersion the initial version of the object before it was modified + * @param element the EObject to test + */ + private static void assertVersionIncreased(int initialVersion, EObject element) + { + CDOObject cdoElement = CDOUtil.getCDOObject(element); + assertEquals(initialVersion + 1, cdoElement.cdoRevision().getVersion()); + } + + /** + * Ensures that the CDOServer does not contain 2 identical Adjacent revisions. + */ + private static void assertServerDoesNotContainIdenticalAdjacentRevision(CDOID targetElement, + CDOTransaction transaction) + { + // Step 1: get all revisions for the given ID through the revision manager + CDORevisionManager revisionManager = transaction.getSession().getRevisionManager(); + int initialChunkSize = transaction.getSession().options().getCollectionLoadingPolicy().getInitialChunkSize(); + + int version = CDOBranchVersion.FIRST_VERSION; + List<CDORevision> revisions = new LinkedList<CDORevision>(); + + boolean noMoreRevisionsAvailable = false; + while (!noMoreRevisionsAvailable) + { + CDOBranchVersion branchVersion = new CDOBranchVersionImpl(transaction.getBranch(), version); + if (revisionManager.containsRevisionByVersion(targetElement, branchVersion)) + { + CDORevision fetched = revisionManager + .getRevisionByVersion(targetElement, branchVersion, initialChunkSize, true); + if (fetched != null) + { + revisions.add(fetched); + } + } + else + { + noMoreRevisionsAvailable = true; + } + + version++; + } + + // Step 2: compare all adjacent revisions and check that there are different + if (revisions.size() > 1) + { + for (int i = 0; i < revisions.size() - 1; i++) + { + CDORevision rev1 = revisions.get(i); + CDORevision rev2 = revisions.get(i + 1); + CDORevisionDelta rDelta = rev1.compare(rev2); + if (rDelta.getFeatureDeltas().size() == 0) + { + // The revision delta contains no feature deltas + // this means the revisions are identical + fail("2 Adjacent Revisions should never be equals."); + } + } + } + } +} |