blob: ed0e2f52b80c813f45ab1ba84c52e0f29fa8882e [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.upgrade;
import org.apache.jackrabbit.core.RepositoryContext;
import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder;
import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
import org.apache.jackrabbit.oak.segment.memory.MemoryStore;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
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.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import static org.junit.Assert.fail;
@RunWith(Parameterized.class)
public class LongNameTest {
private static final Logger LOG = LoggerFactory.getLogger(LongNameTest.class);
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() {
List<Object[]> params = new ArrayList<Object[]>();
params.add(new Object[] { "Short parent, short name", 349, 150, false });
params.add(new Object[] { "Short parent, long name", 349, 151, false });
params.add(new Object[] { "Long parent, short name", 350, 150, false });
params.add(new Object[] { "Long parent, long name", 350, 151, true });
return params;
}
private final String parentPath;
private final String nodeName;
private final boolean shouldBeSkipped;
@Rule
public final TemporaryFolder crxRepo = new TemporaryFolder(new File("target"));
public LongNameTest(String name, int parentPathLength, int nodeNameLength, boolean shouldBeSkipped) {
this.parentPath = generatePath(parentPathLength);
this.nodeName = generateNodeName(nodeNameLength);
this.shouldBeSkipped = shouldBeSkipped;
}
@Test
public void testMigrationToDocStore() throws IOException, CommitFailedException, RepositoryException {
SegmentNodeStore src = SegmentNodeStoreBuilders.builder(new MemoryStore()).build();
createNodes(src);
DocumentNodeStore dst = DocumentNodeStoreBuilder.newDocumentNodeStoreBuilder().build();
RepositorySidegrade sidegrade = new RepositorySidegrade(src, dst);
sidegrade.setFilterLongNames(true);
sidegrade.copy();
NodeState parent = getParent(dst);
Assert.assertTrue("Parent should exists", parent.exists());
if (shouldBeSkipped) {
Assert.assertFalse("Node shouldn't exists", parent.hasChildNode(nodeName));
} else {
Assert.assertTrue("Node should exists", parent.hasChildNode(nodeName));
}
}
@Test
public void testNodeOnDocStore() throws CommitFailedException {
DocumentNodeStore docStore = DocumentNodeStoreBuilder.newDocumentNodeStoreBuilder().build();
try {
createNodes(docStore);
if (shouldBeSkipped) {
fail("It shouldn't be possible to create a node");
}
} catch (CommitFailedException e) {
if (!shouldBeSkipped) {
LOG.warn("Unexpected exception", e);
fail("It should be possible to create a node");
}
}
}
@Test
@Ignore
public void testUpgradeToDocStore() throws IOException, CommitFailedException, RepositoryException {
File root = crxRepo.newFolder();
File source = new File(root, "source");
source.mkdirs();
RepositoryImpl sourceRepository = RepositoryContext.create(RepositoryConfig.install(source)).getRepository();
Session session = sourceRepository.login(new SimpleCredentials("admin", "admin".toCharArray()));
try {
Node node = session.getRootNode();
for (String s : PathUtils.elements(parentPath)) {
node = node.addNode(s);
}
node.addNode(nodeName);
session.save();
} finally {
session.logout();
}
sourceRepository.shutdown();
DocumentNodeStore dst = DocumentNodeStoreBuilder.newDocumentNodeStoreBuilder().build();
RepositoryContext ctx = RepositoryContext.create(RepositoryConfig.install(source));
RepositoryUpgrade upgrade = new RepositoryUpgrade(ctx, dst);
upgrade.setCheckLongNames(true);
try {
upgrade.copy(null);
if (shouldBeSkipped) {
fail("Jackrabbit2 Lucene index should be used to inform about the node with long name");
}
} catch (Exception e) {
if (!shouldBeSkipped) {
LOG.warn("Unexpected exception", e);
fail("Upgrade should be successful");
}
}
ctx.getRepository().shutdown();
ctx = RepositoryContext.create(RepositoryConfig.install(source));
upgrade = new RepositoryUpgrade(ctx, dst);
upgrade.setCheckLongNames(false);
upgrade.copy(null);
NodeState parent = getParent(dst);
Assert.assertTrue("Parent should exists", parent.exists());
if (shouldBeSkipped) {
Assert.assertFalse("Node shouldn't exists", parent.hasChildNode(nodeName));
} else {
Assert.assertTrue("Node should exists", parent.hasChildNode(nodeName));
}
}
private void createNodes(NodeStore ns) throws CommitFailedException {
NodeBuilder root = ns.getRoot().builder();
NodeBuilder nb = root;
for (String s : PathUtils.elements(parentPath)) {
nb = nb.child(s);
}
nb.child(nodeName);
ns.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
private static String generatePath(int length) {
if (length == 1) {
return "/";
}
Random random = new Random();
StringBuilder path = new StringBuilder();
while (path.length() < length) {
int remaining = length - path.length();
if (remaining == 1) {
path.append(generateNodeName(1));
} else {
path.append('/');
remaining--;
path.append(generateNodeName(1 + random.nextInt(Math.min(remaining, 150))));
}
}
return path.toString();
}
private static String generateNodeName(int length) {
Random random = new Random();
StringBuilder nodeName = new StringBuilder();
for (int i = 0; i < length; i++) {
nodeName.append((char) ('a' + random.nextInt('z' - 'a')));
}
return nodeName.toString();
}
private NodeState getParent(NodeStore ns) {
NodeState node = ns.getRoot();
for (String s : PathUtils.elements(parentPath)) {
node = node.getChildNode(s);
}
return node;
}
}