Author: stefan
Date: Fri Oct 26 15:56:20 2012
New Revision: 1402557
URL: http://svn.apache.org/viewvc?rev=1402557&view=rev
Log:
OAK-407: potential lost update on merge
added more test cases provided by mete
Modified:
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/AbstractMicroKernelIT.java
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
Modified:
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/AbstractMicroKernelIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/AbstractMicroKernelIT.java?rev=1402557&r1=1402556&r2=1402557&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/AbstractMicroKernelIT.java
(original)
+++
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/AbstractMicroKernelIT.java
Fri Oct 26 15:56:20 2012
@@ -34,6 +34,7 @@ import org.junit.runners.Parameterized.P
import static com.google.common.base.Preconditions.checkArgument;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -327,4 +328,65 @@ public abstract class AbstractMicroKerne
}
return val;
}
+
+ protected void assertPropExists(String rev, String path, String property) {
+ String nodes = mk.getNodes(path, rev, -1 /*depth*/, 0 /*offset*/, -1
/*maxChildNodes*/, null /*filter*/);
+ JSONObject obj = parseJSONObject(nodes);
+ assertPropertyExists(obj, property);
+ }
+
+ protected void assertPropNotExists(String rev, String path, String
property) {
+ String nodes = mk.getNodes(path, rev, -1 /*depth*/, 0 /*offset*/, -1
/*maxChildNodes*/, null /*filter*/);
+ if (nodes == null) {
+ return;
+ }
+ JSONObject obj = parseJSONObject(nodes);
+ assertPropertyNotExists(obj, property);
+ }
+
+ protected void assertPropValue(String rev, String path, String property,
String value) {
+ String nodes = mk.getNodes(path, rev, -1 /*depth*/, 0 /*offset*/, -1
/*maxChildNodes*/, null /*filter*/);
+ JSONObject obj = parseJSONObject(nodes);
+ assertPropertyValue(obj, property, value);
+ }
+
+ protected String addNodes(String rev, String...nodes) {
+ String newRev = rev;
+ for (String node : nodes) {
+ newRev = mk.commit("", "+\"" + node + "\":{}", newRev, "");
+ }
+ return newRev;
+ }
+
+ protected String removeNodes(String rev, String...nodes) {
+ String newRev = rev;
+ for (String node : nodes) {
+ newRev = mk.commit("", "-\"" + node + "\"", newRev, "");
+ }
+ return newRev;
+ }
+
+ protected String setProp(String rev, String prop, Object value) {
+ value = value == null? null : "\"" + value + "\"";
+ return mk.commit("", "^\"" + prop + "\" : " + value, rev, "");
+ }
+
+ protected void assertNodesExist(String revision, String...paths) {
+ doAssertNodes(true, revision, paths);
+ }
+
+ protected void assertNodesNotExist(String revision, String...paths) {
+ doAssertNodes(false, revision, paths);
+ }
+
+ protected void doAssertNodes(boolean checkExists, String revision,
String...paths) {
+ for (String path : paths) {
+ boolean exists = mk.nodeExists(path, revision);
+ if (checkExists) {
+ assertTrue(path + " does not exist", exists);
+ } else {
+ assertFalse(path + " should not exist", exists);
+ }
+ }
+ }
}
Modified:
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java?rev=1402557&r1=1402556&r2=1402557&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
(original)
+++
jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
Fri Oct 26 15:56:20 2012
@@ -1025,33 +1025,215 @@ public class MicroKernelIT extends Abstr
}
@Test
- public void branchAndMerge2() {
- // make sure /trunk doesn't exist in head
- assertFalse(mk.nodeExists("/trunk", null));
+ public void oneBranchAddedChildren1() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
- // add a node /trunk in head
- mk.commit("", "+\"/trunk\":{}", null, "");
- // add a node /trunk/child1 in head
- mk.commit("", "+\"/trunk/child1\":{}", null, "");
+ String branchRev = mk.branch(null);
+
+ branchRev = addNodes(branchRev, "/branch1", "/branch1/child1");
+ assertNodesExist(branchRev, "/trunk", "/trunk/child1");
+ assertNodesExist(branchRev, "/branch1", "/branch1/child1");
+ assertNodesNotExist(null, "/branch1", "/branch1/child1");
+
+ addNodes(null, "/trunk/child2");
+ assertNodesExist(null, "/trunk/child2");
+ assertNodesNotExist(branchRev, "/trunk/child2");
+
+ mk.merge(branchRev, "");
+ assertNodesExist(null, "/trunk", "/trunk/child1", "/trunk/child2",
"/branch1", "/branch1/child1");
+ }
+
+ @Test
+ public void oneBranchAddedChildren2() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+
+ String branchRev = mk.branch(null);
+
+ branchRev = addNodes(branchRev, "/trunk/child1/child2");
+ assertNodesExist(branchRev, "/trunk", "/trunk/child1");
+ assertNodesExist(branchRev, "/trunk/child1/child2");
+ assertNodesNotExist(null, "/trunk/child1/child2");
+
+ addNodes(null, "/trunk/child3");
+ assertNodesExist(null, "/trunk/child3");
+ assertNodesNotExist(branchRev, "/trunk/child3");
+
+ mk.merge(branchRev, "");
+ assertNodesExist(null, "/trunk", "/trunk/child1",
"/trunk/child1/child2", "/trunk/child3");
+ }
+
+ @Test
+ public void oneBranchAddedChildren3() {
+ addNodes(null, "/root", "/root/child1");
+ assertNodesExist(null, "/root", "/root/child1");
+
+ String branchRev = mk.branch(null);
+
+ addNodes(null, "/root/child2");
+ assertNodesExist(null, "/root", "/root/child1", "/root/child2");
+ assertNodesExist(branchRev, "/root", "/root/child1");
+ assertNodesNotExist(branchRev, "/root/child2");
+
+ branchRev = addNodes(branchRev, "/root/child1/child3", "/root/child4");
+ assertNodesExist(branchRev, "/root", "/root/child1",
"/root/child1/child3", "/root/child4");
+ assertNodesNotExist(branchRev, "/root/child2");
+ assertNodesExist(null, "/root", "/root/child1", "/root/child2");
+ assertNodesNotExist(null, "/root/child1/child3", "/root/child4");
+
+ mk.merge(branchRev, "");
+ assertNodesExist(null, "/root", "/root/child1", "/root/child2",
+ "/root/child1/child3", "/root/child4");
+ }
+
+ @Test
+ public void oneBranchRemovedChildren() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+
+ String branchRev = mk.branch(null);
+
+ branchRev = removeNodes(branchRev, "/trunk/child1");
+ assertNodesExist(branchRev, "/trunk");
+ assertNodesNotExist(branchRev, "/trunk/child1");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+ }
+
+ @Test
+ public void oneBranchChangedProperties() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ setProp(null, "/trunk/child1/prop1", "value1");
+ setProp(null, "/trunk/child1/prop2", "value2");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+ assertPropExists(null, "/trunk/child1", "prop1");
+ assertPropExists(null, "/trunk/child1", "prop2");
- // create a branch on head
String branchRev = mk.branch(null);
- // add a node /trunk/child1/child2 in branchRev
- branchRev = mk.commit("", "+\"/trunk/child1/child2\":{}", branchRev,
"");
- // add a node /trunk/child3 in head
- mk.commit("", "+\"/trunk/child3\":{}", null, "");
+ branchRev = setProp(branchRev, "/trunk/child1/prop1", "value1a");
+ branchRev = setProp(branchRev, "/trunk/child1/prop2", null);
+ branchRev = setProp(branchRev, "/trunk/child1/prop3", "value3");
+ assertPropValue(branchRev, "/trunk/child1", "prop1", "value1a");
+ assertPropNotExists(branchRev, "/trunk/child1", "prop2");
+ assertPropValue(branchRev, "/trunk/child1", "prop3", "value3");
+ assertPropValue(null, "/trunk/child1", "prop1", "value1");
+ assertPropExists(null, "/trunk/child1", "prop2");
+ assertPropNotExists(null, "/trunk/child1", "prop3");
- // merge branchRev with head
mk.merge(branchRev, "");
+ assertPropValue(null, "/trunk/child1", "prop1", "value1a");
+ assertPropNotExists(null, "/trunk/child1", "prop2");
+ assertPropValue(null, "/trunk/child1", "prop3", "value3");
+ }
+
+ @Test
+ public void oneBranchAddedSubChildren() {
+ addNodes(null, "/trunk", "/trunk/child1", "/trunk/child1/child2",
"/trunk/child1/child2/child3");
+ assertNodesExist(null, "/trunk", "/trunk/child1",
"/trunk/child1/child2", "/trunk/child1/child2/child3");
+
+ String branchRev = mk.branch(null);
+
+ branchRev = addNodes(branchRev, "/branch1", "/branch1/child1",
"/branch1/child1/child2", "/branch1/child1/child2/child3");
+ assertNodesExist(branchRev, "/trunk", "/trunk/child1",
"/trunk/child1/child2", "/trunk/child1/child2/child3");
+ assertNodesExist(branchRev, "/branch1", "/branch1/child1",
"/branch1/child1/child2", "/branch1/child1/child2/child3");
+ assertNodesNotExist(null, "/branch1", "/branch1/child1",
"/branch1/child1/child2", "/branch1/child1/child2/child3");
+
+ addNodes(null, "/trunk/child1/child2/child3/child4", "/trunk/child5");
+ assertNodesExist(null, "/trunk/child1/child2/child3/child4",
"/trunk/child5");
+ assertNodesNotExist(branchRev, "/trunk/child1/child2/child3/child4",
"/trunk/child5");
- assertTrue(mk.nodeExists("/trunk", null));
- assertTrue(mk.nodeExists("/trunk/child1", null));
+ mk.merge(branchRev, "");
+ assertNodesExist(null, "/trunk", "/trunk/child1",
"/trunk/child1/child2", "/trunk/child1/child2/child3",
"/trunk/child1/child2/child3/child4");
+ assertNodesExist(null, "/branch1", "/branch1/child1",
"/branch1/child1/child2", "/branch1/child1/child2/child3");
+ }
- // make sure /trunk/child1/child2 does now exist in head
- assertTrue(mk.nodeExists("/trunk/child1/child2", null));
- // make sure /trunk/child3 still exists in head
- assertTrue(mk.nodeExists("/trunk/child3", null));
+ @Test
+ public void oneBranchAddedChildrenAndAddedProperties() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ setProp(null, "/trunk/child1/prop1", "value1");
+ setProp(null, "/trunk/child1/prop2", "value2");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+ assertPropExists(null, "/trunk/child1", "prop1");
+ assertPropExists(null, "/trunk/child1", "prop2");
+
+ String branchRev = mk.branch(null);
+
+ branchRev = addNodes(branchRev, "/branch1", "/branch1/child1");
+ branchRev = setProp(branchRev, "/branch1/child1/prop1", "value1");
+ branchRev = setProp(branchRev, "/branch1/child1/prop2", "value2");
+ assertNodesExist(branchRev, "/trunk", "/trunk/child1");
+ assertPropExists(branchRev, "/trunk/child1", "prop1");
+ assertPropExists(branchRev, "/trunk/child1", "prop2");
+ assertNodesExist(branchRev, "/branch1", "/branch1/child1");
+ assertPropExists(branchRev, "/branch1/child1", "prop1");
+ assertPropExists(branchRev, "/branch1/child1", "prop2");
+ assertNodesNotExist(null, "/branch1", "/branch1/child1");
+ assertPropNotExists(null, "/branch1/child1", "prop1");
+ assertPropNotExists(null, "/branch1/child1", "prop2");
+
+ mk.merge(branchRev, "");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+ assertPropExists(null, "/trunk/child1", "prop1");
+ assertPropExists(null, "/trunk/child1", "prop2");
+ assertNodesExist(null, "/branch1", "/branch1/child1");
+ assertPropExists(null, "/branch1/child1", "prop1");
+ assertPropExists(null, "/branch1/child1", "prop2");
+ }
+
+ @Test
+ public void twoBranchesAddedChildren1() {
+ addNodes(null, "/trunk", "/trunk/child1");
+ assertNodesExist(null, "/trunk", "/trunk/child1");
+
+ String branchRev1 = mk.branch(null);
+ String branchRev2 = mk.branch(null);
+
+ branchRev1 = addNodes(branchRev1, "/branch1", "/branch1/child1");
+ branchRev2 = addNodes(branchRev2, "/branch2", "/branch2/child2");
+ assertNodesExist(branchRev1, "/trunk", "/trunk/child1");
+ assertNodesExist(branchRev2, "/trunk", "/trunk/child1");
+ assertNodesExist(branchRev1, "/branch1/child1");
+ assertNodesNotExist(branchRev1, "/branch2/child2");
+ assertNodesExist(branchRev2, "/branch2/child2");
+ assertNodesNotExist(branchRev2, "/branch1/child1");
+ assertNodesNotExist(null, "/branch1/child1", "/branch2/child2");
+
+ addNodes(null, "/trunk/child2");
+ assertNodesExist(null, "/trunk/child2");
+ assertNodesNotExist(branchRev1, "/trunk/child2");
+ assertNodesNotExist(branchRev2, "/trunk/child2");
+
+ mk.merge(branchRev1, "");
+ assertNodesExist(null, "/trunk", "/branch1", "/branch1/child1");
+ assertNodesNotExist(null, "/branch2", "/branch2/child2");
+
+ mk.merge(branchRev2, "");
+ assertNodesExist(null, "/trunk", "/branch1", "/branch1/child1",
"/branch2", "/branch2/child2");
+ }
+
+ @Test
+ public void emptyMergeCausesNoChange() {
+ String rev1 = mk.commit("", "+\"/child1\":{}", null, "");
+
+ String branchRev = mk.branch(null);
+ branchRev = mk.commit("", "+\"/child2\":{}", branchRev, "");
+ branchRev = mk.commit("", "-\"/child2\"", branchRev, "");
+
+ String rev2 = mk.merge(branchRev, "");
+
+ assertTrue(mk.nodeExists("/child1", null));
+ assertFalse(mk.nodeExists("/child2", null));
+ assertEquals(rev1, rev2);
+ }
+
+ @Test
+ public void trunkMergeNotAllowed() {
+ String rev = mk.commit("", "+\"/child1\":{}", null, "");
+ try {
+ mk.merge(rev, "");
+ fail("Exception expected");
+ } catch (Exception expected) {}
}
@Test