You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/02/26 22:49:14 UTC
svn commit: r631397 - in /jackrabbit/branches/1.3: ./ jackrabbit-core/
jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/
jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/
Author: jukka
Date: Tue Feb 26 13:49:05 2008
New Revision: 631397
URL: http://svn.apache.org/viewvc?rev=631397&view=rev
Log:
JCR-1400: Backport JCR-940: add db connection autoConnect for BundleDbPersistenceManager
- Added test case from JCR-1419
- Patch by Alexander Klimetschek
Added:
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/DatabaseConnectionFailureTest.java
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyProcess.java
jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyTest.java
Modified:
jackrabbit/branches/1.3/jackrabbit-core/pom.xml
jackrabbit/branches/1.3/pom.xml
Modified: jackrabbit/branches/1.3/jackrabbit-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/jackrabbit-core/pom.xml?rev=631397&r1=631396&r2=631397&view=diff
==============================================================================
--- jackrabbit/branches/1.3/jackrabbit-core/pom.xml (original)
+++ jackrabbit/branches/1.3/jackrabbit-core/pom.xml Tue Feb 26 13:49:05 2008
@@ -327,6 +327,16 @@
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbynet</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbyclient</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
Added: jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/DatabaseConnectionFailureTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/DatabaseConnectionFailureTest.java?rev=631397&view=auto
==============================================================================
--- jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/DatabaseConnectionFailureTest.java (added)
+++ jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/DatabaseConnectionFailureTest.java Tue Feb 26 13:49:05 2008
@@ -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.core.persistence;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.persistence.ext.ExternalDerbyTest;
+
+/**
+ * <code>DatabaseConnectionFailureTest</code> tests various situations in
+ * which the connection of a persistence manager or file system to its database
+ * is lost. If the server restarts properly, Jackrabbit should re-connect
+ * automatically and in the best case there is no data lost.
+ */
+public class DatabaseConnectionFailureTest extends ExternalDerbyTest {
+
+ // this test takes about 2 mins and is not very important (it verifies
+ // that an RepositoryException is thrown if the database server behind
+ // the persistence manager is killed)
+/*
+ // external derby process
+ public void testConnectionBroken() throws Exception {
+ startExternalDerby();
+
+ startJackrabbitWithExternalDerby();
+ Session session = helper.getSuperuserSession();
+
+ // do something jcr-like
+ jcrWorkA(session);
+ session.save();
+
+ killExternalDerby();
+
+ // do something jcr-like => expect RepositoryException
+ jcrWorkB(session);
+
+ long start = System.currentTimeMillis();
+ try {
+ // with the auto-reconnect feature in Bundle PMs, this save will trigger
+ // a loop of connection trials that will all fail, because we killed
+ // the server. this typically takes about 2 mins before finally a
+ // RepositoryException is thrown.
+ session.save();
+
+ assertTrue("RepositoryException was expected (waiting some time is normal)", false);
+ } catch (RepositoryException e) {
+ // fine, exception is expected
+ }
+ long end = System.currentTimeMillis();
+ logger.debug("time taken: " + (end - start));
+ }
+*/
+
+ // external derby process
+ public void testConnectionBrokenAndReconnect() throws Exception {
+ startExternalDerby();
+
+ startJackrabbitWithExternalDerby();
+ Session session = helper.getSuperuserSession();
+
+ // do something jcr-like
+ jcrWorkA(session);
+ session.save();
+
+ killExternalDerby();
+
+ // RESTART derby
+ startExternalDerby();
+
+ // do something jcr-like => works again, maybe data corrupted
+ jcrWorkB(session);
+
+ // an exception here means that the PM does not properly re-connect to the database
+ session.save();
+ }
+
+ // The following test cases are just ideas for testing an embedded derby
+/*
+ // embedded derby
+ public void testConnectionClosed() throws Exception {
+ // start derby
+ // start jackrabbit + derby pm/file system
+ // do something jcr-like
+ // SHUTDOWN derby
+ // do something jcr-like => expect RepositoryException
+ }
+
+ // embedded derby
+ public void testConnectionClosedAndReconnect() throws Exception {
+ // start derby
+ // start jackrabbit + derby pm/file system
+ // do something jcr-like
+ // SHUTDOWN derby
+ // RESTART derby
+ // do something jcr-like => everything should work normally
+ }
+*/
+}
Added: jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java?rev=631397&view=auto
==============================================================================
--- jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java (added)
+++ jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java Tue Feb 26 13:49:05 2008
@@ -0,0 +1,43 @@
+/*
+ * 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.core.persistence;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all jackrabbit specific testcases for the
+ * persistence module.
+ */
+public class TestAll extends TestCase {
+
+ /**
+ * Returns a <code>Test</code> suite that executes all tests inside this
+ * package.
+ *
+ * @return a <code>Test</code> suite that executes all tests inside this
+ * package.
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite("Persistence tests");
+
+ suite.addTestSuite(DatabaseConnectionFailureTest.class);
+
+ return suite;
+ }
+}
Added: jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyProcess.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyProcess.java?rev=631397&view=auto
==============================================================================
--- jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyProcess.java (added)
+++ jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyProcess.java Tue Feb 26 13:49:05 2008
@@ -0,0 +1,151 @@
+/*
+ * 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.core.persistence.ext;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.derby.drda.NetworkServerControl;
+import org.apache.derby.jdbc.EmbeddedDriver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>ExternalDerbyProcess</code> is a helper class for starting
+ * an external derby server on localhost, port 1527 (standard settings).
+ *
+ */
+public class ExternalDerbyProcess {
+
+ public static Logger logger = LoggerFactory.getLogger(ExternalDerbyProcess.class);
+
+ public static void setLogger(Logger aLogger) {
+ logger = aLogger;
+ }
+
+ /**
+ * Returns the path to the JAR file that a certain class is located in. This only works
+ * if the classloader loaded this class from a JAR file.
+ */
+ public static final String getJarFileForClass(Class clazz) {
+ // eg. /org/apache/derby/drda/NetworkServerControl.class
+ String classResource = "/" + clazz.getCanonicalName().replace(".", "/") + ".class";
+ // eg. jar:file:/Users/alex/.m2/repository/org/apache/derby/derbynet/10.2.1.6/derbynet-10.2.1.6.jar!/org/apache/derby/drda/NetworkServerControl.class
+ String fullResourceURL = clazz.getResource(classResource).toString();
+ // eg. /Users/alex/.m2/repository/org/apache/derby/derbynet/10.2.1.6/derbynet-10.2.1.6.jar
+ return fullResourceURL.replaceFirst("jar:file:([^!]+).*", "$1");
+ }
+
+ public static final String EXTERNAL_DERBY_JDBC_DRIVER = "org.apache.derby.jdbc.ClientDriver";
+
+ public static final String EXTERNAL_DERBY_USER = "cloud";
+
+ public static final String EXTERNAL_DERBY_PASSWORD = "scape";
+
+ private static final String DERBY_JAVA_CMD =
+ "-Dderby.drda.logConnections=true org.apache.derby.drda.NetworkServerControl start";
+
+ private static final int DERBY_STARTUP_TIME = 1000; // ms
+
+ private static List processes = new ArrayList();
+
+ public static Process start() throws IOException, InterruptedException {
+ // Let's create a hand-made pid
+ final String prefix = "[derby server " + (processes.size() + 1) + "]: ";
+
+ // derby server needs classpath with:
+ // org.apache.derby:derby
+ // org.apache.derby:derbynet
+ String derbyJar = getJarFileForClass(EmbeddedDriver.class);
+ String derbyNetJar = getJarFileForClass(NetworkServerControl.class);
+
+ String classPath = System.getProperty("java.class.path");
+ classPath += File.pathSeparatorChar + derbyJar;
+ classPath += File.pathSeparatorChar + derbyNetJar;
+
+ String cmd = "java -cp " + classPath + " " + DERBY_JAVA_CMD;
+ logger.info(prefix + "Starting " + cmd);
+
+ final Process p = Runtime.getRuntime().exec(cmd);
+ processes.add(p);
+
+ // log stdout and stderr to our console
+ Thread stdoutThread = new Thread(new InputStream2ConsolePrinter(p.getInputStream(), prefix, false));
+ Thread stderrThread = new Thread(new InputStream2ConsolePrinter(p.getErrorStream(), prefix, true));
+ stdoutThread.start();
+ stderrThread.start();
+
+ // write the exit code on the console when the process ends
+ Thread exitCodeThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ logger.debug(prefix + "Exit code: " + p.waitFor());
+ } catch (InterruptedException e) {
+ logger.error("Interrupted while waiting for external derby process", e);
+ }
+ }
+ });
+ exitCodeThread.start();
+
+ // wait for the server to start
+ Thread.sleep(DERBY_STARTUP_TIME);
+
+ return p;
+ }
+
+ public static void killAll() {
+ for (int i=0; i < processes.size(); i++) {
+ logger.debug("Killing derby server " + i);
+ ((Process) processes.get(i)).destroy();
+ }
+ }
+
+ private static class InputStream2ConsolePrinter implements Runnable {
+
+ private BufferedReader input;
+ private String prefix;
+ private boolean toStdErr;
+
+ public InputStream2ConsolePrinter(InputStream is, String prefix, boolean toStdErr) {
+ this.input = new BufferedReader(new InputStreamReader(is));
+ this.prefix = prefix;
+ this.toStdErr = toStdErr;
+ }
+
+ public void run() {
+ String line;
+ try {
+ while ((line = input.readLine()) != null) {
+ if (toStdErr) {
+ logger.warn(prefix + line);
+ } else {
+ logger.debug(prefix + line);
+ }
+ }
+ input.close();
+ } catch (IOException e) {
+ }
+ }
+
+ }
+
+}
Added: jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyTest.java?rev=631397&view=auto
==============================================================================
--- jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyTest.java (added)
+++ jackrabbit/branches/1.3/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/ext/ExternalDerbyTest.java Tue Feb 26 13:49:05 2008
@@ -0,0 +1,161 @@
+/*
+ * 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.core.persistence.ext;
+
+import java.io.File;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.test.JUnitTest;
+import org.apache.jackrabbit.test.RepositoryHelper;
+import org.apache.jackrabbit.test.config.DynamicRepositoryHelper;
+import org.apache.jackrabbit.test.config.PersistenceManagerConf;
+import org.apache.jackrabbit.test.config.RepositoryConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>ExternalDerbyTest</code> is an abstract base class for jackrabbit
+ * persistence manager tests that need to connect to an external derby
+ * server for testing connection problems, data loss etc., which can
+ * be easily done by manipulating the external process.
+ *
+ * This test class does not use {@link #setUp()} to setup the repository, but
+ * instead it is required to call {@link #startExternalDerby()} and
+ * {@link #startJackrabbitWithExternalDerby()}.
+ */
+public abstract class ExternalDerbyTest extends JUnitTest {
+
+ /**
+ * Helper object to access repository transparently
+ */
+ public static RepositoryHelper helper = new RepositoryHelper();
+
+ private static final String REPO_HOME = "target/repository";
+
+ protected final Logger logger = LoggerFactory.getLogger(JUnitTest.class);
+
+ protected Process derbyProcess;
+
+ protected void setUp() {
+ // do nothing here, ie. don't set up helper with a new repo
+ }
+
+ protected void tearDown() {
+ killExternalDerby();
+ }
+
+ protected void startExternalDerby() throws Exception {
+ logger.debug("Starting external derby server...");
+
+ ExternalDerbyProcess.setLogger(logger);
+ derbyProcess = ExternalDerbyProcess.start();
+
+ try {
+ int exitCode = derbyProcess.exitValue();
+ throw new Exception("Derby server for testing did not start properly, exit code is " + exitCode);
+ } catch (IllegalThreadStateException e) {
+ // happens when the process is still running, which is good
+ }
+ }
+
+ protected void killExternalDerby() {
+ if (derbyProcess != null) {
+ try {
+ derbyProcess.exitValue();
+ // if there is no exception, derby has quit already
+ return;
+ } catch (IllegalThreadStateException e) {
+ // happens when the process is still running
+ }
+
+ logger.debug("Killing external derby server...");
+ derbyProcess.destroy();
+ }
+ }
+
+ protected RepositoryConf createRepositoryConf() {
+ RepositoryConf conf = new RepositoryConf();
+
+ // set jdbc urls on PMs for external derby
+ // workspaces
+ PersistenceManagerConf pmc = conf.getWorkspaceConfTemplate().getPersistenceManagerConf();
+ pmc.setParameter("url", "jdbc:derby://localhost/${wsp.home}/version/db/itemState;create=true");
+ pmc.setParameter("driver", ExternalDerbyProcess.EXTERNAL_DERBY_JDBC_DRIVER);
+ pmc.setParameter("user", ExternalDerbyProcess.EXTERNAL_DERBY_USER);
+ pmc.setParameter("password", ExternalDerbyProcess.EXTERNAL_DERBY_PASSWORD);
+ // false is the default value anyway, but we want to make sure, the code does not block forever
+ pmc.setParameter("blockOnConnectionLoss", "false");
+
+ // versioning
+ pmc = conf.getVersioningConf().getPersistenceManagerConf();
+ pmc.setParameter("url", "jdbc:derby://localhost/${rep.home}/db/itemState;create=true");
+ pmc.setParameter("driver", ExternalDerbyProcess.EXTERNAL_DERBY_JDBC_DRIVER);
+ pmc.setParameter("user", ExternalDerbyProcess.EXTERNAL_DERBY_USER);
+ pmc.setParameter("password", ExternalDerbyProcess.EXTERNAL_DERBY_PASSWORD);
+ // false is the default value anyway, but we want to make sure, the code does not block forever
+ pmc.setParameter("blockOnConnectionLoss", "false");
+
+ return conf;
+ }
+
+ protected void startJackrabbitWithExternalDerby() throws RepositoryException {
+ // clean up
+ shutdownJackrabbit();
+ deleteDirectory(new File(REPO_HOME));
+
+ logger.debug("Starting jackrabbit...");
+ helper = new DynamicRepositoryHelper(createRepositoryConf(), REPO_HOME);
+ }
+
+ protected void shutdownJackrabbit() {
+ if (helper != null && helper instanceof DynamicRepositoryHelper) {
+ logger.debug("Stopping jackrabbit...");
+ ((DynamicRepositoryHelper) helper).shutdown();
+ }
+ }
+
+ protected void jcrWorkA(Session session) throws RepositoryException {
+ Node rootNode = session.getRootNode();
+ Node node = rootNode.addNode("test");
+ node.setProperty("prop", "foobar");
+ }
+
+ protected void jcrWorkB(Session session) throws RepositoryException {
+ Node rootNode = session.getRootNode();
+ Node node = rootNode.addNode("test2");
+ node.setProperty("prop", "foobar");
+ }
+
+ public static boolean deleteDirectory(File path) {
+ if (path.exists()) {
+ File[] files = path.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ deleteDirectory(files[i]);
+ } else {
+ files[i].delete();
+ }
+ }
+ }
+ return (path.delete());
+ }
+
+}
Modified: jackrabbit/branches/1.3/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.3/pom.xml?rev=631397&r1=631396&r2=631397&view=diff
==============================================================================
--- jackrabbit/branches/1.3/pom.xml (original)
+++ jackrabbit/branches/1.3/pom.xml Tue Feb 26 13:49:05 2008
@@ -693,6 +693,16 @@
<version>10.2.1.6</version>
</dependency>
<dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbynet</artifactId>
+ <version>10.2.1.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbyclient</artifactId>
+ <version>10.2.1.6</version>
+ </dependency>
+ <dependency>
<groupId>poi</groupId>
<artifactId>poi</artifactId>
<version>2.5.1-final-20040804</version>