blob: 2186628251c1a721c70c114d668e1e523fc81fac [file] [log] [blame]
/*
* 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.observation;
import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.jcr.NoSuchWorkspaceException;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.Oak;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.ContentRepository;
import org.apache.jackrabbit.oak.api.ContentSession;
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.InitialContent;
import org.apache.jackrabbit.oak.security.SecurityProviderImpl;
import org.apache.jackrabbit.oak.spi.commit.CommitContext;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.Observer;
import org.apache.jackrabbit.oak.spi.commit.SimpleCommitContext;
import org.apache.jackrabbit.oak.spi.observation.ChangeSet;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
public class ChangeCollectorProviderTest {
ChangeCollectorProvider collectorProvider;
private ContentRepository contentRepository;
private ContentSession session;
private Recorder recorder;
private SecurityProviderImpl securityProvider;
class ContentChange {
final NodeState root;
final CommitInfo info;
ContentChange(NodeState root, CommitInfo info) {
this.root = root;
this.info = info;
}
}
class Recorder implements Observer {
List<ContentChange> changes = new LinkedList<ContentChange>();
@Override
public void contentChanged(@Nonnull NodeState root,@Nonnull CommitInfo info) {
changes.add(new ContentChange(root, info));
}
}
protected SecurityProvider getSecurityProvider() {
if (securityProvider == null) {
securityProvider = new SecurityProviderImpl(ConfigurationParameters.EMPTY);
}
return securityProvider;
}
/**
* Checks that the actual string set provided matches the expected one. A
* match is when all elements occur, irrespective of the order.
*/
private void assertMatches(String msg, Set<String> actuals, String... expected) {
if ((actuals == null || actuals.size() == 0) && expected.length != 0) {
fail("assertion failed for '" + msg + "': expected length " + expected.length + " != actual 0."
+ " Expected: '" + Arrays.toString(expected) + "', got: '" + actuals + "'");
} else if (expected.length == 0 && actuals != null && actuals.size() != 0) {
fail("assertion failed for '" + msg + "': expected length == 0, actual " + actuals.size() + "."
+ " Expected: '" + Arrays.toString(expected) + "', got: '" + actuals + "'");
} else if (expected.length != actuals.size()) {
fail("assertion failed for '" + msg + "': expected length (" + expected.length + ") != actual ("
+ actuals.size() + ")." + " Expected: '" + Arrays.toString(expected) + "', got: '" + actuals + "'");
}
for (String anExpected : expected) {
if (!actuals.contains(anExpected)) {
fail("assertion failed for '" + msg + "': expected '" + anExpected + "' not found. Got: '" + actuals
+ "'");
}
}
}
/**
* Assumes that the recorder got 1 call, and extracts the ChangeSet from
* that call
*/
private ChangeSet getSingleChangeSet() {
assertEquals(recorder.changes.size(), 1);
CommitContext commitContext = (CommitContext) recorder.changes.get(0).info.getInfo().get(CommitContext.NAME);
assertNotNull(commitContext);
ChangeSet changeSet = (ChangeSet) commitContext
.get(ChangeSet.COMMIT_CONTEXT_OBSERVATION_CHANGESET);
assertNotNull(changeSet);
return changeSet;
}
@Before
public void setup() throws PrivilegedActionException, CommitFailedException {
collectorProvider = new ChangeCollectorProvider();
recorder = new Recorder();
Oak oak = new Oak().with(new InitialContent()).with(collectorProvider).with(recorder)
.with(getSecurityProvider());
contentRepository = oak.createContentRepository();
session = Subject.doAs(SystemSubject.INSTANCE, new PrivilegedExceptionAction<ContentSession>() {
@Override
public ContentSession run() throws LoginException, NoSuchWorkspaceException {
return contentRepository.login(null, null);
}
});
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/").addChild("test");
rootTree.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:parentType", Type.NAME);
Tree child1 = rootTree.addChild("child1");
child1.setProperty("child1Prop", 1);
child1.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:childType", Type.NAME);
Tree grandChild1 = child1.addChild("grandChild1");
grandChild1.setProperty("grandChild1Prop", 1);
grandChild1.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:grandChildType", Type.NAME);
Tree greatGrandChild1 = grandChild1.addChild("greatGrandChild1");
greatGrandChild1.setProperty("greatGrandChild1Prop", 1);
greatGrandChild1.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:greatGrandChildType", Type.NAME);
Tree child2 = rootTree.addChild("child2");
child2.setProperty("child2Prop", 1);
child2.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:childType", Type.NAME);
Tree grandChild2 = child2.addChild("grandChild2");
grandChild2.setProperty("grandChild2Prop", 1);
grandChild2.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:grandChildType", Type.NAME);
recorder.changes.clear();
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child2", "/test/child1",
"/test/child1/grandChild1/greatGrandChild1", "/", "/test", "/test/child1/grandChild1",
"/test/child2/grandChild2");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "child2", "child1", "greatGrandChild1", "test",
"grandChild1", "grandChild2");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "child1Prop",
"child2Prop", "grandChild1Prop", "grandChild2Prop", "greatGrandChild1Prop");
// clear the recorder so that we start off empty
recorder.changes.clear();
}
private static CommitInfo newCommitInfoWithCommitContext(String sessionId, String userId) {
return new CommitInfo(sessionId, userId,
ImmutableMap.<String, Object> builder().put(CommitContext.NAME, new SimpleCommitContext()).build());
}
@Test
public void testNull() {
NodeBuilder builder = EMPTY_NODE.builder();
builder.setChildNode("test");
builder.setChildNode("a1").setChildNode("b1").setProperty("p1", 1);
NodeState before = builder.getNodeState();
builder = before.builder();
builder.setChildNode("a2").setChildNode("b12").setProperty("p12", "12");
NodeState after = builder.getNodeState();
assertNull(collectorProvider.getRootValidator(before, after, null));
assertNull(collectorProvider.getRootValidator(before, after, CommitInfo.EMPTY));
assertNotNull(collectorProvider.getRootValidator(before, after,
newCommitInfoWithCommitContext(CommitInfo.OAK_UNKNOWN, CommitInfo.OAK_UNKNOWN)));
}
@Test
public void testRemoveChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
assertTrue(rootTree.getChild("child1").remove());
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/child1", "/test/child1/grandChild1",
"/test/child1/grandChild1/greatGrandChild1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "child1", "grandChild1",
"greatGrandChild1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "child1Prop",
"grandChild1Prop", "greatGrandChild1Prop");
}
@Test
public void testRemoveGreatGrandChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
assertTrue(rootTree.getChild("child1").getChild("grandChild1").getChild("greatGrandChild1").remove());
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child1/grandChild1/greatGrandChild1",
"/test/child1/grandChild1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "grandChild1", "greatGrandChild1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:greatGrandChildType",
"test:grandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE,
"greatGrandChild1Prop");
}
@Test
public void testChangeGreatGrandChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
rootTree.getChild("child1").getChild("grandChild1").getChild("greatGrandChild1")
.setProperty("greatGrandChild1Prop", 2);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child1/grandChild1/greatGrandChild1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "greatGrandChild1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:greatGrandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), "greatGrandChild1Prop");
}
@Test
public void testChangeGreatAndGrandChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
rootTree.getChild("child1").getChild("grandChild1").setProperty("grandChild1Prop", 2);
rootTree.getChild("child1").getChild("grandChild1").getChild("greatGrandChild1")
.setProperty("greatGrandChild1Prop", 2);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child1/grandChild1",
"/test/child1/grandChild1/greatGrandChild1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "grandChild1", "greatGrandChild1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:grandChildType",
"test:greatGrandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType", "test:greatGrandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), "grandChild1Prop", "greatGrandChild1Prop");
}
@Test
public void testAddEmptyChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
rootTree.addChild("child");
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType");
assertMatches("propertyNames", changeSet.getPropertyNames());
}
@Test
public void testAddEmptyGrandChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree child = rootTree.addChild("child");
child.addChild("grandChild");
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/child");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "child");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType");
assertMatches("propertyNames", changeSet.getPropertyNames());
}
@Test
public void testAddNonEmptyGrandChild() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree child = rootTree.addChild("child");
child.setProperty("childProperty", 1);
Tree grandChild = child.addChild("grandChild");
grandChild.setProperty("grandChildProperty", 2);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/child", "/test/child/grandChild");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "child", "grandChild");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType");
assertMatches("propertyNames", changeSet.getPropertyNames(), "childProperty", "grandChildProperty");
}
@Test
public void testAddSomeChildren() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
for (int i = 0; i < 10; i++) {
Tree child = rootTree.addChild("x" + i);
child.setProperty(JcrConstants.JCR_PRIMARYTYPE, "test:type" + i, Type.NAME);
child.setProperty("foo" + i, "bar");
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/x0", "/test/x1", "/test/x2",
"/test/x3", "/test/x4", "/test/x5", "/test/x6", "/test/x7", "/test/x8", "/test/x9");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "x0", "x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "test:type0", "test:type1",
"test:type2", "test:type3", "test:type4", "test:type5", "test:type6", "test:type7", "test:type8",
"test:type9");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:type0", "test:type1",
"test:type2", "test:type3", "test:type4", "test:type5", "test:type6", "test:type7", "test:type8",
"test:type9");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "foo0", "foo1",
"foo2", "foo3", "foo4", "foo5", "foo6", "foo7", "foo8", "foo9");
}
@Test
public void testAddEmptyRemoveChildren() throws CommitFailedException {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree child = rootTree.addChild("child");
child.addChild("grandChild");
assertTrue(rootTree.getChild("child2").remove());
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/child", "/test/child2",
"/test/child2/grandChild2");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "child", "child2", "grandChild2");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType",
"test:grandChildType");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "child2Prop",
"grandChild2Prop");
}
@Test
public void testAddMaxPathDepthAll() throws CommitFailedException, PrivilegedActionException {
for (int i = 0; i < 16; i++) {
setup();
doAddMaxPathDepth(i);
}
}
private void doAddMaxPathDepth(int maxPathDepth) throws CommitFailedException {
collectorProvider.setMaxPathDepth(maxPathDepth);
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree next = rootTree;
for (int i = 0; i < 16; i++) {
next = next.addChild("n" + i);
if (i % 3 != 0) {
next.setProperty("nextProp" + i, i);
next.setProperty(JcrConstants.JCR_PRIMARYTYPE, i % 2 == 0 ? "test:even" : "test:odd", Type.NAME);
}
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
List<String> expectedParentPaths = new LinkedList<String>();
if (maxPathDepth == 0) {
expectedParentPaths.add("/");
} else {
expectedParentPaths.add("/test");
}
for (int i = 0; i < maxPathDepth - 1; i++) {
StringBuffer path = new StringBuffer("/test");
for (int j = 0; j < i; j++) {
path.append("/n" + j);
}
expectedParentPaths.add(path.toString());
}
assertMatches("parentPaths-" + maxPathDepth, changeSet.getParentPaths(),
expectedParentPaths.toArray(new String[0]));
assertMatches("parentNodeNames-" + maxPathDepth, changeSet.getParentNodeNames(), "test", "n0", "n1", "n2", "n3",
"n4", "n5", "n6", "n7", "n8", "n9", "n10", "n11", "n12", "n13",
"n14"/* , "n15" */);
assertMatches("parentNodeTypes-" + maxPathDepth, changeSet.getParentNodeTypes(), "test:parentType", "test:even",
"test:odd");
assertMatches("allNodeTypes-" + maxPathDepth, changeSet.getAllNodeTypes(), "test:parentType", "test:even", "test:odd");
assertMatches("propertyNames-" + maxPathDepth, changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE,
/* "nextProp0", */"nextProp1", "nextProp2", /* "nextProp3", */ "nextProp4",
"nextProp5"/* , "nextProp6" */
, "nextProp7", "nextProp8", /* "nextProp9", */"nextProp10", "nextProp11",
/* "nextProp12", */ "nextProp13",
"nextProp14"/* , "nextProp15" */);
}
@Test
public void testAddMixin() throws Exception {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
rootTree.addChild("child").setProperty(JcrConstants.JCR_MIXINTYPES, Arrays.asList("aMixin1", "aMixin2"),
Type.NAMES);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/child");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "child");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "aMixin1", "aMixin2");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "aMixin1", "aMixin2");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_MIXINTYPES);
}
@Test
public void testAddNodeWithProperties() throws Exception {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree aChild = rootTree.addChild("newchild");
aChild.setProperty("aProp", "aValue", Type.NAME);
aChild.setProperty(JcrConstants.JCR_PRIMARYTYPE, "aPrimaryType", Type.NAME);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test", "/test/newchild");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "test", "newchild");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType", "aPrimaryType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "aPrimaryType");
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "aProp");
}
@Test
public void testPathNotOverflown() throws Exception {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Set<String> expectedParentPaths = Sets.newHashSet();
expectedParentPaths.add("/test");
Set<String> expectedParentNodeNames = Sets.newHashSet();
expectedParentNodeNames.add("test");
Set<String> expectedParentNodeTypes = Sets.newHashSet();
expectedParentNodeTypes.add("test:parentType");
// do maxItems-1 iterations only, as the above already adds 1 item - to
// avoid overflowing
for (int i = 0; i < collectorProvider.getMaxItems() - 1; i++) {
Tree aChild = rootTree.addChild("manychildren" + i);
aChild.setProperty("aProperty", "foo");
aChild.setProperty(JcrConstants.JCR_PRIMARYTYPE, "aChildPrimaryType" + i, Type.NAME);
expectedParentPaths.add("/test/manychildren" + i);
expectedParentNodeNames.add("manychildren" + i);
expectedParentNodeTypes.add("aChildPrimaryType" + i);
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), expectedParentPaths.toArray(new String[0]));
assertMatches("parentNodeNames", changeSet.getParentNodeNames(),
expectedParentNodeNames.toArray(new String[0]));
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(),
expectedParentNodeTypes.toArray(new String[0]));
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(),
expectedParentNodeTypes.toArray(new String[0]));
assertMatches("propertyNames", changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE, "aProperty");
}
@Test
public void testPathOverflown() throws Exception {
doTestPathOverflown(0);
for (int overflowCnt = 1; overflowCnt <= 64 * 1024; overflowCnt += overflowCnt) {
doTestPathOverflown(overflowCnt);
}
}
private void doTestPathOverflown(int overflowCnt) throws CommitFailedException, PrivilegedActionException {
setup();
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
for (int i = 0; i < collectorProvider.getMaxItems() + overflowCnt; i++) {
rootTree.addChild("manychildren" + i).setProperty("aProperty", "foo");
;
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertEquals("parentPaths", null, changeSet.getParentPaths());
assertEquals("parentNodeNames", null, changeSet.getParentNodeNames());
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:parentType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType");
assertMatches("propertyNames", changeSet.getPropertyNames(), "aProperty");
}
@Test
public void testPropertyNotOverflown() throws Exception {
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree child1 = rootTree.getChild("child1");
Set<String> expectedPropertyNames = Sets.newHashSet();
for (int i = 0; i < collectorProvider.getMaxItems(); i++) {
child1.setProperty("aProperty" + i, "foo");
expectedPropertyNames.add("aProperty" + i);
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "child1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:childType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType");
assertMatches("propertyNames", changeSet.getPropertyNames(), expectedPropertyNames.toArray(new String[0]));
}
@Test
public void testPropertyOverflown() throws Exception {
for (int overflowCnt = 1; overflowCnt <= 64 * 1024; overflowCnt += overflowCnt) {
doTestPropertyOverflown(overflowCnt);
}
}
private void doTestPropertyOverflown(int overflowCnt) throws CommitFailedException, PrivilegedActionException {
setup();
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree child1 = rootTree.getChild("child1");
Set<String> expectedPropertyNames = Sets.newHashSet();
for (int i = 0; i < collectorProvider.getMaxItems() + overflowCnt; i++) {
child1.setProperty("aProperty" + i, "foo");
expectedPropertyNames.add("aProperty" + i);
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths", changeSet.getParentPaths(), "/test/child1");
assertMatches("parentNodeNames", changeSet.getParentNodeNames(), "child1");
assertMatches("parentNodeTypes", changeSet.getParentNodeTypes(), "test:childType");
assertMatches("allNodeTypes", changeSet.getAllNodeTypes(), "test:parentType", "test:childType");
assertEquals("propertyNames", null, changeSet.getPropertyNames());
}
@Test
public void testRemoveMaxPathDepthAll() throws CommitFailedException, PrivilegedActionException {
for (int i = 0; i < 16; i++) {
setup();
doRemoveMaxPathDepth(i);
}
}
private void doRemoveMaxPathDepth(int maxPathDepth) throws CommitFailedException {
collectorProvider.setMaxPathDepth(maxPathDepth);
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree next = rootTree;
for (int i = 0; i < 16; i++) {
next = next.addChild("n" + i);
if (i % 3 != 0) {
next.setProperty("nextProp" + i, i);
next.setProperty(JcrConstants.JCR_PRIMARYTYPE, i % 2 == 0 ? "test:even" : "test:odd", Type.NAME);
}
}
root.commit();
// now do the delete
recorder.changes.clear();
root = session.getLatestRoot();
rootTree = root.getTree("/test");
next = rootTree;
for (int i = 0; i < 15; i++) {
next = next.getChild("n" + i);
if (i == 14) {
next.remove();
}
}
root.commit();
ChangeSet changeSet = getSingleChangeSet();
Set<String> expectedParentPaths = new HashSet<String>();
String path = "/";
if (maxPathDepth == 1) {
path = "/test";
} else if (maxPathDepth > 1) {
path = "/test";
for (int i = 0; i < maxPathDepth - 1; i++) {
path = concat(path, "n" + i);
}
}
expectedParentPaths.add(path);
assertMatches("parentPaths-" + maxPathDepth, changeSet.getParentPaths(),
expectedParentPaths.toArray(new String[0]));
assertMatches("parentNodeNames-" + maxPathDepth, changeSet.getParentNodeNames(), "n13", "n14");
assertMatches("parentNodeTypes-" + maxPathDepth, changeSet.getParentNodeTypes(), "test:even", "test:odd");
assertMatches("allNodeTypes-" + maxPathDepth, changeSet.getAllNodeTypes(), "test:parentType", "test:even", "test:odd");
assertMatches("propertyNames-" + maxPathDepth, changeSet.getPropertyNames(), JcrConstants.JCR_PRIMARYTYPE,
"nextProp14");
}
@Test
public void testChangeMaxPathDepthAll() throws CommitFailedException, PrivilegedActionException {
for (int maxPathDepth = 0; maxPathDepth < 16; maxPathDepth++) {
for (int changeAt = 0; changeAt < 16; changeAt++) {
setup();
doChangeMaxPathDepth(changeAt, maxPathDepth);
}
}
}
private void doChangeMaxPathDepth(int changeAt, int maxPathDepth) throws CommitFailedException {
collectorProvider.setMaxPathDepth(maxPathDepth);
Root root = session.getLatestRoot();
Tree rootTree = root.getTree("/test");
Tree next = rootTree;
for (int i = 0; i < 16; i++) {
next = next.addChild("n" + i);
if (i % 3 != 0) {
next.setProperty("nextProp" + i, i);
next.setProperty(JcrConstants.JCR_PRIMARYTYPE, i % 2 == 0 ? "test:even" : "test:odd", Type.NAME);
}
}
root.commit();
recorder.changes.clear();
// now do the change
root = session.getLatestRoot();
rootTree = root.getTree("/test");
next = rootTree;
List<String> expectedParentPaths = new LinkedList<String>();
List<String> expectedParentNodeNames = new LinkedList<String>();
Set<String> expectedAllNodeTypes = new HashSet<String>();
List<String> expectedParentNodeTypes = new LinkedList<String>();
List<String> expectedPropertyNames = new LinkedList<String>();
expectedPropertyNames.add(JcrConstants.JCR_PRIMARYTYPE);
String parent = "/";
if (maxPathDepth > 0) {
parent = "/test";
}
expectedAllNodeTypes.add("test:parentType");
for (int i = 0; i <= changeAt; i++) {
String childName = "n" + i;
next = next.getChild(childName);
if (i < maxPathDepth - 1) {
parent = concat(parent, childName);
}
final String originalNodeTypeName = i % 2 == 0 ? "test:even" : "test:odd";
if (i % 3 != 0) {
if (i == changeAt) {
expectedParentNodeTypes.add(originalNodeTypeName);
}
expectedAllNodeTypes.add(originalNodeTypeName);
}
if (i == changeAt) {
expectedParentNodeNames.add(next.getName());
String propertyName = "nextProp" + i;
next.setProperty(propertyName, i + 1);
expectedPropertyNames.add(propertyName);
final String changedNodeTypeName = i % 2 == 0 ? "test:evenChanged" : "test:oddChanged";
expectedParentNodeTypes.add(changedNodeTypeName);
expectedAllNodeTypes.add(changedNodeTypeName);
next.setProperty(JcrConstants.JCR_PRIMARYTYPE, changedNodeTypeName, Type.NAME);
}
}
expectedParentPaths.add(parent);
root.commit();
ChangeSet changeSet = getSingleChangeSet();
assertMatches("parentPaths-" + changeAt + "-" + maxPathDepth, changeSet.getParentPaths(),
expectedParentPaths.toArray(new String[0]));
assertMatches("parentNodeNames-" + changeAt + "-" + maxPathDepth, changeSet.getParentNodeNames(),
expectedParentNodeNames.toArray(new String[0]));
assertMatches("parentNodeTypes-" + changeAt + "-" + maxPathDepth, changeSet.getParentNodeTypes(),
expectedParentNodeTypes.toArray(new String[0]));
assertMatches("allNodeTypes-" + changeAt + "-" + maxPathDepth, changeSet.getAllNodeTypes(),
expectedAllNodeTypes.toArray(new String[0]));
assertMatches("propertyNames-" + changeAt + "-" + maxPathDepth, changeSet.getPropertyNames(),
expectedPropertyNames.toArray(new String[0]));
}
}