You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2012/02/13 19:20:26 UTC
svn commit: r1243636 - in /commons/proper/vfs/trunk: ./ core/
core/src/test/java/org/apache/commons/vfs2/provider/test/
core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/
core/src/test/java/org/apache/commons/vfs2/provider/zip/test/ core/...
Author: ggregory
Date: Mon Feb 13 18:20:26 2012
New Revision: 1243636
URL: http://svn.apache.org/viewvc?rev=1243636&view=rev
Log:
[VFS-392] Build tests WebDAV file system with an embedded WebDAV server (Apache Jackrabbit).
Added:
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JackrabbitMain.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JcrUtils.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/zip/test/BugReport.java
Modified:
commons/proper/vfs/trunk/core/ (props changed)
commons/proper/vfs/trunk/core/pom.xml
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/test/JunctionProviderConfig.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/WebdavProviderTestCase.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/AbstractProviderTestConfig.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ContentTests.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderTestConfig.java
commons/proper/vfs/trunk/pom.xml
Propchange: commons/proper/vfs/trunk/core/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Feb 13 18:20:26 2012
@@ -3,3 +3,4 @@ target
.*
maven-eclipse.xml
bin
+jackrabbit
Modified: commons/proper/vfs/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/pom.xml?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/pom.xml (original)
+++ commons/proper/vfs/trunk/core/pom.xml Mon Feb 13 18:20:26 2012
@@ -119,6 +119,16 @@
<artifactId>httpcore-nio</artifactId>
<scope>test</scope>
</dependency>
+ <!-- Test WebDAV with Apache Jackrabbit-->
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-standalone</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<properties>
@@ -221,13 +231,13 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
- <version>1.5.6</version>
+ <version>1.5.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.5.6</version>
+ <version>1.5.5</version>
<scope>test</scope>
</dependency>
</dependencies>
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/test/JunctionProviderConfig.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/test/JunctionProviderConfig.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/test/JunctionProviderConfig.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/test/JunctionProviderConfig.java Mon Feb 13 18:20:26 2012
@@ -73,4 +73,9 @@ public class JunctionProviderConfig
return newFs.resolveFile(junctionPoint);
}
+
+ public boolean isFileSystemRootAccessible()
+ {
+ return true;
+ }
}
Added: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JackrabbitMain.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JackrabbitMain.java?rev=1243636&view=auto
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JackrabbitMain.java (added)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JackrabbitMain.java Mon Feb 13 18:20:26 2012
@@ -0,0 +1,268 @@
+/*
+ * 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.commons.vfs2.provider.webdav.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.servlet.jackrabbit.JackrabbitRepositoryServlet;
+import org.apache.jackrabbit.standalone.Main;
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.NCSARequestLog;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.bio.SocketConnector;
+import org.mortbay.jetty.handler.RequestLogHandler;
+import org.mortbay.jetty.servlet.ServletHolder;
+import org.mortbay.jetty.webapp.WebAppContext;
+
+/**
+ * Manages a Jackrabbit server instance.
+ *
+ * Copied and minimally changed from Jackrabbit's Main class in 1.5.2 to add a shutdown method.
+ *
+ * @since 2.1
+ */
+class JackrabbitMain
+{
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception
+ {
+ new JackrabbitMain(args).run();
+ }
+
+ private final Options options = new Options();
+
+ private final CommandLine command;
+
+ private final RequestLogHandler accessLog = new RequestLogHandler();
+
+ private final WebAppContext webapp = new WebAppContext();
+
+ private final Connector connector = new SocketConnector();
+
+ private final Server server = new Server();
+
+ public JackrabbitMain(String[] args) throws ParseException
+ {
+ options.addOption("?", "help", false, "print this message");
+ options.addOption("n", "notice", false, "print copyright notices");
+ options.addOption("l", "license", false, "print license information");
+
+ options.addOption("q", "quiet", false, "disable console output");
+ options.addOption("d", "debug", false, "enable debug logging");
+
+ options.addOption("h", "host", true, "IP address of the HTTP server");
+ options.addOption("p", "port", true, "TCP port of the HTTP server (8080)");
+ options.addOption("f", "file", true, "location of this jar file");
+ options.addOption("r", "repo", true, "repository directory (jackrabbit)");
+ options.addOption("c", "conf", true, "repository configuration file");
+
+ command = new GnuParser().parse(options, args);
+ }
+
+ private void copyToOutput(String resource) throws IOException
+ {
+ InputStream stream = JackrabbitMain.class.getResourceAsStream(resource);
+ try
+ {
+ IOUtils.copy(stream, System.out);
+ } finally
+ {
+ stream.close();
+ }
+ }
+
+ private void message(String message)
+ {
+ if (!command.hasOption("quiet"))
+ {
+ System.out.println(message);
+ }
+ }
+
+ private void prepareAccessLog(File log)
+ {
+ NCSARequestLog ncsa = new NCSARequestLog(new File(log, "access.log.yyyy_mm_dd").getPath());
+ ncsa.setFilenameDateFormat("yyyy-MM-dd");
+ accessLog.setRequestLog(ncsa);
+ }
+
+ private void prepareConnector()
+ {
+ String port = command.getOptionValue("port", "8080");
+ connector.setPort(Integer.parseInt(port));
+ String host = command.getOptionValue("host");
+ if (host != null)
+ {
+ connector.setHost(host);
+ }
+ }
+
+ private void prepareServerLog(File log) throws IOException
+ {
+ Layout layout = new PatternLayout("%d{dd.MM.yyyy HH:mm:ss} *%-5p* %c{1}: %m%n");
+
+ Logger jackrabbitLog = Logger.getRootLogger();
+ jackrabbitLog.addAppender(new FileAppender(layout, new File(log, "jackrabbit.log").getPath()));
+
+ Logger jettyLog = Logger.getLogger("org.mortbay.log");
+ jettyLog.addAppender(new FileAppender(layout, new File(log, "jetty.log").getPath()));
+ jettyLog.setAdditivity(false);
+
+ // if (command.hasOption("debug"))
+ // {
+ // jackrabbitLog.setLevel(Level.DEBUG);
+ // jettyLog.setLevel(Level.DEBUG);
+ // } else
+ // {
+ // jackrabbitLog.setLevel(Level.INFO);
+ // jettyLog.setLevel(Level.INFO);
+ // }
+ //
+ System.setProperty("derby.stream.error.file", new File(log, "derby.log").getPath());
+ }
+
+ private void prepareShutdown()
+ {
+ Runtime.getRuntime().addShutdownHook(new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ shutdown();
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ });
+ }
+
+ private void prepareWebapp(File file, File repository, File tmp)
+ {
+ webapp.setContextPath("/");
+ webapp.setWar(file.getPath());
+ webapp.setExtractWAR(false);
+ webapp.setTempDirectory(tmp);
+
+ ServletHolder servlet = new ServletHolder(JackrabbitRepositoryServlet.class);
+ servlet.setInitOrder(1);
+ servlet.setInitParameter("repository.home", repository.getPath());
+ String conf = command.getOptionValue("conf");
+ if (conf != null)
+ {
+ servlet.setInitParameter("repository.config", conf);
+ }
+ webapp.addServlet(servlet, "/repository.properties");
+ }
+
+ public void run() throws Exception
+ {
+ String defaultFile = "jackrabbit-standalone.jar";
+ URL location = Main.class.getProtectionDomain().getCodeSource().getLocation();
+ if (location != null && "file".equals(location.getProtocol()))
+ {
+ File file = new File(location.getPath());
+ if (file.isFile())
+ {
+ defaultFile = location.getPath();
+ }
+ }
+ File file = new File(command.getOptionValue("file", defaultFile));
+
+ if (command.hasOption("help"))
+ {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("java -jar " + file.getName(), options, true);
+ } else if (command.hasOption("notice"))
+ {
+ copyToOutput("/META-INF/NOTICE.txt");
+ } else if (command.hasOption("license"))
+ {
+ copyToOutput("/META-INF/LICENSE.txt");
+ } else
+ {
+ message("Welcome to Apache Jackrabbit!");
+ message("-------------------------------");
+
+ File repository = new File(command.getOptionValue("repo", "jackrabbit"));
+ message("Using repository directory " + repository);
+ repository.mkdirs();
+ File tmp = new File(repository, "tmp");
+ tmp.mkdir();
+ File log = new File(repository, "log");
+ log.mkdir();
+
+ message("Writing log messages to " + log);
+ prepareServerLog(log);
+
+ message("Starting the server...");
+ prepareWebapp(file, repository, tmp);
+ accessLog.setHandler(webapp);
+ prepareAccessLog(log);
+ server.setHandler(accessLog);
+ prepareConnector();
+ server.addConnector(connector);
+ prepareShutdown();
+
+ try
+ {
+ server.start();
+
+ String host = connector.getHost();
+ if (host == null)
+ {
+ host = "localhost";
+ }
+ message("Apache Jackrabbit is now running at " + "http://" + host + ":" + connector.getPort() + "/");
+ } catch (Throwable t)
+ {
+ System.err.println("Unable to start the server: " + t.getMessage());
+ System.exit(1);
+ }
+ }
+ }
+
+ public void shutdown() throws Exception, InterruptedException
+ {
+ message("Shutting down the server...");
+ server.stop();
+ server.join();
+ message("-------------------------------");
+ message("Goodbye from Apache Jackrabbit!");
+ }
+
+}
Added: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JcrUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JcrUtils.java?rev=1243636&view=auto
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JcrUtils.java (added)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/JcrUtils.java Mon Feb 13 18:20:26 2012
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+// COPIED FROM JACKRABBIT 2.4.0
+
+package org.apache.commons.vfs2.provider.webdav.test;
+
+import java.io.InputStream;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+/**
+ * Collection of static utility methods for use with the JCR 1.0 API and Apache Jackrabbit 1.5.2.
+ *
+ * Copied, adapted and pruned down from Jackrabbit 2.4.0.
+ *
+ * @since 2.1
+ */
+class JcrUtils
+{
+
+ private static final String NodeType_NT_RESOURCE = "nt:resource";
+
+ private static final String Node_JCR_CONTENT = "jcr:content";
+
+ private static final String NodeType_NT_FOLDER = "nt:folder";
+
+ private static final String NodeType_NT_FILE = "nt:file";
+
+ private static final String Property_JCR_MIMETYPE = "jcr:mimeType";
+
+ private static final String Property_JCR_ENCODING = "jcr:encoding";
+
+ private static final String Property_JCR_LAST_MODIFIED = "jcr:lastModified";
+
+ private static final String Property_JCR_DATA = "jcr:data";
+
+ /**
+ * Returns the named child of the given node, creating it as an nt:folder node if it does not already exist. The caller is expected to
+ * take care of saving or discarding any transient changes.
+ * <p>
+ * Note that the type of the returned node is <em>not</em> guaranteed to match nt:folder in case the node already existed. The caller
+ * can use an explicit {@link Node#isNodeType(String)} check if needed, or simply use a data-first approach and not worry about the node
+ * type until a constraint violation is encountered.
+ *
+ * @param parent
+ * parent node
+ * @param name
+ * name of the child node
+ * @return the child node
+ * @throws RepositoryException
+ * if the child node can not be accessed or created
+ */
+ public static Node getOrAddFolder(Node parent, String name) throws RepositoryException
+ {
+ return getOrAddNode(parent, name, NodeType_NT_FOLDER);
+ }
+
+ /**
+ * Returns the named child of the given node, creating the child if it does not already exist. If the child node gets added, then it is
+ * created with the given node type. The caller is expected to take care of saving or discarding any transient changes.
+ *
+ * @see Node#getNode(String)
+ * @see Node#addNode(String, String)
+ * @see Node#isNodeType(String)
+ * @param parent
+ * parent node
+ * @param name
+ * name of the child node
+ * @param type
+ * type of the child node, ignored if the child already exists
+ * @return the child node
+ * @throws RepositoryException
+ * if the child node can not be accessed or created
+ */
+ public static Node getOrAddNode(Node parent, String name, String type) throws RepositoryException
+ {
+ if (parent.hasNode(name))
+ {
+ return parent.getNode(name);
+ } else
+ {
+ return parent.addNode(name, type);
+ }
+ }
+
+ /**
+ * Creates or updates the named child of the given node. If the child does not already exist, then it is created using the nt:file node
+ * type. This file child node is returned from this method.
+ * <p>
+ * If the file node does not already contain a jcr:content child, then one is created using the nt:resource node type. The following
+ * properties are set on the jcr:content node:
+ * <dl>
+ * <dt>jcr:mimeType</dt>
+ * <dd>media type</dd>
+ * <dt>jcr:encoding (optional)</dt>
+ * <dd>charset parameter of the media type, if any</dd>
+ * <dt>jcr:lastModified</dt>
+ * <dd>current time</dd>
+ * <dt>jcr:data</dt>
+ * <dd>binary content</dd>
+ * </dl>
+ * <p>
+ * Note that the types of the returned node or the jcr:content child are <em>not</em> guaranteed to match nt:file and nt:resource in
+ * case the nodes already existed. The caller can use an explicit {@link Node#isNodeType(String)} check if needed, or simply use a
+ * data-first approach and not worry about the node type until a constraint violation is encountered.
+ * <p>
+ * The given binary content stream is closed by this method.
+ *
+ * @param parent
+ * parent node
+ * @param name
+ * name of the file
+ * @param mime
+ * media type of the file
+ * @param data
+ * binary content of the file
+ * @return the child node
+ * @throws RepositoryException
+ * if the child node can not be created or updated
+ */
+ public static Node putFile(Node parent, String name, String mime, InputStream data) throws RepositoryException
+ {
+ return putFile(parent, name, mime, data, Calendar.getInstance());
+ }
+
+ /**
+ * Creates or updates the named child of the given node. If the child does not already exist, then it is created using the nt:file node
+ * type. This file child node is returned from this method.
+ * <p>
+ * If the file node does not already contain a jcr:content child, then one is created using the nt:resource node type. The following
+ * properties are set on the jcr:content node:
+ * <dl>
+ * <dt>jcr:mimeType</dt>
+ * <dd>media type</dd>
+ * <dt>jcr:encoding (optional)</dt>
+ * <dd>charset parameter of the media type, if any</dd>
+ * <dt>jcr:lastModified</dt>
+ * <dd>date of last modification</dd>
+ * <dt>jcr:data</dt>
+ * <dd>binary content</dd>
+ * </dl>
+ * <p>
+ * Note that the types of the returned node or the jcr:content child are <em>not</em> guaranteed to match nt:file and nt:resource in
+ * case the nodes already existed. The caller can use an explicit {@link Node#isNodeType(String)} check if needed, or simply use a
+ * data-first approach and not worry about the node type until a constraint violation is encountered.
+ * <p>
+ * The given binary content stream is closed by this method.
+ *
+ * @param parent
+ * parent node
+ * @param name
+ * name of the file
+ * @param mime
+ * media type of the file
+ * @param data
+ * binary content of the file
+ * @param date
+ * date of last modification
+ * @return the child node
+ * @throws RepositoryException
+ * if the child node can not be created or updated
+ */
+ public static Node putFile(Node parent, String name, String mime, InputStream data, Calendar date)
+ throws RepositoryException
+ {
+ Value binary = parent.getSession().getValueFactory().createValue(data);
+ try
+ {
+ Node file = getOrAddNode(parent, name, NodeType_NT_FILE);
+ Node content = getOrAddNode(file, Node_JCR_CONTENT, NodeType_NT_RESOURCE);
+
+ content.setProperty(Property_JCR_MIMETYPE, mime);
+ String[] parameters = mime.split(";");
+ for (int i = 1; i < parameters.length; i++)
+ {
+ int equals = parameters[i].indexOf('=');
+ if (equals != -1)
+ {
+ String parameter = parameters[i].substring(0, equals);
+ if ("charset".equalsIgnoreCase(parameter.trim()))
+ {
+ content.setProperty(Property_JCR_ENCODING, parameters[i].substring(equals + 1).trim());
+ }
+ }
+ }
+
+ content.setProperty(Property_JCR_LAST_MODIFIED, date);
+ content.setProperty(Property_JCR_DATA, binary);
+ return file;
+ } finally
+ {
+ // JCR 2.0 API:
+ // binary.dispose();
+ }
+ }
+
+ /**
+ * Private constructor to prevent instantiation of this class.
+ */
+ private JcrUtils()
+ {
+ }
+}
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/WebdavProviderTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/WebdavProviderTestCase.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/WebdavProviderTestCase.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/webdav/test/WebdavProviderTestCase.java Mon Feb 13 18:20:26 2012
@@ -16,8 +16,24 @@
*/
package org.apache.commons.vfs2.provider.webdav.test;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+
import junit.framework.Test;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileSystemOptions;
@@ -27,53 +43,327 @@ import org.apache.commons.vfs2.provider.
import org.apache.commons.vfs2.provider.webdav.WebdavFileSystemConfigBuilder;
import org.apache.commons.vfs2.test.AbstractProviderTestConfig;
import org.apache.commons.vfs2.test.ProviderTestSuite;
+import org.apache.commons.vfs2.util.FreeSocketPortUtil;
+import org.apache.jackrabbit.core.TransientRepository;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
/**
* Test cases for the WebDAV provider.
- *
+ *
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
*/
-public class WebdavProviderTestCase
- extends AbstractProviderTestConfig
+public class WebdavProviderTestCase extends AbstractProviderTestConfig
{
+ private static final char[] PASSWORD = new char[0];
+
+ private static final String USER_ID = "admin";
+
+ private static int SocketPort;
+
private static final String TEST_URI = "test.webdav.uri";
- public static Test suite() throws Exception
+
+ private static JackrabbitMain JrMain;
+
+ /**
+ * Use %40 for @ in URLs
+ */
+ private static String ConnectionUri;
+
+ private static File RepoDirectory;
+
+ private static boolean DEBUG = Boolean.getBoolean("WebdavProviderTestCase.Debug");
+
+ public static File createTempDirectory() throws IOException
+ {
+ final File tempFile;
+
+ tempFile = File.createTempFile("WebdavProviderTestCase_", Long.toString(System.nanoTime()));
+
+ if (!tempFile.delete())
+ {
+ throw new IOException("Could not delete temp file: " + tempFile.getAbsolutePath());
+ }
+
+ if (!tempFile.mkdir())
+ {
+ throw new IOException("Could not create temp directory: " + tempFile.getAbsolutePath());
+ }
+
+ return tempFile;
+ }
+
+ private static void dump(File repoDirectory) throws Exception
+ {
+ TransientRepository repository = getTransientRepository(repoDirectory);
+ try
+ {
+ final Session session = getSession(repository);
+ message("Root node dump:");
+ dump(session.getRootNode());
+ session.logout();
+ } finally
+ {
+ repository.shutdown();
+ }
+ }
+
+ /** Recursively outputs the contents of the given node. */
+ private static void dump(Node node) throws RepositoryException
{
- if (System.getProperty(TEST_URI) != null)
+ // First output the node path
+ message(node.getPath());
+ // Skip the virtual (and large!) jcr:system subtree
+ if (node.getName().equals("jcr:system"))
+ {
+ return;
+ }
+
+ if (node.getName().equals("jcr:content"))
+ {
+ return;
+ }
+
+ // Then output the properties
+ PropertyIterator properties = node.getProperties();
+ while (properties.hasNext())
+ {
+ Property property = properties.nextProperty();
+ if (property.getDefinition().isMultiple())
+ {
+ // A multi-valued property, print all values
+ Value[] values = property.getValues();
+ for (Value value : values)
+ {
+ message(property.getPath() + " = " + value.getString());
+ }
+ } else
+ {
+ // A single-valued property
+ message(property.getPath() + " = " + property.getString());
+ }
+ }
+
+ // Finally output all the child nodes recursively
+ NodeIterator nodes = node.getNodes();
+ while (nodes.hasNext())
{
- ProviderTestSuite suite = new WebdavProviderTestSuite(new WebdavProviderTestCase());
- suite.addTests(WebdavVersioningTests.class);
- return suite;
+ dump(nodes.nextNode());
}
- else
+ }
+
+ private static Session getSession(TransientRepository repository) throws RepositoryException
+ {
+ return repository.login(new SimpleCredentials(USER_ID, PASSWORD));
+ }
+
+ private static String getSystemTestUriOverride()
+ {
+ return System.getProperty(TEST_URI);
+ }
+
+ private static TransientRepository getTransientRepository(File repoDirectory) throws IOException
+ {
+ // Jackrabbit 1.6:
+ // TransientRepository repository = new TransientRepository(repoDirectory);
+ // Jackrabbit 1.5.2:
+ return new TransientRepository(new File(repoDirectory, "repository.xml").toString(), repoDirectory.toString());
+ }
+
+ private static void importFiles(File repoDirectory, File sourceDir) throws Exception
+ {
+ TransientRepository repository = getTransientRepository(repoDirectory);
+ try
{
- return notConfigured(WebdavProviderTestCase.class);
+ final Session session = getSession(repository);
+ importFiles(session.getRootNode(), sourceDir);
+ session.save();
+ session.logout();
+ } finally
+ {
+ repository.shutdown();
+ }
+ }
+
+ private static void importFiles(final Node parent, final File sourceDir) throws RepositoryException, IOException
+ {
+ final File[] files = sourceDir.listFiles();
+ for (File file : files)
+ {
+ if (file.isFile())
+ {
+ final InputStream data = new FileInputStream(file);
+ try
+ {
+ message("Importing file " + file);
+ JcrUtils.putFile(parent, file.getName(), "application/octet-stream", data);
+ } finally
+ {
+ data.close();
+ }
+ } else if (file.isDirectory())
+ {
+ message("Importing folder " + file);
+ final Node folder = JcrUtils.getOrAddFolder(parent, file.getName());
+ importFiles(folder, file);
+ }
+ }
+ }
+
+ private static void message(IOException e)
+ {
+ if (DEBUG)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private static void message(String string)
+ {
+ if (DEBUG)
+ {
+ System.out.println(string);
}
}
/**
- * Prepares the file system manager.
+ * Creates and starts an embedded Apache WebDAV Server (Jackrabbit).
+ *
+ * @throws Exception
*/
- @Override
- public void prepare(final DefaultFileSystemManager manager)
- throws Exception
+ private static void setUpClass() throws Exception
{
- manager.addProvider("webdav", new WebdavFileProvider());
- manager.addProvider("tmp", new TemporaryFileProvider());
+ // Create temp dir for repo
+ RepoDirectory = createTempDirectory();
+ message("Created temp directory " + RepoDirectory);
+ // Populate repo
+ importFiles(RepoDirectory, new File(getTestDirectory()));
+ dump(RepoDirectory);
+ // Start server with temp repo
+ startJackrabbit(RepoDirectory);
+ message("Returned from org.apache.jackrabbit.standalone.Main " + SocketPort);
+ }
+
+ /**
+ * Starts an embedded Apache Jackrabbit server.
+ *
+ * @param repoDirectory
+ * @throws Exception
+ */
+ private static void startJackrabbit(File repoDirectory) throws Exception
+ {
+ boolean quiet = false;
+ if (!DEBUG)
+ {
+ Logger.getLogger("org.apache.jackrabbit").setLevel(Level.WARN);
+ Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.ERROR);
+ Logger.getLogger("org.apache.commons.vfs2").setLevel(Level.WARN);
+ Logger.getLogger("org.mortbay").setLevel(Level.WARN);
+ quiet = true;
+ }
+ JrMain = new JackrabbitMain(new String[]
+ { "--port", Integer.toString(SocketPort), "--repo", repoDirectory.toString(), quiet ? "--quiet" : "" });
+ JrMain.run();
+ }
+
+ public static Test suite() throws Exception
+ {
+ return new ProviderTestSuite(new WebdavProviderTestCase())
+ {
+ @Override
+ protected void setUp() throws Exception
+ {
+ if (getSystemTestUriOverride() == null)
+ {
+ setUpClass();
+ }
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ tearDownClass();
+ super.tearDown();
+ }
+ };
+ }
+
+ /**
+ * Tears down resources for this test case.
+ * <ol>
+ * <li>Shuts down the embedded Jackrabbit</li>
+ * <li>Extra clean up for org.apache.commons.httpclient.MultiThreadedHttpConnectionManager</li>
+ * <li>Remove temporary repository directory.</li>
+ * </ol>
+ * Stops the embedded Apache WebDAV Server.
+ *
+ * @throws Exception
+ * @throws
+ */
+ private static void tearDownClass() throws Exception
+ {
+ // Main JR shutdown
+ JrMain.shutdown();
+ // WARN logged because one thread is still there, so clean up explicitly.
+ MultiThreadedHttpConnectionManager.shutdownAll();
+ // Remove repo dir
+ try
+ {
+ message("Deleting temp directory " + RepoDirectory);
+ FileUtils.deleteDirectory(RepoDirectory);
+ } catch (IOException e)
+ {
+ message(e);
+ if (RepoDirectory.exists())
+ {
+ message("Directory will be deleted on VM exit " + RepoDirectory);
+ RepoDirectory.deleteOnExit();
+ }
+ }
+ }
+
+ public WebdavProviderTestCase() throws IOException
+ {
+ SocketPort = FreeSocketPortUtil.findFreeLocalPort();
+ message("FreeSocketPortUtil.findFreeLocalPort() = " + SocketPort);
+ // Use %40 for @ in a URL
+ // Any user id and password will do with the default Jackrabbit set up.
+ ConnectionUri = String.format("webdav://%s@localhost:%d/repository/default", USER_ID, SocketPort);
}
/**
* Returns the base folder for tests.
*/
@Override
- public FileObject getBaseTestFolder(final FileSystemManager manager)
- throws Exception
+ public FileObject getBaseTestFolder(final FileSystemManager manager) throws Exception
{
- WebdavFileSystemConfigBuilder builder =
- (WebdavFileSystemConfigBuilder)manager.getFileSystemConfigBuilder("webdav");
- final String uri = System.getProperty(TEST_URI);
+ String uri = getSystemTestUriOverride();
+ if (uri == null)
+ {
+ uri = ConnectionUri;
+ }
+ WebdavFileSystemConfigBuilder builder = (WebdavFileSystemConfigBuilder) manager
+ .getFileSystemConfigBuilder("webdav");
FileSystemOptions opts = new FileSystemOptions();
builder.setRootURI(opts, uri);
return manager.resolveFile(uri, opts);
}
+
+ @Override
+ public boolean isFileSystemRootAccessible()
+ {
+ return false;
+ }
+
+ /**
+ * Prepares the file system manager.
+ */
+ @Override
+ public void prepare(final DefaultFileSystemManager manager) throws Exception
+ {
+ manager.addProvider("webdav", new WebdavFileProvider());
+ manager.addProvider("tmp", new TemporaryFileProvider());
+ }
+
}
Added: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/zip/test/BugReport.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/zip/test/BugReport.java?rev=1243636&view=auto
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/zip/test/BugReport.java (added)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/zip/test/BugReport.java Mon Feb 13 18:20:26 2012
@@ -0,0 +1,76 @@
+package org.apache.commons.vfs2.provider.zip.test;
+
+import org.apache.commons.io.IOUtils;
+
+import org.apache.commons.vfs2.FileContent;
+
+import org.apache.commons.vfs2.FileObject;
+
+import org.apache.commons.vfs2.FileSystemManager;
+
+import org.apache.commons.vfs2.VFS;
+
+import java.io.ByteArrayOutputStream;
+
+import java.io.InputStream;
+
+/**
+ *
+ * Demonstrate a bug in commons vfs2:
+ *
+ * Closing a zip file object doesn't release the underlying file lock.
+ *
+ *
+ *
+ * Discovered on:
+ *
+ * Windows 7 pro SP1
+ *
+ * Java 1.6.0_20-b02 64-bit
+ *
+ * VFS maven version: org.apache.commons:commons-vfs2:2.0
+ */
+
+public class BugReport
+{
+
+ public static void main(String args[]) throws Exception
+ {
+
+ String zipFile = "zip:C:\\some-file.zip!some-zip-entry.xml";
+
+ FileSystemManager vfs = VFS.getManager();
+
+ FileObject file = vfs.resolveFile(zipFile);
+
+ FileContent content = file.getContent();
+
+ InputStream is = content.getInputStream(); // actually locks the file
+
+ // Optionally consume the input stream.
+
+ // This implicitly call close() on the input stream when finish reading.
+
+ // See DefaultFileContent.FileContentInputStream class and MonitorInputStream.read()
+
+ // But either way, the zip file is still locked.
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ IOUtils.copy(is, buffer);
+
+ // The following expected to unlock the file but they don't
+
+ IOUtils.closeQuietly(is);
+
+ content.close();
+
+ file.close(); // doesn't close the embedded ZipFileSystem which takes a file lock.
+
+ // Only this releases file lock.
+
+ vfs.closeFileSystem(file.getFileSystem());
+
+ }
+
+}
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/AbstractProviderTestConfig.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/AbstractProviderTestConfig.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/AbstractProviderTestConfig.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/AbstractProviderTestConfig.java Mon Feb 13 18:20:26 2012
@@ -55,4 +55,10 @@ public abstract class AbstractProviderTe
return cache;
}
+
+ public boolean isFileSystemRootAccessible()
+ {
+ return true;
+ }
+
}
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ContentTests.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ContentTests.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ContentTests.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ContentTests.java Mon Feb 13 18:20:26 2012
@@ -99,6 +99,10 @@ public class ContentTests
*/
public void testRootURI() throws FileSystemException
{
+ if (!this.getProviderConfig().isFileSystemRootAccessible())
+ {
+ return;
+ }
FileSystem fs = getReadFolder().getFileSystem();
String uri = fs.getRootURI();
testRoot(getManager().resolveFile(uri));
@@ -108,7 +112,11 @@ public class ContentTests
* Tests root of file system exists.
*/
public void testRootAPI() throws FileSystemException
- {
+ {
+ if (!this.getProviderConfig().isFileSystemRootAccessible())
+ {
+ return;
+ }
FileSystem fs = getReadFolder().getFileSystem();
testRoot(fs.getRoot());
}
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java Mon Feb 13 18:20:26 2012
@@ -30,12 +30,11 @@ import org.apache.commons.vfs2.FileType;
/**
* Read-only test cases for file providers.
- *
+ *
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
* @todo Test getLastModified(), getAttribute()
*/
-public class ProviderReadTests
- extends AbstractProviderTestCase
+public class ProviderReadTests extends AbstractProviderTestCase
{
/**
* Returns the capabilities required by the tests of this test case.
@@ -44,16 +43,11 @@ public class ProviderReadTests
protected Capability[] getRequiredCaps()
{
return new Capability[]
- {
- Capability.GET_TYPE,
- Capability.LIST_CHILDREN,
- Capability.READ_CONTENT
- };
+ { Capability.GET_TYPE, Capability.LIST_CHILDREN, Capability.READ_CONTENT };
}
/**
- * Walks the base folder structure, asserting it contains exactly the
- * expected files and folders.
+ * Walks the base folder structure, asserting it contains exactly the expected files and folders.
*/
public void testStructure() throws Exception
{
@@ -62,12 +56,9 @@ public class ProviderReadTests
}
/**
- * Walks a folder structure, asserting it contains exactly the
- * expected files and folders.
+ * Walks a folder structure, asserting it contains exactly the expected files and folders.
*/
- protected void assertSameStructure(final FileObject folder,
- final FileInfo expected)
- throws Exception
+ protected void assertSameStructure(final FileObject folder, final FileInfo expected) throws Exception
{
// Setup the structure
final List<FileInfo> queueExpected = new ArrayList<FileInfo>();
@@ -97,7 +88,7 @@ public class ProviderReadTests
int length = children.length;
if (info.children.size() != children.length)
{
- for (int i=0; i < children.length; ++i)
+ for (int i = 0; i < children.length; ++i)
{
if (children[i].getName().getBaseName().startsWith("."))
{
@@ -155,6 +146,10 @@ public class ProviderReadTests
*/
public void testRoot() throws FileSystemException
{
+ if (!this.getProviderConfig().isFileSystemRootAccessible())
+ {
+ return;
+ }
FileSystem fs = getReadFolder().getFileSystem();
String uri = fs.getRootURI();
final FileObject file = getManager().resolveFile(uri);
@@ -173,7 +168,8 @@ public class ProviderReadTests
final FileObject[] actualFiles = getReadFolder().findFiles(selector);
Arrays.sort(actualFiles);
FileObject prevActualFile = actualFiles[0];
- for (FileObject actualFile : actualFiles) {
+ for (FileObject actualFile : actualFiles)
+ {
assertTrue(prevActualFile.toString().compareTo(actualFile.toString()) <= 0);
prevActualFile = actualFile;
}
@@ -208,8 +204,7 @@ public class ProviderReadTests
{
folder.getContent().getInputStream();
fail();
- }
- catch (FileSystemException e)
+ } catch (FileSystemException e)
{
assertSameMessage("vfs.provider/read-not-file.error", folder, e);
}
@@ -233,8 +228,7 @@ public class ProviderReadTests
folder.exists();
folder.getType();
folder.getChildren();
- }
- finally
+ } finally
{
instr.close();
}
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderTestConfig.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderTestConfig.java?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderTestConfig.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/test/ProviderTestConfig.java Mon Feb 13 18:20:26 2012
@@ -23,11 +23,10 @@ import org.apache.commons.vfs2.impl.Defa
/**
* Test configuration for a file system.
- *
+ *
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
*/
-public interface ProviderTestConfig
-{
+public interface ProviderTestConfig {
/**
* Returns a DefaultFileSystemManager instance (or subclass instance).
*/
@@ -39,8 +38,7 @@ public interface ProviderTestConfig
void prepare(DefaultFileSystemManager manager) throws Exception;
/**
- * Returns the base folder for tests. This folder must exist, and contain
- * the following structure:
+ * Returns the base folder for tests. This folder must exist, and contain the following structure:
* <ul>
* <li>/read-tests
* <li>/write-tests
@@ -52,4 +50,13 @@ public interface ProviderTestConfig
* Returns the filesCache implementation used for tests.
*/
FilesCache getFilesCache();
+
+ /**
+ * Whether or not the root of test file system is accessible.
+ *
+ * For example, with the default Jackrabbit (WebDAV) server, the root is not accessible, but deeper paths are OK.
+ *
+ * @return Whether or not the root of test file system is accessible.
+ */
+ boolean isFileSystemRootAccessible();
}
Modified: commons/proper/vfs/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/pom.xml?rev=1243636&r1=1243635&r2=1243636&view=diff
==============================================================================
--- commons/proper/vfs/trunk/pom.xml (original)
+++ commons/proper/vfs/trunk/pom.xml Mon Feb 13 18:20:26 2012
@@ -17,9 +17,7 @@
limitations under the License.
-->
-<project
- xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.apache.commons</groupId>
@@ -370,13 +368,13 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
- <version>1.6.3</version>
+ <version>1.5.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.6.3</version>
+ <version>1.5.5</version>
<scope>test</scope>
</dependency>
<!-- Test SFTP with Apache SHHd Server (MINA) -->
@@ -405,6 +403,25 @@
<version>4.1.4</version>
<scope>test</scope>
</dependency>
+ <!-- Test WebDAV with Apache Jackrabbit -->
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-standalone</artifactId>
+ <version>1.5.2</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <!-- Exclude Derby due to a sealing violation -->
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -458,8 +475,8 @@
</site>
</distributionManagement>
- <!-- Releasing VFS as a multi-module build with binary artifacts is somewhat painful. This profile hooks into the commons-parent and the apache-pom
- to get the build done and then uses the assembly to package it up. -->
+ <!-- Releasing VFS as a multi-module build with binary artifacts is somewhat painful. This profile hooks into the commons-parent
+ and the apache-pom to get the build done and then uses the assembly to package it up. -->
<profiles>
<profile>
<id>include-sandbox</id>