Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java?rev=1792995&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java
 (added)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeStateTest.java
 Fri Apr 28 07:18:26 2017
@@ -0,0 +1,322 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade.nodestate;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Arrays.asList;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static 
org.apache.jackrabbit.oak.plugins.tree.impl.TreeConstants.OAK_CHILD_ORDER;
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.FilteringNodeState.wrap;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.assertExists;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.assertMissing;
+import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.commit;
+import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.create;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.createNodeStoreWithContent;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.getNodeState;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FilteringNodeStateTest {
+
+    private static final Set<String> DEFAULT_INCLUDES = FilteringNodeState.ALL;
+
+    private static final Set<String> DEFAULT_EXCLUDES = 
FilteringNodeState.NONE;
+
+    private NodeState rootNodeState;
+
+    @Before
+    public void setup() throws RepositoryException, CommitFailedException, 
IOException {
+        final NodeStore nodeStore = createNodeStoreWithContent(
+                "/content/foo/de",
+                "/content/foo/en",
+                "/content/football/en",
+                "/apps/foo/install",
+                "/libs/foo/install"
+        );
+
+        final PropertyState childOrder = createProperty(OAK_CHILD_ORDER, 
asList("foo", "football"), Type.NAMES);
+        final NodeBuilder builder = nodeStore.getRoot().builder();
+        create(builder, "/content", childOrder);
+        commit(nodeStore, builder);
+
+        rootNodeState = nodeStore.getRoot();
+    }
+
+    @Test
+    public void shouldNotDecorateForNullArgs() {
+        final NodeState decorated = wrap("/", rootNodeState, null, null);
+        assertSame("root should be identical to decorated", rootNodeState, 
decorated);
+    }
+
+    @Test
+    public void shouldNotDecorateForDefaultIncludes() {
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
null);
+        assertSame("root should be identical to decorated", rootNodeState, 
decorated);
+    }
+
+    @Test
+    public void shouldNotDecorateForDefaultExcludes() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
DEFAULT_EXCLUDES);
+        assertSame("root should be identical to decorated", rootNodeState, 
decorated);
+    }
+
+    @Test
+    public void shouldNotDecorateForDefaultIncludesAndExcludes() {
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
DEFAULT_EXCLUDES);
+        assertSame("root should be identical to decorated", rootNodeState, 
decorated);
+    }
+
+    @Test
+    public void shouldNotDecorateIncludedPath() {
+        final NodeState content = getNodeState(rootNodeState, "/content");
+        final NodeState decorated = wrap("/content", content, of("/content"), 
null);
+        assertSame("content should be identical to decorated", content, 
decorated);
+    }
+
+    @Test
+    public void shouldNotDecorateIncludedDescendants() {
+        final NodeState foo = getNodeState(rootNodeState, "/content/foo");
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
null);
+        assertSame("foo should be identical to decorated", foo, decorated);
+    }
+
+    @Test
+    public void shouldDecorateAncestorOfExcludedDescendants() {
+        final NodeState foo = getNodeState(rootNodeState, "/content/foo");
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
of("/content/foo/de"));
+        assertNotSame("foo should not be identical to decorated", foo, 
decorated);
+
+        assertMissing(decorated, "de");
+        assertExists(decorated, "en");
+        assertFalse("child nodes \"de\" should not be equal",
+                getNodeState(foo, "de").equals(getNodeState(decorated, "de")));
+
+        final NodeState en = getNodeState(decorated, "en");
+        assertEquals("child nodes \"en\" should be equal", getNodeState(foo, 
"en"), en);
+        assertTrue("child node \"en\" should not be decorated", !(en 
instanceof FilteringNodeState));
+    }
+
+    @Test
+    public void shouldHaveCorrectChildOrderProperty() throws 
CommitFailedException {
+        final NodeState content = rootNodeState.getChildNode("content");
+        final NodeState decorated = wrap("/content", content, null, 
of("/content/foo"));
+
+        assertTrue(decorated.hasProperty(OAK_CHILD_ORDER));
+
+        { // access via getProperty()
+            final PropertyState childOrder = 
decorated.getProperty(OAK_CHILD_ORDER);
+            final Iterable<String> values = childOrder.getValue(Type.STRINGS);
+            assertEquals(newArrayList("football"), newArrayList(values));
+        }
+
+        { // access via getProperties()
+            final Predicate<PropertyState> isChildOrderProperty = new 
Predicate<PropertyState>() {
+                @Override
+                public boolean apply(PropertyState propertyState) {
+                    return OAK_CHILD_ORDER.equals(propertyState.getName());
+                }
+            };
+            final PropertyState childOrder = 
Iterables.find(decorated.getProperties(), isChildOrderProperty);
+            final Iterable<String> values = childOrder.getValue(Type.STRINGS);
+            assertEquals(newArrayList("football"), newArrayList(values));
+        }
+    }
+
+    @Test
+    public void shouldDecorateExcludedNode() {
+        final NodeState decoratedRoot = wrap("/", rootNodeState, 
of("/content"), of("/content/foo/de"));
+        final NodeState de = getNodeState(rootNodeState, "/content/foo/de");
+        final NodeState decorated = getNodeState(decoratedRoot, 
"/content/foo/de");
+        assertFalse("de should not be equal to decorated", 
de.equals(decorated));
+        assertFalse("decorated should not exist", decorated.exists());
+    }
+
+    @Test
+    public void shouldDecorateImplicitlyExcludedNode() {
+        final NodeState content = getNodeState(rootNodeState, "/content");
+        final NodeState decorated = wrap("/content", content, of("/apps"), 
null);
+        assertNotSame("content should not be identical to decorated", content, 
decorated);
+    }
+
+
+    @Test
+    public void shouldHideExcludedPathsViaExists() {
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"));
+        assertMissing(decorated, "apps");
+        assertMissing(decorated, "libs/foo/install");
+
+        assertExists(decorated, "content/foo/de");
+        assertExists(decorated, "content/foo/en");
+    }
+
+    @Test
+    public void shouldHideExcludedPathsViaHasChildNode() {
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"));
+
+        assertExistingHasChildNode(decorated, "content");
+        assertMissingHasChildNode(decorated, "apps");
+        assertMissingHasChildNode(decorated, "libs");
+    }
+
+    @Test
+    public void shouldHideExcludedPathsViaGetChildNodeNames() {
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"));
+
+        assertExistingChildNodeName(decorated, "content");
+        assertMissingChildNodeName(decorated, "apps");
+        assertMissingChildNodeName(decorated, "libs");
+    }
+
+    @Test
+    public void shouldHideMissingIncludedPathsViaExists() {
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null);
+        assertMissing(decorated, "apps");
+        assertMissing(decorated, "libs/foo/install");
+
+        assertExists(decorated, "content/foo/de");
+        assertExists(decorated, "content/foo/en");
+    }
+
+    @Test
+    public void shouldHideMissingIncludedPathsViaHasChildNode() {
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null);
+
+        assertExistingHasChildNode(decorated, "content");
+        assertMissingHasChildNode(decorated, "apps");
+        assertMissingHasChildNode(decorated, "libs");
+    }
+
+    @Test
+    public void shouldHideMissingIncludedPathsViaGetChildNodeNames() {
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null);
+
+        assertExistingChildNodeName(decorated, "content");
+        assertMissingChildNodeName(decorated, "apps");
+        assertMissingChildNodeName(decorated, "libs");
+    }
+
+    @Test
+    public void shouldGivePrecedenceForExcludesOverIncludes() {
+        final NodeState conflictingRules = wrap("/", rootNodeState, 
of("/content"), of("/content"));
+        assertMissingChildNodeName(conflictingRules, "content");
+
+        final NodeState overlappingRules = wrap("/", rootNodeState, 
of("/content"), of("/content/foo"));
+        assertExistingChildNodeName(overlappingRules, "content");
+        assertMissingChildNodeName(overlappingRules.getChildNode("content"), 
"foo");
+
+
+        final NodeState overlappingRules2 = wrap("/", rootNodeState, 
of("/content/foo"), of("/content"));
+        assertMissingChildNodeName(overlappingRules2, "content");
+        assertMissingChildNodeName(overlappingRules2.getChildNode("content"), 
"foo");
+
+    }
+
+    @Test
+    public void shouldRespectPathBoundariesForIncludes() {
+        final NodeState decorated = wrap("/", rootNodeState, 
of("/content/foo"), null);
+
+        assertExistingChildNodeName(decorated, "content");
+        assertExistingChildNodeName(decorated.getChildNode("content"), "foo");
+        assertMissingChildNodeName(decorated.getChildNode("content"), 
"football");
+    }
+
+    @Test
+    public void shouldRespectPathBoundariesForExcludes() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"));
+
+        assertExistingChildNodeName(decorated, "content");
+        assertMissingChildNodeName(decorated.getChildNode("content"), "foo");
+        assertExistingChildNodeName(decorated.getChildNode("content"), 
"football");
+    }
+
+    @Test
+    public void shouldDelegatePropertyCount() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"));
+
+        assertEquals(1, getNodeState(decorated, 
"/content").getPropertyCount());
+        assertEquals(0, getNodeState(decorated, 
"/content/foo").getPropertyCount());
+    }
+
+
+    @Test
+    public void shouldDelegateGetProperty() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"));
+        final NodeState content = getNodeState(decorated, "/content");
+
+        assertNotNull(content.getProperty(OAK_CHILD_ORDER));
+        assertNull(content.getProperty("nonexisting"));
+    }
+
+
+    @Test
+    public void shouldDelegateHasProperty() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"));
+
+        assertTrue(getNodeState(decorated, 
"/content").hasProperty(OAK_CHILD_ORDER));
+        assertFalse(getNodeState(decorated, "/content").hasProperty("foo"));
+    }
+
+
+    @Test
+    public void exists() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"));
+        assertTrue("/content should exist and be visible", 
getNodeState(decorated, "/content").exists());
+        assertFalse("/content/foo should be hidden", getNodeState(decorated, 
"/content/foo").exists());
+        assertFalse("/nonexisting should not exist", getNodeState(decorated, 
"/nonexisting").exists());
+    }
+
+
+    private void assertExistingHasChildNode(NodeState decorated, String name) {
+        assertTrue("should have child \"" + name + "\"", 
decorated.hasChildNode(name));
+    }
+
+    private void assertMissingHasChildNode(NodeState decorated, String name) {
+        assertFalse("should not have child \"" + name + "\"", 
decorated.hasChildNode(name));
+    }
+
+    private void assertExistingChildNodeName(NodeState decorated, String name) 
{
+        final Iterable<String> childNodeNames = decorated.getChildNodeNames();
+        assertTrue("should list child \"" + name + "\"", 
Iterables.contains(childNodeNames, name));
+    }
+
+    private void assertMissingChildNodeName(NodeState decorated, String name) {
+        final Iterable<String> childNodeNames = decorated.getChildNodeNames();
+        assertFalse("should not list child \"" + name + "\"", 
Iterables.contains(childNodeNames, name));
+    }
+}

