You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2018/04/12 11:46:18 UTC

svn commit: r1828972 [5/5] - in /jackrabbit/oak/trunk/oak-search: ./ src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/ src/test/java/org/apache/jackrabbit/oak/plugins/index/...

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java?rev=1828972&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java Thu Apr 12 11:46:17 2018
@@ -0,0 +1,113 @@
+/*
+ * 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.plugins.index.search.util;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class FunctionIndexProcessorTest {
+    
+    @Test
+    public void getProperties() {
+        assertEquals(
+                "[a, test/b, test/:name]",
+                Arrays.toString(
+                FunctionIndexProcessor.getProperties(new String[] { "function",
+                        "multiply", "@a", "add", "@test/b", "@test/:name" })));
+    }
+    
+    @Test
+    public void xpath() {
+        checkConvert(
+                "fn:upper-case(@data)", 
+                "function*upper*@data");
+        checkConvert(
+                "fn:lower-case(test/@data)", 
+                "function*lower*@test/data");
+        checkConvert(
+                "fn:lower-case(fn:name())", 
+                "function*lower*@:name");        
+        checkConvert(
+                "fn:lower-case(fn:local-name())", 
+                "function*lower*@:localname");
+        checkConvert(
+                "fn:string-length(test/@data)", 
+                "function*length*@test/data");
+        checkConvert(
+                "fn:string-length(fn:name())", 
+                "function*length*@:name");
+        checkConvert(
+                "fn:lower-case(fn:upper-case(test/@data))", 
+                "function*lower*upper*@test/data");
+        checkConvert("fn:coalesce(jcr:content/@foo2, jcr:content/@foo)",
+                "function*coalesce*@jcr:content/foo2*@jcr:content/foo");
+        checkConvert("fn:coalesce(jcr:content/@foo2,fn:lower-case(jcr:content/@foo))",
+                "function*coalesce*@jcr:content/foo2*lower*@jcr:content/foo");
+        checkConvert("fn:coalesce(jcr:content/@foo2,fn:coalesce(jcr:content/@foo, fn:lower-case(fn:name())))",
+                "function*coalesce*@jcr:content/foo2*coalesce*@jcr:content/foo*lower*@:name");
+        checkConvert("fn:coalesce(fn:coalesce(jcr:content/@foo2,jcr:content/@foo), fn:coalesce(@a:b, @c:d))",
+                "function*coalesce*coalesce*@jcr:content/foo2*@jcr:content/foo*coalesce*@a:b*@c:d");
+    }
+
+    @Test
+    public void sql2() {
+        checkConvert(
+                "upper([data])", 
+                "function*upper*@data");
+        checkConvert(
+                "lower([test/data])", 
+                "function*lower*@test/data");
+        checkConvert(
+                "lower(name())", 
+                "function*lower*@:name");
+        checkConvert(
+                "lower(localname())", 
+                "function*lower*@:localname");
+        checkConvert(
+                "length([test/data])", 
+                "function*length*@test/data");
+        checkConvert(
+                "length(name())", 
+                "function*length*@:name");
+        checkConvert(
+                "lower(upper([test/data]))", 
+                "function*lower*upper*@test/data");
+        // the ']' character is escaped as ']]'
+        checkConvert(
+                "[strange[0]]]", 
+                "function*@strange[0]");
+        checkConvert("coalesce([jcr:content/foo2],[jcr:content/foo])",
+                "function*coalesce*@jcr:content/foo2*@jcr:content/foo");
+        checkConvert("coalesce([jcr:content/foo2], lower([jcr:content/foo]))",
+                "function*coalesce*@jcr:content/foo2*lower*@jcr:content/foo");
+        checkConvert("coalesce([jcr:content/foo2] , coalesce([jcr:content/foo],lower(name())))",
+                "function*coalesce*@jcr:content/foo2*coalesce*@jcr:content/foo*lower*@:name");
+        checkConvert("coalesce(coalesce([jcr:content/foo2],[jcr:content/foo]), coalesce([a:b], [c:d]))",
+                "function*coalesce*coalesce*@jcr:content/foo2*@jcr:content/foo*coalesce*@a:b*@c:d");
+    }
+
+    private static void checkConvert(String function, String expectedPolishNotation) {
+        String p = FunctionIndexProcessor.convertToPolishNotation(function);
+        assertEquals(expectedPolishNotation, p);
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilderTest.java?rev=1828972&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilderTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilderTest.java Thu Apr 12 11:46:17 2018
@@ -0,0 +1,318 @@
+/*
+ * 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.plugins.index.search.util;
+
+import java.util.Iterator;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.tree.factories.TreeFactory;
+import org.apache.jackrabbit.oak.spi.filter.PathFilter;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.junit.After;
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.AGGREGATES;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class IndexDefinitionBuilderTest {
+    private IndexDefinitionBuilder builder = new IndexDefinitionBuilder();
+    private NodeBuilder nodeBuilder = EMPTY_NODE.builder();
+
+    @After
+    public void dumpState(){
+        System.out.println(NodeStateUtils.toString(builder.build()));
+    }
+
+    @Test
+    public void defaultvSetup() throws Exception{
+        NodeState state = builder.build();
+        assertEquals("async", state.getString("async"));
+        assertEquals("fulltext", state.getString("type"));
+    }
+
+    @Test
+    public void indexRule() throws Exception{
+        builder.includedPaths("/a", "/b");
+        builder.queryPaths("/c", "/d");
+        builder.supersedes("/e", "/f");
+        builder.indexRule("nt:base")
+                    .property("foo")
+                        .ordered()
+                .enclosingRule()
+                    .property("bar")
+                        .analyzed()
+                        .propertyIndex()
+                .enclosingRule()
+                    .property("baz")
+                    .propertyIndex();
+
+        NodeState state = builder.build();
+        assertTrue(state.getChildNode("indexRules").exists());
+        assertTrue(state.getChildNode("indexRules").getChildNode("nt:base").exists());
+        assertEquals(asList("/a", "/b"), state.getProperty(PathFilter.PROP_INCLUDED_PATHS).getValue(Type.STRINGS));
+        assertEquals(asList("/c", "/d"), state.getProperty(IndexConstants.QUERY_PATHS).getValue(Type.STRINGS));
+        assertEquals(asList("/e", "/f"), state.getProperty(IndexConstants.SUPERSEDED_INDEX_PATHS).getValue(Type.STRINGS));
+    }
+
+    @Test
+    public void propertyDefIndexPropertySetIndexFalse() throws Exception {
+        builder.indexRule("nt:base")
+                .property("foo")
+                .disable();
+
+        PropertyState state = builder.build().
+                getChildNode("indexRules").
+                getChildNode("nt:base").
+                getChildNode("properties").
+                getChildNode("foo").
+                getProperty("index");
+
+        assertNotNull("index property must exist", state);
+        assertFalse("Incorrect default value of index property", state.getValue(Type.BOOLEAN));
+    }
+
+    @Test
+    public void aggregates() throws Exception{
+        builder.aggregateRule("cq:Page").include("jcr:content").relativeNode();
+        builder.aggregateRule("dam:Asset", "*", "*/*");
+
+        NodeState state = builder.build();
+        assertTrue(state.getChildNode("aggregates").exists());
+        assertTrue(state.getChildNode("aggregates").getChildNode("dam:Asset").exists());
+        assertTrue(state.getChildNode("aggregates").getChildNode("cq:Page").exists());
+    }
+
+    @Test
+    public void duplicatePropertyName() throws Exception{
+        builder.indexRule("nt:base")
+                    .property("foo")
+                        .ordered()
+                .enclosingRule()
+                    .property("jcr:content/foo")
+                        .analyzed()
+                        .propertyIndex()
+                .enclosingRule()
+                    .property("metadata/content/foo")
+                        .propertyIndex();
+
+        NodeState state = builder.build();
+        assertTrue(state.getChildNode("indexRules").exists());
+        assertTrue(state.getChildNode("indexRules").getChildNode("nt:base").exists());
+        assertEquals(3, state.getChildNode("indexRules").getChildNode("nt:base")
+                .getChildNode("properties").getChildNodeCount(10));
+    }
+
+    @Test
+    public void ruleOrder() throws Exception{
+        builder.indexRule("nt:unstructured");
+        builder.indexRule("nt:base");
+
+        Tree tree = TreeFactory.createTree(EMPTY_NODE.builder());
+        builder.build(tree);
+
+        //Assert the order
+        Iterator<Tree> children = tree.getChild("indexRules").getChildren().iterator();
+        assertEquals("nt:unstructured", children.next().getName());
+        assertEquals("nt:base", children.next().getName());
+    }
+
+    @Test
+    public void regexProperty() throws Exception{
+        builder.indexRule("nt:base")
+                .property(FulltextIndexConstants.REGEX_ALL_PROPS, true);
+
+        NodeState state = builder.build();
+        assertTrue(NodeStateUtils.getNode(state, "indexRules/nt:base/properties/prop")
+                .getBoolean(FulltextIndexConstants.PROP_IS_REGEX));
+    }
+
+    @Test
+    public void mergeExisting() throws Exception{
+        nodeBuilder.setProperty("foo", "bar");
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+
+        NodeState state = builder.build();
+        assertEquals("bar", state.getString("foo"));
+        assertEquals("async", state.getString("async"));
+    }
+
+    @Test
+    public void mergeExisting_IndexRule() throws Exception{
+        builder.indexRule("nt:unstructured").property("foo").propertyIndex();
+
+        nodeBuilder = builder.build().builder();
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+
+        assertTrue(builder.hasIndexRule("nt:unstructured"));
+        assertFalse(builder.hasIndexRule("nt:base"));
+
+        builder.indexRule("nt:unstructured").property("bar").propertyIndex();
+        builder.indexRule("nt:base");
+
+        assertTrue(builder.indexRule("nt:unstructured").hasPropertyRule("foo"));
+        assertTrue(builder.indexRule("nt:unstructured").hasPropertyRule("bar"));
+    }
+
+    @Test
+    public void mergeExisting_Aggregates() throws Exception{
+        builder.aggregateRule("foo").include("/path1");
+        builder.aggregateRule("foo").include("/path2");
+
+        nodeBuilder = builder.build().builder();
+
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+
+        builder.aggregateRule("foo").include("/path1");
+        builder.aggregateRule("foo").include("/path3");
+
+        NodeState state = builder.build();
+        assertEquals(3, state.getChildNode(AGGREGATES).getChildNode("foo").getChildNodeCount(100));
+    }
+
+    @Test
+    public void noReindexIfNoChange() throws Exception{
+        builder.includedPaths("/a", "/b");
+        builder.indexRule("nt:base")
+                .property("foo")
+                .ordered();
+
+        nodeBuilder = builder.build().builder();
+        nodeBuilder.setProperty(REINDEX_PROPERTY_NAME, false);
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+        builder.includedPaths("/a", "/b");
+
+        assertFalse(builder.isReindexRequired());
+        NodeState state = builder.build();
+        assertFalse(state.getBoolean(REINDEX_PROPERTY_NAME));
+
+
+        NodeState baseState = builder.build();
+        nodeBuilder = baseState.builder();
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+        builder.indexRule("nt:file");
+
+        assertTrue(builder.isReindexRequired());
+        state = builder.build();
+        assertTrue(state.getBoolean(REINDEX_PROPERTY_NAME));
+
+        builder = new IndexDefinitionBuilder(baseState.builder(), false);
+        builder.indexRule("nt:file");
+        assertTrue(builder.isReindexRequired());
+        state = builder.build();
+        assertTrue(builder.isReindexRequired());
+        assertFalse(state.getBoolean(REINDEX_PROPERTY_NAME));
+    }
+
+    @Test
+    public void reindexAndAsyncFlagChange() throws Exception{
+        builder.async("async", IndexConstants.INDEXING_MODE_NRT);
+
+        nodeBuilder = builder.build().builder();
+        nodeBuilder.setProperty(REINDEX_PROPERTY_NAME, false);
+
+        NodeState oldState = nodeBuilder.getNodeState();
+
+        builder = new IndexDefinitionBuilder(nodeBuilder);
+        builder.async("async", IndexConstants.INDEXING_MODE_SYNC);
+        assertFalse(builder.build().getBoolean(REINDEX_PROPERTY_NAME));
+
+        builder = new IndexDefinitionBuilder(oldState.builder());
+        builder.async("fulltext-async", IndexConstants.INDEXING_MODE_SYNC);
+        assertTrue(builder.build().getBoolean(REINDEX_PROPERTY_NAME));
+    }
+
+    @Test
+    public void propRuleCustomName() throws Exception{
+        builder.indexRule("nt:base").property("foo").property("bar");
+        builder.indexRule("nt:base").property("fooProp", "foo2");
+        builder.indexRule("nt:base").property("fooProp", "foo2");
+
+        Root idx = new ImmutableRoot(builder.build());
+        assertTrue(idx.getTree("/indexRules/nt:base/properties/fooProp").exists());
+        assertTrue(idx.getTree("/indexRules/nt:base/properties/bar").exists());
+        assertTrue(idx.getTree("/indexRules/nt:base/properties/foo").exists());
+    }
+
+    @Test
+    public void typeNotChangedIfSet() throws Exception{
+        NodeState state = builder.build();
+        assertEquals("fulltext", state.getString("type"));
+
+        NodeBuilder updated = state.builder();
+        updated.setProperty("type", "disabled");
+        IndexDefinitionBuilder newBuilder = new IndexDefinitionBuilder(updated);
+
+        NodeState updatedState = newBuilder.build();
+        assertEquals("disabled", updatedState.getString("type"));
+
+        //Type other than 'disabled' would be reset
+        updated.setProperty("type", "foo");
+        assertEquals("fulltext", new IndexDefinitionBuilder(updated).build().getString("type"));
+    }
+
+    @Test
+    public void nodeTypeIndex() throws Exception{
+        builder.nodeTypeIndex();
+        builder.indexRule("nt:file");
+
+        NodeState state = builder.build();
+        assertTrue(state.getChildNode("indexRules").exists());
+        NodeState ntFileRule = state.getChildNode("indexRules").getChildNode("nt:file");
+        assertTrue(ntFileRule.exists());
+        assertTrue(state.getBoolean(FulltextIndexConstants.PROP_INDEX_NODE_TYPE));
+        assertFalse(ntFileRule.getBoolean(FulltextIndexConstants.PROP_SYNC));
+    }
+
+    @Test
+    public void nodeTypeIndexSync() throws Exception{
+        builder.nodeTypeIndex();
+        builder.indexRule("nt:file").sync();
+
+        NodeState state = builder.build();
+        assertTrue(state.getChildNode("indexRules").exists());
+        NodeState ntFileRule = state.getChildNode("indexRules").getChildNode("nt:file");
+        assertTrue(ntFileRule.exists());
+        assertTrue(state.getBoolean(FulltextIndexConstants.PROP_INDEX_NODE_TYPE));
+        assertTrue(ntFileRule.getBoolean(FulltextIndexConstants.PROP_SYNC));
+    }
+
+    @Test
+    public void noPropertiesNodeForEmptyRule() throws Exception{
+        builder.nodeTypeIndex();
+        builder.indexRule("nt:file").sync();
+
+        NodeState state = builder.build();
+        assertFalse(NodeStateUtils.getNode(state, "/indexRules/nt:file/properties").exists());
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtilsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtilsTest.java?rev=1828972&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtilsTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtilsTest.java Thu Apr 12 11:46:17 2018
@@ -0,0 +1,198 @@
+/*
+ * 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.plugins.index.search.util;
+
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Iterator;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.plugins.memory.ArrayBasedBlob;
+import org.apache.jackrabbit.oak.plugins.tree.factories.TreeFactory;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.util.ISO8601;
+import org.junit.After;
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.NT_OAK_UNSTRUCTURED;
+import static org.junit.Assert.assertEquals;
+
+public class NodeStateCopyUtilsTest {
+    private NodeBuilder builder = EMPTY_NODE.builder();
+    private Repository repository;
+
+    @After
+    public void cleanup(){
+        if (repository instanceof JackrabbitRepository) {
+            ((JackrabbitRepository) repository).shutdown();
+        }
+    }
+
+    @Test
+    public void copyUnordered() throws Exception{
+        builder.setProperty("foo", "x");
+        builder.child("a").setProperty("foo", "y");
+        builder.child("b").setProperty("foo", "z");
+        builder.child("a").child("c").setProperty("foo", "acx");
+
+        Tree tree = TreeFactory.createTree(EMPTY_NODE.builder());
+        NodeStateCopyUtils.copyToTree(builder.getNodeState(), tree);
+
+        assertEquals("x", tree.getProperty("foo").getValue(Type.STRING));
+        assertEquals(2, tree.getChildrenCount(100));
+        assertEquals("y", tree.getChild("a").getProperty("foo").getValue(Type.STRING));
+        assertEquals("z", tree.getChild("b").getProperty("foo").getValue(Type.STRING));
+        assertEquals("acx", tree.getChild("a").getChild("c").getProperty("foo").getValue(Type.STRING));
+    }
+
+    @Test
+    public void copyOrdered() throws Exception{
+        NodeBuilder testBuilder = EMPTY_NODE.builder();
+        Tree srcTree = TreeFactory.createTree(testBuilder);
+        srcTree.setOrderableChildren(true);
+        srcTree.setProperty("foo", "x");
+
+        srcTree.addChild("a").setOrderableChildren(true);
+        srcTree.addChild("a").setProperty("foo", "y");
+
+        srcTree.addChild("b").setOrderableChildren(true);
+        srcTree.addChild("b").setProperty("foo", "z");
+
+        Tree tree = TreeFactory.createTree(EMPTY_NODE.builder());
+        NodeStateCopyUtils.copyToTree(testBuilder.getNodeState(), tree);
+
+        assertEquals("x", tree.getProperty("foo").getValue(Type.STRING));
+        assertEquals(2, tree.getChildrenCount(100));
+        assertEquals("y", tree.getChild("a").getProperty("foo").getValue(Type.STRING));
+        assertEquals("z", tree.getChild("b").getProperty("foo").getValue(Type.STRING));
+
+        //Assert the order
+        Iterator<Tree> children = tree.getChildren().iterator();
+        assertEquals("a", children.next().getName());
+        assertEquals("b", children.next().getName());
+    }
+
+    @Test
+    public void copyToJcr() throws Exception{
+        repository = new Jcr().with(new OpenSecurityProvider()).createRepository();
+
+        Tree srcTree = TreeFactory.createTree(builder);
+        srcTree.setOrderableChildren(true);
+        srcTree.setProperty("foo", "x");
+        srcTree.setProperty("foo", "x");
+        srcTree.setProperty(JcrConstants.JCR_PRIMARYTYPE, NT_OAK_UNSTRUCTURED, Type.NAME);
+
+        srcTree.addChild("a").setOrderableChildren(true);
+        srcTree.addChild("a").setProperty("foo", "y");
+        srcTree.addChild("a").setProperty(JcrConstants.JCR_PRIMARYTYPE, NT_OAK_UNSTRUCTURED, Type.NAME);
+
+        srcTree.addChild("b").setOrderableChildren(true);
+        srcTree.addChild("b").setProperty("foo", "z");
+        srcTree.addChild("b").setProperty(JcrConstants.JCR_PRIMARYTYPE, NT_OAK_UNSTRUCTURED, Type.NAME);
+
+        Session session = repository.login(null, null);
+        Node node = session.getRootNode();
+        Node test = node.addNode("test", NT_OAK_UNSTRUCTURED);
+
+        NodeStateCopyUtils.copyToNode(builder.getNodeState(), test);
+        session.save();
+
+        test = session.getNode("/test");
+        assertEquals("y", test.getProperty("a/foo").getString());
+        assertEquals("z", test.getProperty("b/foo").getString());
+    }
+
+    @Test
+    public void copyToJcrAndHiddenProps() throws Exception{
+        repository = new Jcr().with(new OpenSecurityProvider()).createRepository();
+
+        Tree srcTree = TreeFactory.createTree(builder);
+        srcTree.addChild("a").setProperty("foo", "y");
+        srcTree.addChild("a").setProperty(JcrConstants.JCR_PRIMARYTYPE, NT_OAK_UNSTRUCTURED, Type.NAME);
+        builder.child(":hidden-node").setProperty("x", "y");
+        builder.setProperty(":hidden-prop", "y");
+
+        Session session = repository.login(null, null);
+        Node node = session.getRootNode();
+        Node test = node.addNode("test", NT_OAK_UNSTRUCTURED);
+
+        NodeStateCopyUtils.copyToNode(builder.getNodeState(), test);
+        session.save();
+
+        test = session.getNode("/test");
+        assertEquals("y", test.getProperty("a/foo").getString());
+    }
+
+    @Test
+    public void copyToJcrVariousProps() throws Exception{
+        repository = new Jcr().with(new OpenSecurityProvider()).createRepository();
+
+        Calendar cal = ISO8601.parse(ISO8601.format(Calendar.getInstance()));
+        Tree srcTree = TreeFactory.createTree(builder);
+        srcTree.setOrderableChildren(true);
+        srcTree.setProperty("fooString", "x");
+        srcTree.setProperty("fooLong", 1L, Type.LONG);
+        srcTree.setProperty("fooPath", "/fooNode", Type.PATH);
+        srcTree.setProperty("fooName", "mix:title", Type.NAME);
+        srcTree.setProperty("fooDouble", 1.0, Type.DOUBLE);
+        srcTree.setProperty("fooDate", ISO8601.format(cal), Type.DATE);
+        srcTree.setProperty("fooBoolean", true, Type.BOOLEAN);
+        srcTree.setProperty("fooStrings", asList("a", "b"), Type.STRINGS);
+        srcTree.setProperty("fooBlob", new ArrayBasedBlob("foo".getBytes()), Type.BINARY);
+        srcTree.setProperty(JcrConstants.JCR_PRIMARYTYPE, NT_OAK_UNSTRUCTURED, Type.NAME);
+
+        srcTree.setProperty(JcrConstants.JCR_MIXINTYPES, asList("mix:mimeType", "mix:title"), Type.NAMES);
+
+        Session session = repository.login(null, null);
+        Node node = session.getRootNode();
+        Node test = node.addNode("test", NT_OAK_UNSTRUCTURED);
+        Node fooNode = node.addNode("fooNode", NT_OAK_UNSTRUCTURED);
+
+        NodeStateCopyUtils.copyToNode(builder.getNodeState(), test);
+        session.save();
+
+        test = session.getNode("/test");
+        assertEquals("x", test.getProperty("fooString").getString());
+        assertEquals("/fooNode", test.getProperty("fooPath").getNode().getPath());
+        assertEquals("mix:title", test.getProperty("fooName").getString());
+        assertEquals(1, test.getProperty("fooLong").getLong());
+
+        assertEquals(cal, test.getProperty("fooDate").getDate());
+        assertEquals("a", test.getProperty("fooStrings").getValues()[0].getString());
+        assertEquals("b", test.getProperty("fooStrings").getValues()[1].getString());
+
+        InputStream is = test.getProperty("fooBlob").getBinary().getStream();
+        String streamVal = IOUtils.toString(is, "UTF-8");
+        assertEquals("foo", streamVal);
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtilsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native