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 2011/11/18 15:34:00 UTC
svn commit: r1203669 - in /commons/proper/vfs/trunk: ./ core/
core/src/test/java/org/apache/commons/vfs2/provider/http/test/ src/changes/
Author: ggregory
Date: Fri Nov 18 14:33:59 2011
New Revision: 1203669
URL: http://svn.apache.org/viewvc?rev=1203669&view=rev
Log:
[VFS-386] Build tests HTTP file system with an embedded HTTP server (Apache HttpComponent Core)
Added:
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/NHttpServer.java
Modified:
commons/proper/vfs/trunk/core/pom.xml
commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/HttpProviderTestCase.java
commons/proper/vfs/trunk/pom.xml
commons/proper/vfs/trunk/src/changes/changes.xml
Modified: commons/proper/vfs/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/pom.xml?rev=1203669&r1=1203668&r2=1203669&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/pom.xml (original)
+++ commons/proper/vfs/trunk/core/pom.xml Fri Nov 18 14:33:59 2011
@@ -16,7 +16,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -113,6 +113,12 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
+ <!-- Test HTTP with Apache HttpComponent Core -->
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-nio</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<properties>
Modified: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/HttpProviderTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/HttpProviderTestCase.java?rev=1203669&r1=1203668&r2=1203669&view=diff
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/HttpProviderTestCase.java (original)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/HttpProviderTestCase.java Fri Nov 18 14:33:59 2011
@@ -16,6 +16,8 @@
*/
package org.apache.commons.vfs2.provider.http.test;
+import java.io.IOException;
+
import junit.framework.Test;
import org.apache.commons.vfs2.FileObject;
@@ -24,46 +26,109 @@ import org.apache.commons.vfs2.impl.Defa
import org.apache.commons.vfs2.provider.http.HttpFileProvider;
import org.apache.commons.vfs2.test.AbstractProviderTestConfig;
import org.apache.commons.vfs2.test.ProviderTestSuite;
+import org.apache.commons.vfs2.util.FreeSocketPortUtil;
/**
* Test cases for the HTTP provider.
- *
+ *
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
*/
-public class HttpProviderTestCase
- extends AbstractProviderTestConfig
+public class HttpProviderTestCase extends AbstractProviderTestConfig
{
+ private static NHttpServer Server;
+
+ private static int SocketPort;
+
private static final String TEST_URI = "test.http.uri";
- public static Test suite() throws Exception
+
+ /**
+ * Use %40 for @ in URLs
+ */
+ private static String ConnectionUri;
+
+ private static String getSystemTestUriOverride()
{
- if (System.getProperty(TEST_URI) != null)
+ return System.getProperty(TEST_URI);
+ }
+
+ /**
+ * Creates and starts an embedded Apache HTTP Server ().
+ *
+ * @throws Exception
+ */
+ private static void setUpClass() throws Exception
+ {
+ Server = new NHttpServer();
+ if (!Server.run(SocketPort, getTestDirectory(), 5000))
{
- return new ProviderTestSuite(new HttpProviderTestCase());
+ throw new IllegalStateException("The embedded HTTP server has not completed startup, increase wait time");
}
- else
+ }
+
+ public static Test suite() throws Exception
+ {
+ return new ProviderTestSuite(new HttpProviderTestCase())
{
- return notConfigured(HttpProviderTestCase.class);
- }
+ @Override
+ protected void setUp() throws Exception
+ {
+ if (getSystemTestUriOverride() == null)
+ {
+ setUpClass();
+ }
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ tearDownClass();
+ super.tearDown();
+ }
+ };
}
/**
- * Prepares the file system manager.
+ * Stops the embedded Apache HTTP Server ().
+ *
+ * @throws IOException
*/
- @Override
- public void prepare(final DefaultFileSystemManager manager)
- throws Exception
+ private static void tearDownClass() throws IOException
{
- manager.addProvider("http", new HttpFileProvider());
+ if (Server != null)
+ {
+ Server.stop();
+ }
+
+ }
+
+ public HttpProviderTestCase() throws IOException
+ {
+ SocketPort = FreeSocketPortUtil.findFreeLocalPort();
+ // Use %40 for @ in the a URL a @
+ ConnectionUri = "http://localhost:" + SocketPort;
}
/**
* Returns the base folder for tests.
*/
@Override
- public FileObject getBaseTestFolder(final FileSystemManager manager)
- throws Exception
+ public FileObject getBaseTestFolder(final FileSystemManager manager) throws Exception
{
- final String uri = System.getProperty(TEST_URI);
+ String uri = getSystemTestUriOverride();
+ if (uri == null)
+ {
+ uri = ConnectionUri;
+ }
return manager.resolveFile(uri);
}
+
+ /**
+ * Prepares the file system manager.
+ */
+ @Override
+ public void prepare(final DefaultFileSystemManager manager) throws Exception
+ {
+ manager.addProvider("http", new HttpFileProvider());
+ }
}
Added: commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/NHttpServer.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/NHttpServer.java?rev=1203669&view=auto
==============================================================================
--- commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/NHttpServer.java (added)
+++ commons/proper/vfs/trunk/core/src/test/java/org/apache/commons/vfs2/provider/http/test/NHttpServer.java Fri Nov 18 14:33:59 2011
@@ -0,0 +1,298 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.commons.vfs2.provider.http.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Date;
+import java.util.Locale;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.httpclient.util.DateUtil;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpStatus;
+import org.apache.http.MethodNotSupportedException;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
+import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
+import org.apache.http.nio.NHttpConnection;
+import org.apache.http.nio.entity.NFileEntity;
+import org.apache.http.nio.entity.NStringEntity;
+import org.apache.http.nio.protocol.BufferingHttpServiceHandler;
+import org.apache.http.nio.protocol.EventListener;
+import org.apache.http.nio.reactor.IOEventDispatch;
+import org.apache.http.nio.reactor.IOReactorException;
+import org.apache.http.nio.reactor.ListeningIOReactor;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.SyncBasicHttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.HttpRequestHandlerRegistry;
+import org.apache.http.protocol.ImmutableHttpProcessor;
+import org.apache.http.protocol.ResponseConnControl;
+import org.apache.http.protocol.ResponseContent;
+import org.apache.http.protocol.ResponseDate;
+import org.apache.http.protocol.ResponseServer;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * Adapted from org.apache.http.examples.nio.NHttpServer.
+ *
+ * <p>
+ * Basic, yet fully functional and spec compliant, HTTP/1.1 server based on the non-blocking I/O model.
+ * </p>
+ * <p>
+ * Please note the purpose of this application is demonstrate the usage of HttpCore APIs. It is NOT intended to demonstrate the most
+ * efficient way of building an HTTP server.
+ * </p>
+ *
+ * @version $Id: $
+ * @since 2.1
+ */
+public class NHttpServer
+{
+
+ static class EventLogger implements EventListener
+ {
+ public void connectionClosed(final NHttpConnection conn)
+ {
+ System.out.println("Connection closed: " + conn);
+ }
+
+ public void connectionOpen(final NHttpConnection conn)
+ {
+ System.out.println("Connection open: " + conn);
+ }
+
+ public void connectionTimeout(final NHttpConnection conn)
+ {
+ System.out.println("Connection timed out: " + conn);
+ }
+
+ public void fatalIOException(final IOException ex, final NHttpConnection conn)
+ {
+ System.err.println("I/O error: " + ex.getMessage());
+ }
+
+ public void fatalProtocolException(final HttpException ex, final NHttpConnection conn)
+ {
+ System.err.println("HTTP error: " + ex.getMessage());
+ }
+ }
+
+ static class HttpFileHandler implements HttpRequestHandler
+ {
+ private final String docRoot;
+
+ public HttpFileHandler(final String docRoot)
+ {
+ super();
+ this.docRoot = docRoot;
+ }
+
+ public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context)
+ throws HttpException, IOException
+ {
+ String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
+ if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST"))
+ {
+ throw new MethodNotSupportedException(method + " method not supported");
+ }
+
+ if (request instanceof HttpEntityEnclosingRequest)
+ {
+ HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
+ byte[] entityContent = EntityUtils.toByteArray(entity);
+ System.out.println("Incoming entity content (bytes): " + entityContent.length);
+ }
+
+ String target = request.getRequestLine().getUri();
+ final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
+ if (!file.exists())
+ {
+ response.setStatusCode(HttpStatus.SC_NOT_FOUND);
+ NStringEntity entity = new NStringEntity("<html><body><h1>File" + file.getPath()
+ + " not found</h1></body></html>", "UTF-8");
+ entity.setContentType("text/html; charset=UTF-8");
+ response.setEntity(entity);
+ System.out.println("File " + file.getPath() + " not found");
+
+ } else if (!file.canRead())
+ {
+ response.setStatusCode(HttpStatus.SC_FORBIDDEN);
+ NStringEntity entity = new NStringEntity("<html><body><h1>Access denied</h1></body></html>", "UTF-8");
+ entity.setContentType("text/html; charset=UTF-8");
+ response.setEntity(entity);
+ System.out.println("Cannot read file " + file.getPath());
+
+ } else
+ {
+ response.setStatusCode(HttpStatus.SC_OK);
+ NFileEntity body = new NFileEntity(file, "text/html");
+ response.setEntity(body);
+ if (!response.containsHeader(HttpHeaders.LAST_MODIFIED))
+ {
+ response.addHeader(HttpHeaders.LAST_MODIFIED, DateUtil.formatDate(new Date(file.lastModified())));
+ }
+ System.out.println("Serving file " + file.getPath());
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ new NHttpServer().run(0, null, 0);
+ }
+
+ public volatile ListeningIOReactor ioReactor;
+
+ public boolean run(final int port, final String docRoot, long waitMillis) throws IOReactorException,
+ InterruptedException
+ {
+ Executors.newSingleThreadExecutor().execute(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ runBlock(port, docRoot);
+ } catch (IOReactorException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+ });
+ return waitForServerStartup(port, waitMillis);
+ }
+
+ private void runBlock(final int port, final String docRoot) throws IOReactorException
+ {
+ HttpParams params = new SyncBasicHttpParams();
+ params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
+ .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
+ .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+ .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
+ .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
+
+ HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpResponseInterceptor[]
+ { new ResponseDate(), new ResponseServer(), new ResponseContent(), new ResponseConnControl() });
+
+ BufferingHttpServiceHandler handler = new BufferingHttpServiceHandler(httpproc,
+ new DefaultHttpResponseFactory(), new DefaultConnectionReuseStrategy(), params);
+
+ // Set up request handlers
+ HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
+ reqistry.register("*", new HttpFileHandler(docRoot));
+
+ handler.setHandlerResolver(reqistry);
+
+ // Provide an event logger
+ handler.setEventListener(new EventLogger());
+
+ IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(handler, params);
+ ioReactor = new DefaultListeningIOReactor(2, params);
+ try
+ {
+ ioReactor.listen(new InetSocketAddress(port));
+ ioReactor.execute(ioEventDispatch);
+ } catch (InterruptedIOException ex)
+ {
+ System.err.println("Interrupted");
+ } catch (IOException e)
+ {
+ System.err.println("I/O error: " + e.getMessage());
+ }
+ System.out.println("Shutdown");
+ }
+
+ public void stop() throws IOException
+ {
+ if (this.ioReactor != null)
+ {
+ this.ioReactor.shutdown(2000);
+ }
+
+ }
+
+ /**
+ * Waits {@code waitMillis} for the server to start on the given {@code port}
+ *
+ * @param port
+ * The port the server is running on
+ * @param waitMillis
+ * How long to wail in milliseconds.
+ * @throws InterruptedException
+ * If waiting is interrupted
+ */
+ private boolean waitForServerStartup(final int port, long waitMillis) throws InterruptedException
+ {
+ final long endWait = System.currentTimeMillis() + waitMillis;
+ final String urlSpec = "http://localhost:" + port;
+ try
+ {
+ URL url = new URL(urlSpec);
+ InputStream inputStream = null;
+ while (System.currentTimeMillis() < endWait && inputStream == null)
+ {
+ try
+ {
+ inputStream = url.openStream();
+ if (inputStream != null)
+ {
+ IOUtils.closeQuietly(inputStream);
+ return true;
+ }
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ Thread.sleep(100);
+ }
+ } catch (MalformedURLException e)
+ {
+ throw new IllegalStateException("Error in test code for URL " + urlSpec);
+ }
+ return false;
+ }
+}
Modified: commons/proper/vfs/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/pom.xml?rev=1203669&r1=1203668&r2=1203669&view=diff
==============================================================================
--- commons/proper/vfs/trunk/pom.xml (original)
+++ commons/proper/vfs/trunk/pom.xml Fri Nov 18 14:33:59 2011
@@ -17,7 +17,6 @@
limitations under the License.
-->
-
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -399,6 +398,13 @@
<version>2.1</version>
<scope>test</scope>
</dependency>
+ <!-- Test HTTP with Apache HttpComponent Core -->
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore-nio</artifactId>
+ <version>4.1.3</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
Modified: commons/proper/vfs/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/src/changes/changes.xml?rev=1203669&r1=1203668&r2=1203669&view=diff
==============================================================================
--- commons/proper/vfs/trunk/src/changes/changes.xml (original)
+++ commons/proper/vfs/trunk/src/changes/changes.xml Fri Nov 18 14:33:59 2011
@@ -23,6 +23,9 @@
<body>
<release version="2.1" date="TBD" description="">
+ <action issue="VFS-386" dev="ggregory" type="update">
+ Build tests HTTP file system with an embedded HTTP server (Apache HttpComponent Core).
+ </action>
<action issue="VFS-385" dev="ggregory" type="update">
Add HTTP status code to HTTP file provider exception messages when available.
</action>