Modified: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopierTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopierTest.java?rev=1792995&r1=1792994&r2=1792995&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopierTest.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/NodeStateCopierTest.java
 Fri Apr 28 07:18:26 2017
@@ -18,7 +18,15 @@
  */
 package org.apache.jackrabbit.oak.upgrade.nodestate;
 
-import com.google.common.collect.ImmutableSet;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier.builder;
+import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.commit;
+import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.create;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.createNodeStoreWithContent;
+import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.expectDifference;
+
+import java.io.IOException;
+
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
@@ -27,20 +35,46 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.junit.Test;
 
-import static com.google.common.collect.ImmutableSet.of;
-import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
-import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.commit;
-import static org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.create;
-import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.createNodeStoreWithContent;
-import static 
org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils.expectDifference;
-
 public class NodeStateCopierTest {
 
     private final PropertyState primaryType =
             createProperty("jcr:primaryType", "nt:unstructured", Type.NAME);
 
     @Test
-    public void shouldMergeIdenticalContent() throws CommitFailedException {
+    public void shouldCreateMissingAncestors() throws CommitFailedException, 
IOException {
+        final NodeStore source = createPrefilledNodeStore();
+        final NodeStore target = createNodeStoreWithContent();
+
+        builder()
+                .include("/a/b/c")
+                .copy(source, target);
+
+        expectDifference()
+                .childNodeChanged("/a", "/a/b")
+                .childNodeDeleted("/excluded", "/a/b/excluded")
+                .strict()
+                .verify(source.getRoot(), target.getRoot());
+    }
+
+    @Test
+    public void shouldIncludeMultiplePaths() throws CommitFailedException, 
IOException {
+        final NodeStore source = createPrefilledNodeStore();
+        final NodeStore target = createNodeStoreWithContent();
+
+        builder()
+                .include("/a/b/c/d", "/a/b/c/e")
+                .copy(source, target);
+
+        expectDifference()
+                .propertyDeleted("/a/b/c/f/jcr:primaryType")
+                .childNodeChanged("/a", "/a/b", "/a/b/c")
+                .childNodeDeleted("/excluded", "/a/b/excluded", "/a/b/c/f")
+                .strict()
+                .verify(source.getRoot(), target.getRoot());
+    }
+
+    @Test
+    public void shouldMergeIdenticalContent() throws CommitFailedException, 
IOException {
         final NodeStore source = createPrefilledNodeStore();
         final NodeStore target = createPrefilledNodeStore();
 
@@ -52,7 +86,7 @@ public class NodeStateCopierTest {
         expectDifference().strict().verify(source.getRoot(), after);
     }
 
-    private NodeStore createPrefilledNodeStore() throws CommitFailedException {
+    private NodeStore createPrefilledNodeStore() throws CommitFailedException, 
IOException {
         final NodeStore store = createNodeStoreWithContent();
         final NodeBuilder builder = store.getRoot().builder();
         create(builder, "/excluded");
@@ -68,13 +102,63 @@ public class NodeStateCopierTest {
     }
 
     @Test
-    public void shouldRespectMergePaths() throws CommitFailedException {
+    public void shouldSkipNonMatchingIncludes() throws CommitFailedException, 
IOException {
+        final NodeStore source = createNodeStoreWithContent();
+        final NodeBuilder builder = source.getRoot().builder();
+        create(builder, "/a", primaryType);
+        create(builder, "/a/b", primaryType);
+        create(builder, "/a/b/c", primaryType);
+        commit(source, builder);
+
+        final NodeStore target = createNodeStoreWithContent();
+        builder()
+                .include("/a", "/z")
+                .copy(source, target);
+
+        expectDifference()
+                .strict()
+                .verify(source.getRoot(), target.getRoot());
+    }
+
+    @Test
+    public void shouldCopyFromMultipleSources() throws CommitFailedException, 
IOException {
+        final NodeStore source1 = createNodeStoreWithContent(
+                "/content/foo/en", "/content/foo/de");
+        final NodeStore source2 = createNodeStoreWithContent(
+                "/content/bar/en", "/content/bar/de", "/content/baz/en");
+        final NodeStore target = createNodeStoreWithContent();
+
+        final NodeState before = target.getRoot();
+        builder()
+                .include("/content/foo")
+                .copy(source1, target);
+        builder()
+                .include("/content/bar")
+                .exclude("/content/bar/de")
+                .copy(source2, target);
+        final NodeState after = target.getRoot();
+
+        expectDifference()
+                .strict()
+                .childNodeAdded(
+                        "/content",
+                        "/content/foo",
+                        "/content/foo/en",
+                        "/content/foo/de",
+                        "/content/bar",
+                        "/content/bar/en"
+                )
+                .verify(before, after);
+    }
+
+    @Test
+    public void shouldRespectMergePaths() throws CommitFailedException, 
IOException {
         final NodeStore source = createNodeStoreWithContent("/content/foo/en", 
"/content/bar/en");
         final NodeStore target = createNodeStoreWithContent("/content/foo/de");
 
-        final NodeBuilder builder = target.getRoot().builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
of("/content"));
-        commit(target, builder);
+        builder()
+                .merge("/content")
+                .copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()
@@ -84,16 +168,31 @@ public class NodeStateCopierTest {
                 .verify(source.getRoot(), after);
     }
 
+    @Test
+    public void shouldNotDeleteMergedExcludedPaths() throws 
CommitFailedException, IOException {
+        final NodeStore source = createNodeStoreWithContent("/content/foo/en", 
"/jcr:system");
+        final NodeStore target = 
createNodeStoreWithContent("/jcr:system/jcr:versionStorage");
+
+        final NodeState before = target.getRoot();
+        builder()
+                .merge("/jcr:system")
+                .exclude("/jcr:system")
+                .copy(source, target);
+        final NodeState after = target.getRoot();
+
+        expectDifference()
+                .strict()
+                .childNodeAdded("/content", "/content/foo", "/content/foo/en")
+                .verify(before, after);
+    }
 
     @Test
-    public void shouldDeleteExistingNodes() throws CommitFailedException {
+    public void shouldDeleteExistingNodes() throws CommitFailedException, 
IOException {
         final NodeStore source = createNodeStoreWithContent("/content/foo");
         final NodeStore target = createNodeStoreWithContent("/content/bar");
 
         final NodeState before = target.getRoot();
-        final NodeBuilder builder = before.builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
ImmutableSet.<String>of());
-        commit(target, builder);
+        builder().copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()
@@ -105,17 +204,15 @@ public class NodeStateCopierTest {
     }
 
     @Test
-    public void shouldDeleteExistingPropertyIfMissingInSource() throws 
CommitFailedException {
+    public void shouldDeleteExistingPropertyIfMissingInSource() throws 
CommitFailedException, IOException {
         final NodeStore source = createNodeStoreWithContent("/a");
         final NodeStore target = createNodeStoreWithContent();
-        NodeBuilder builder = target.getRoot().builder();
+        final NodeBuilder builder = target.getRoot().builder();
         create(builder, "/a", primaryType);
         commit(target, builder);
 
         final NodeState before = target.getRoot();
-        builder = before.builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
ImmutableSet.<String>of());
-        commit(target, builder);
+        builder().copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()
@@ -126,14 +223,14 @@ public class NodeStateCopierTest {
     }
 
     @Test
-    public void shouldNotDeleteExistingNodesIfMerged() throws 
CommitFailedException {
+    public void shouldNotDeleteExistingNodesIfMerged() throws 
CommitFailedException, IOException {
         final NodeStore source = createNodeStoreWithContent("/content/foo");
         final NodeStore target = createNodeStoreWithContent("/content/bar");
 
         final NodeState before = target.getRoot();
-        final NodeBuilder builder = before.builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
of("/content/bar"));
-        commit(target, builder);
+        builder()
+                .merge("/content/bar")
+                .copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()
@@ -144,14 +241,14 @@ public class NodeStateCopierTest {
     }
 
     @Test
-    public void shouldNotDeleteExistingNodesIfDescendantsOfMerged() throws 
CommitFailedException {
+    public void shouldNotDeleteExistingNodesIfDescendantsOfMerged() throws 
CommitFailedException, IOException {
         final NodeStore source = createNodeStoreWithContent("/content/foo");
         final NodeStore target = createNodeStoreWithContent("/content/bar");
 
         final NodeState before = target.getRoot();
-        final NodeBuilder builder = before.builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
of("/content"));
-        commit(target, builder);
+        builder()
+                .merge("/content")
+                .copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()
@@ -161,15 +258,16 @@ public class NodeStateCopierTest {
                 .verify(before, after);
     }
 
+
     @Test
-    public void shouldIgnoreNonMatchingMergePaths() throws 
CommitFailedException {
+    public void shouldIgnoreNonMatchingMergePaths() throws 
CommitFailedException, IOException {
         final NodeStore source = createNodeStoreWithContent("/content/foo");
         final NodeStore target = createNodeStoreWithContent("/content/bar");
 
         final NodeState before = target.getRoot();
-        final NodeBuilder builder = before.builder();
-        NodeStateCopier.copyNodeState(source.getRoot(), builder, "/", 
of("/con"));
-        commit(target, builder);
+        builder()
+                .merge("/con")
+                .copy(source, target);
         final NodeState after = target.getRoot();
 
         expectDifference()

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/AssertingPeriodicReporter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/AssertingPeriodicReporter.java?rev=1792995&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/AssertingPeriodicReporter.java
 (added)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/AssertingPeriodicReporter.java
 Fri Apr 28 07:18:26 2017
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade.nodestate.report;
+
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.any;
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.anything;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.collection.IsMapContaining.hasEntry;
+
+class AssertingPeriodicReporter extends PeriodicReporter {
+
+    private final Map<Long, String> reportedNodes = new HashMap<Long, 
String>();
+
+    private final Map<Long, String> reportedProperties = new HashMap<Long, 
String>();
+
+    public AssertingPeriodicReporter(final int nodeLogInterval, final int 
propertyLogInterval) {
+        super(nodeLogInterval, propertyLogInterval);
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        reportedNodes.clear();
+        reportedProperties.clear();
+    }
+
+    @Override
+    protected void reportPeriodicNode(final long count, @Nonnull final 
ReportingNodeState nodeState) {
+        reportedNodes.put(count, nodeState.getPath());
+    }
+
+    @Override
+    protected void reportPeriodicProperty(final long count, @Nonnull final 
ReportingNodeState parent, @Nonnull final String propertyName) {
+        reportedProperties.put(count, PathUtils.concat(parent.getPath(), 
propertyName));
+    }
+
+    @Override
+    public String toString() {
+        return "Reported{ nodes: " + reportedNodes + " properties: " + 
reportedProperties + "}";
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedNode(final int 
count, final String path) {
+        return hasReports(hasEntry((long) count, path), whatever());
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedNode(final int 
count, final Matcher<String> pathMatcher) {
+        return hasReports(typesafeHasEntry(equalTo((long) count), 
pathMatcher), whatever());
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedNodes(final 
String... paths) {
+        final List<Matcher<? super AssertingPeriodicReporter>> matchers =
+                new ArrayList<Matcher<? super AssertingPeriodicReporter>>();
+        for (final String path : paths) {
+            matchers.add(hasReports(typesafeHasEntry(any(Long.class), 
equalTo(path)), whatever()));
+        }
+        return allOf(matchers);
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedProperty(final 
int count, final String path) {
+        return hasReports(whatever(), hasEntry((long) count, path));
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedProperty(final 
int count, final Matcher<String> pathMatcher) {
+        return hasReports(whatever(), typesafeHasEntry(equalTo((long) count), 
pathMatcher));
+    }
+
+    public static Matcher<AssertingPeriodicReporter> hasReportedProperty(final 
String... paths) {
+        final List<Matcher<? super String>> pathMatchers = new 
ArrayList<Matcher<? super String>>();
+        for (final String path : paths) {
+            pathMatchers.add(equalTo(path));
+        }
+        return hasReports(whatever(), typesafeHasEntry(any(Long.class), 
allOf(pathMatchers)));
+    }
+
+    private static Matcher<Map<? extends Long, ? extends String>> whatever() {
+        return anyOf(typesafeHasEntry(any(Long.class), any(String.class)), 
anything());
+    }
+
+    private static Matcher<AssertingPeriodicReporter> hasReports(
+            final Matcher<Map<? extends Long, ? extends String>> 
nodeMapMatcher,
+            final Matcher<Map<? extends Long, ? extends String>> 
propertyMapMatcher) {
+
+        return new org.hamcrest.TypeSafeMatcher<AssertingPeriodicReporter>() {
+            @Override
+            protected boolean matchesSafely(final AssertingPeriodicReporter 
reporter) {
+                final boolean nodesMatch = 
nodeMapMatcher.matches(reporter.reportedNodes);
+                final boolean propertiesMatch = 
propertyMapMatcher.matches(reporter.reportedProperties);
+                return nodesMatch && propertiesMatch;
+            }
+
+            @Override
+            public void describeTo(final Description description) {
+                description
+                        .appendText("Reported{ nodes: ")
+                        .appendDescriptionOf(nodeMapMatcher)
+                        .appendText(", properties: ")
+                        .appendDescriptionOf(propertyMapMatcher);
+
+            }
+        };
+    }
+
+    // Java 6 fails to infer generics correctly if hasEntry is not wrapped in 
this
+    // method.
+    private static Matcher<Map<? extends Long, ? extends String>> 
typesafeHasEntry(
+            final Matcher<Long> countMatcher, final Matcher<String> 
pathMatcher) {
+        return hasEntry(countMatcher, pathMatcher);
+    }
+}

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/PeriodicReporterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/PeriodicReporterTest.java?rev=1792995&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/PeriodicReporterTest.java
 (added)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/PeriodicReporterTest.java
 Fri Apr 28 07:18:26 2017
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade.nodestate.report;
+
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.report.AssertingPeriodicReporter.hasReportedNode;
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.report.AssertingPeriodicReporter.hasReportedProperty;
+import static org.junit.Assert.assertThat;
+
+public class PeriodicReporterTest {
+
+    @Test
+    public void callbackEveryTenNodes() {
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(10, -1);
+        final NodeState counter = 
ReportingNodeState.wrap(EmptyNodeState.EMPTY_NODE, reporter)
+                .getChildNode("counter");
+
+        reporter.reset();
+        for (int i = 1; i < 40; i++) {
+            counter.getChildNode(Integer.toString(i));
+        }
+
+        assertThat(reporter, hasReportedNode(10, "/counter/10"));
+        assertThat(reporter, hasReportedNode(20, "/counter/20"));
+        assertThat(reporter, hasReportedNode(30, "/counter/30"));
+    }
+
+    @Test
+    public void callbackEveryTenProperties() {
+        final NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        for (int i = 1; i < 40; i++) {
+            builder.child("counter").setProperty(Integer.toString(i), i);
+        }
+
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(-1, 10);
+        final NodeState counter = 
ReportingNodeState.wrap(builder.getNodeState(), reporter)
+                .getChildNode("counter");
+
+        reporter.reset();
+        for (int i = 1; i < 40; i++) {
+            counter.getProperty(Integer.toString(i));
+        }
+
+        assertThat(reporter, hasReportedProperty(10, "/counter/10"));
+        assertThat(reporter, hasReportedProperty(20, "/counter/20"));
+        assertThat(reporter, hasReportedProperty(30, "/counter/30"));
+    }
+
+}

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeStateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeStateTest.java?rev=1792995&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeStateTest.java
 (added)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeStateTest.java
 Fri Apr 28 07:18:26 2017
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade.nodestate.report;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.upgrade.util.NodeStateTestUtils;
+import org.junit.Test;
+
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.report.AssertingPeriodicReporter.hasReportedNode;
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.report.AssertingPeriodicReporter.hasReportedNodes;
+import static 
org.apache.jackrabbit.oak.upgrade.nodestate.report.AssertingPeriodicReporter.hasReportedProperty;
+import static org.hamcrest.CoreMatchers.any;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
+public class ReportingNodeStateTest {
+
+    @Test
+    public void getChildNodeReportsNode() {
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(10, 10);
+        final NodeState nodeState = 
ReportingNodeState.wrap(EmptyNodeState.EMPTY_NODE, reporter);
+
+        reporter.reset();
+        for (int i = 1; i <= 20; i++) {
+            nodeState.getChildNode("a" + i);
+        }
+
+        assertThat(reporter, hasReportedNode(10, "/a10"));
+        assertThat(reporter, hasReportedNode(20, "/a20"));
+    }
+
+    @Test
+    public void getChildNodeEntriesReportsNode() {
+        final NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        for (int i = 1; i < 20; i++) {
+            builder.child("a" + i);
+        }
+
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(10, 10);
+        final NodeState nodeState = 
ReportingNodeState.wrap(builder.getNodeState(), reporter);
+
+        reporter.reset();
+        int counter = 0;
+        String name = "<none>";
+        for (final ChildNodeEntry child : nodeState.getChildNodeEntries()) {
+            if (++counter == 10) {
+                name = child.getName();
+                break;
+            }
+        }
+
+        assertThat(reporter, hasReportedNode(10, "/" + name));
+    }
+
+    @Test
+    public void getPropertyReportsProperty() {
+        final NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        final String name = "meaningOfLife";
+        builder.setProperty(name, "42");
+
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(1, 1);
+        final NodeState nodeState = 
ReportingNodeState.wrap(builder.getNodeState(), reporter);
+
+        reporter.reset();
+
+        // 7 accesses via 7 methods
+        nodeState.getProperty(name);
+        nodeState.getBoolean(name);
+        nodeState.getLong(name);
+        nodeState.getString(name);
+        nodeState.getStrings(name);
+        nodeState.getName(name);
+        nodeState.getNames(name);
+
+        assertThat(reporter, not(hasReportedProperty(0, "/meaningOfLife")));
+        assertThat(reporter, hasReportedProperty(1, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(2, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(3, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(4, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(5, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(6, "/meaningOfLife"));
+        assertThat(reporter, hasReportedProperty(7, "/meaningOfLife"));
+        assertThat(reporter, not(hasReportedProperty(8, "/meaningOfLife")));
+    }
+
+    @Test
+    public void getPropertiesReportsProperty() {
+        final NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        for (int i = 0; i < 20; i++) {
+            builder.setProperty("a" + i, "foo");
+        }
+
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(10, 10);
+        final NodeState nodeState = 
ReportingNodeState.wrap(builder.getNodeState(), reporter);
+
+        reporter.reset();
+        int counter = 0;
+        for (final PropertyState property : nodeState.getProperties()) {
+            if (++counter == 10) {
+                break;
+            }
+        }
+
+        assertThat(reporter, hasReportedProperty(10, any(String.class)));
+    }
+
+    @Test
+    public void compareAgainstBaseState() {
+        final NodeBuilder root = EmptyNodeState.EMPTY_NODE.builder();
+        root.child("a").child("aa");
+
+        final NodeState before = root.getNodeState();
+
+        root.child("a").child("ab");
+        root.child("b");
+
+        final AssertingPeriodicReporter reporter = new 
AssertingPeriodicReporter(1, -1);
+        final NodeState after = ReportingNodeState.wrap(root.getNodeState(), 
reporter);
+
+        reporter.reset();
+        NodeStateTestUtils.expectDifference()
+                .childNodeAdded(
+                        "/a/ab",
+                        "/b"
+                )
+                .childNodeChanged(
+                        "/a"
+                )
+                .strict()
+                .verify(before, after);
+
+        assertThat(reporter, hasReportedNodes("/a", "/a/ab", "/b"));
+    }
+}

Modified: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/NodeStateTestUtils.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/NodeStateTestUtils.java?rev=1792995&r1=1792994&r2=1792995&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/NodeStateTestUtils.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/NodeStateTestUtils.java
 Fri Apr 28 07:18:26 2017
@@ -18,6 +18,17 @@
  */
 package org.apache.jackrabbit.oak.upgrade.util;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -31,21 +42,13 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import static org.junit.Assert.assertEquals;
-
 public class NodeStateTestUtils {
 
     private NodeStateTestUtils() {
         // no instances
     }
 
-    public static NodeStore createNodeStoreWithContent(String... paths) throws 
CommitFailedException {
+    public static NodeStore createNodeStoreWithContent(String... paths) throws 
CommitFailedException, IOException {
         final SegmentNodeStore store = new SegmentNodeStore();
         final NodeBuilder builder = store.getRoot().builder();
         for (String path : paths) {
@@ -66,6 +69,14 @@ public class NodeStateTestUtils {
         store.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
     }
 
+    public static NodeState getNodeState(NodeState state, String path) {
+        NodeState current = state;
+        for (final String name : PathUtils.elements(path)) {
+            current = current.getChildNode(name);
+        }
+        return current;
+    }
+
     public static NodeBuilder createOrGetBuilder(NodeBuilder builder, String 
path) {
         NodeBuilder current = builder;
         for (final String name : PathUtils.elements(path)) {
@@ -74,6 +85,14 @@ public class NodeStateTestUtils {
         return current;
     }
 
+    public static void assertExists(NodeState state, String relPath) {
+        assertTrue(relPath + " should exist", getNodeState(state, 
relPath).exists());
+    }
+
+    public static void assertMissing(NodeState state, String relPath) {
+        assertFalse(relPath + " should not exist", getNodeState(state, 
relPath).exists());
+    }
+
     public static ExpectedDifference expectDifference() {
         return new ExpectedDifference();
     }

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/VersionCopyTestUtils.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/VersionCopyTestUtils.java?rev=1792995&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/VersionCopyTestUtils.java
 (added)
+++ 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/util/VersionCopyTestUtils.java
 Fri Apr 28 07:18:26 2017
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+import javax.jcr.version.VersionManager;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.upgrade.version.VersionCopyConfiguration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class VersionCopyTestUtils {
+
+    public static List<String> LABELS = ImmutableList.of("1.0", "1.1", "1.2");
+
+    public static Node getOrAddNode(Node parent, String relPath) throws 
RepositoryException {
+        Node currentParent = parent;
+        for (final String name : PathUtils.elements(relPath)) {
+            if (!currentParent.hasNode(name)) {
+                currentParent.addNode(name, JcrConstants.NT_UNSTRUCTURED);
+            }
+            currentParent = currentParent.getNode(name);
+        }
+        return currentParent;
+    }
+
+    public static Node getOrAddNodeWithMixins(Node parent, String name, String 
mixinType)
+            throws RepositoryException {
+        final Node node = getOrAddNode(parent, name);
+        node.addMixin(mixinType);
+        return node;
+    }
+
+    public static String createLabeledVersions(Node node)
+            throws RepositoryException, InterruptedException {
+        final Session session = node.getSession();
+        final VersionManager versionManager = 
session.getWorkspace().getVersionManager();
+        node.setProperty("version", "root");
+        session.save();
+
+        final String path = node.getPath();
+        final List<String> versionNames = new ArrayList<String>();
+        for (final String label : LABELS) {
+            node.setProperty("version", label);
+            session.save();
+            final Version v = versionManager.checkpoint(path);
+            versionNames.add(v.getName());
+        }
+
+        final VersionHistory history = versionManager.getVersionHistory(path);
+        for (final String versionName : versionNames) {
+            history.addVersionLabel(versionName, String.format("version %s", 
versionName), false);
+        }
+        return history.getPath();
+    }
+
+    public static void assertLabeledVersions(VersionHistory history) throws 
RepositoryException {
+        final VersionIterator versions = history.getAllVersions();
+        
assertFalse(versions.nextVersion().getFrozenNode().hasProperty("version")); // 
root
+        for (final String label : LABELS) {
+            assertEquals(label, 
versions.nextVersion().getFrozenNode().getProperty("version").getString());
+        }
+    }
+
+    public interface VersionCopySetup {
+        void setup(VersionCopyConfiguration config);
+    }
+}

Added: jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/jcr2.zip
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/jcr2.zip?rev=1792995&view=auto
==============================================================================
Binary files 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/jcr2.zip (added) and 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/jcr2.zip Fri Apr 28 
07:18:26 2017 differ

Modified: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/logback-test.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/logback-test.xml?rev=1792995&r1=1792994&r2=1792995&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/logback-test.xml 
(original)
+++ jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/logback-test.xml 
Fri Apr 28 07:18:26 2017
@@ -29,7 +29,7 @@
         </encoder>
     </appender>
 
-    <root level="DEBUG">
+    <root level="INFO">
         <!--
         <appender-ref ref="console"/>
         -->

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/segmentstore.zip
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/segmentstore.zip?rev=1792995&view=auto
==============================================================================
Binary files 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/segmentstore.zip 
(added) and 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/segmentstore.zip Fri 
Apr 28 07:18:26 2017 differ

Added: 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/test-repo-1.0.zip
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/test-repo-1.0.zip?rev=1792995&view=auto
==============================================================================
Binary files 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/test-repo-1.0.zip 
(added) and 
jackrabbit/oak/branches/1.2/oak-upgrade/src/test/resources/test-repo-1.0.zip 
Fri Apr 28 07:18:26 2017 differ


Reply via email to