From 5dc7c8c389b80ccb9c6fe969fc4685554ce79bc3 Mon Sep 17 00:00:00 2001
From: Andrew Azores <aazores@redhat.com>
Date: Mon, 12 Aug 2013 10:00:49 -0400
Subject: Refactored TinyHttpdImpl. Changed constructor, reflect this in
 ServerLauncher. Unit tests moved out of ServerAccessTest into new
 TinyHttpdImplTest. New unit tests added.

---
 .../net/sourceforge/jnlp/TinyHttpdImplTest.java    | 226 +++++++++++++++++++++
 1 file changed, 226 insertions(+)
 create mode 100644 tests/test-extensions-tests/net/sourceforge/jnlp/TinyHttpdImplTest.java

(limited to 'tests/test-extensions-tests/net/sourceforge/jnlp/TinyHttpdImplTest.java')

diff --git a/tests/test-extensions-tests/net/sourceforge/jnlp/TinyHttpdImplTest.java b/tests/test-extensions-tests/net/sourceforge/jnlp/TinyHttpdImplTest.java
new file mode 100644
index 0000000..e7567f5
--- /dev/null
+++ b/tests/test-extensions-tests/net/sourceforge/jnlp/TinyHttpdImplTest.java
@@ -0,0 +1,226 @@
+package net.sourceforge.jnlp;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URLDecoder;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TinyHttpdImplTest {
+
+    private static final String HTTP_OK = "HTTP/1.0 200 OK";
+    private static final String HTTP_400 = "HTTP/1.0 400 Bad Request";
+    private static final String HTTP_404 = "HTTP/1.0 404 Not Found";
+    private static final String HTTP_501 = "HTTP/1.0 501 Not Implemented";
+    private static final String CONTENT_JNLP = "Content-Type: application/x-java-jnlp-file";
+    private static final String CONTENT_HTML = "Content-Type: text/html";
+    private static final String CONTENT_JAR = "Content-Type: application/x-jar";
+    private static final Pattern CONTENT_LENGTH = Pattern.compile("Content-Length:([0-9]+)");
+
+    private static final String[] FilePathTestUrls = {
+            "/foo.html",
+            "/foo/",
+            "/foo/bar.jar",
+            "/foo/bar.jar;path_param",
+            "/foo/bar.jar%3Bpath_param",
+            "/foo/bar?query=string&red=hat"
+    };
+
+    private static BufferedReader mReader;
+    private static DataOutputStream mWriter;
+    private static TinyHttpdImpl mServer;
+
+    static {
+        try {
+            ServerSocket sSocket = new ServerSocket(44322);
+            sSocket.setReuseAddress(true);
+            File dir = new File(System.getProperty("test.server.dir"));
+            Socket extSock = new Socket("localhost", 44322);
+            extSock.setReuseAddress(true);
+            mServer = new TinyHttpdImpl(extSock, dir);
+
+            Socket socket = sSocket.accept();
+            socket.setReuseAddress(true);
+            mReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+            mWriter = new DataOutputStream(socket.getOutputStream());
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    @Test
+    public void urlToFilePathTest() throws Exception {
+        for (String url : FilePathTestUrls) {
+            String newUrl = TinyHttpdImpl.urlToFilePath(url);
+
+            Assert.assertFalse("File path should not contain query string: " + newUrl, newUrl.contains("?"));
+            Assert.assertTrue("File path should be relative: " + newUrl, newUrl.startsWith("./"));
+            Assert.assertFalse("File path should not contain \"/XslowX\":" + newUrl,
+                    newUrl.toLowerCase().contains("/XslowX".toLowerCase()));
+
+            if (url.endsWith("/")) {
+                Assert.assertTrue(newUrl.endsWith("/index.html"));
+            }
+        }
+    }
+
+    @Test
+    public void urlToFilePathUrlDecodeTest() throws Exception {
+        // This test may fail with strange original URLs, eg those containing the substring "%253B",
+        // which can be decoded into "%3B", then decoded again into ';'.
+
+        for (String url : FilePathTestUrls) {
+            String newUrl = TinyHttpdImpl.urlToFilePath(url);
+            Assert.assertEquals(newUrl, URLDecoder.decode(newUrl, "UTF-8"));
+        }
+    }
+
+    @Test
+    public void stripHttpPathParamTest() {
+        String[] testBaseUrls = {
+                "http://foo.com/bar",
+                "localhost:8080",
+                "https://bar.co.uk/site;para/baz?u=param1&v=param2"
+        };
+
+        String[] testJarNames = {
+                "jar",
+                "foo.jar",
+                "bar;baz.jar",
+                "nom.jar;",
+                "rhat.jar.pack.gz;tag"
+        };
+
+        for (String url : testBaseUrls) {
+            for (String jar : testJarNames) {
+                String newUrl = TinyHttpdImpl.stripHttpPathParams(url), newJar = TinyHttpdImpl.stripHttpPathParams(jar), path = newUrl + "/" + newJar;
+                Assert.assertTrue("Base URL should not have been modified: " + url + " => " + newUrl, newUrl.equals(url));
+                Assert.assertTrue("JAR name should not be altered other than removing path param: " + jar + " => " + newJar, jar.startsWith(newJar));
+                Assert.assertTrue("New path should be a substring of old path: " + path + " => " + url + "/" + jar, (url + "/" + jar).startsWith(path));
+            }
+        }
+    }
+
+    private void headTestHelper(String request, String contentType) {
+        Matcher matcher = CONTENT_LENGTH.matcher(request);
+
+        Assert.assertTrue("Status should have been " + HTTP_OK, request.contains(HTTP_OK));
+        Assert.assertTrue("Content type should have been " + contentType, request.contains(contentType));
+        Assert.assertTrue("Should have had a content length", matcher.find());
+    }
+
+    @Test
+    public void JnlpHeadTest() throws IOException, InterruptedException {
+        String head = getTinyHttpdImplResponse("HEAD", "/simpletest1.jnlp");
+        headTestHelper(head, CONTENT_JNLP);
+    }
+
+    @Test
+    public void HtmlHeadTest() throws Exception {
+        String head = getTinyHttpdImplResponse("HEAD", "/StripHttpPathParams.html");
+        headTestHelper(head, CONTENT_HTML);
+    }
+
+    @Test
+    public void JarHeadTest() throws Exception {
+        String head = getTinyHttpdImplResponse("HEAD", "/StripHttpPathParams.jar");
+        headTestHelper(head, CONTENT_JAR);
+    }
+
+    @Test
+    public void PngHeadTest() throws Exception {
+        // TinyHttpdImpl doesn't recognize PNG type - default content type should be HTML
+        String head = getTinyHttpdImplResponse("HEAD", "/netxPlugin.png");
+        headTestHelper(head, CONTENT_HTML);
+    }
+
+    @Test
+    public void SlowSendTest() throws Exception {
+        // This test is VERY SLOW due to the extremely slow sending speed TinyHttpdImpl uses when XslowX is specified.
+        // Running time will be over two minutes.
+        long fastStartTime = System.nanoTime();
+        String req1 = getTinyHttpdImplResponse("GET", "/simpletest1.jnlp");
+        long fastElapsed = System.nanoTime() - fastStartTime;
+
+        long slowStartTime = System.nanoTime();
+        String req2 = getTinyHttpdImplResponse("GET", "/XslowXsimpletest1.jnlp");
+        long slowElapsed = System.nanoTime() - slowStartTime;
+
+        Assert.assertTrue("Slow request should have returned the same data as normal request", req1.equals(req2));
+
+        // This isn't a very good test since as it is, getTinyHttpdImpl is slowing down its receive rate to
+        // deal with the reduced sending rate. It is hardcoded to be slower.
+        Assert.assertTrue("Slow request should have taken longer than normal request", slowElapsed > fastElapsed);
+    }
+
+    @Test
+    public void GetTest() throws Exception {
+        String jnlpHead = getTinyHttpdImplResponse("HEAD", "/simpletest1.jnlp");
+        String jnlpGet = getTinyHttpdImplResponse("GET", "/simpletest1.jnlp");
+
+        Assert.assertTrue("GET status should be " + HTTP_OK, jnlpGet.contains(HTTP_OK));
+        Assert.assertTrue("GET content type should have been " + CONTENT_JNLP, jnlpGet.contains(CONTENT_JNLP));
+        Assert.assertTrue("GET response should contain HEAD response", jnlpGet.contains(jnlpHead));
+        Assert.assertTrue("GET response should have been longer than HEAD response", jnlpGet.length() > jnlpHead.length());
+    }
+
+    @Test
+    public void Error404DoesNotCauseShutdown() throws Exception {
+        // Pre-refactoring, 404 errors were sent after catching an IOException when trying to open the requested
+        // resource. However this was caught by a try/catch clause around the entire while loop, so a 404 would
+        // shut down the server.
+        String firstRequest = getTinyHttpdImplResponse("HEAD", "/no_such_file");
+        String secondRequest = getTinyHttpdImplResponse("HEAD", "/simpletest1.jnlp");
+
+        Assert.assertTrue("First request should have been " + HTTP_404, firstRequest.trim().equals(HTTP_404));
+        Assert.assertTrue("Second request should have been " + HTTP_OK, secondRequest.contains(HTTP_OK));
+    }
+
+    @Test
+    public void BadMethodTest() throws Exception {
+        String head = getTinyHttpdImplResponse("BADMETHOD", "/simpletest1.jnlp");
+
+        Assert.assertTrue("Status should have been " + HTTP_400, head.trim().equals(HTTP_400));
+    }
+
+    @Test
+    public void NotSupportingHeadRequest() throws Exception {
+        boolean headRequestSupport = mServer.isSupportingHeadRequest();
+        mServer.setSupportingHeadRequest(false);
+        String head = getTinyHttpdImplResponse("HEAD", "/simpletest1.jnlp");
+
+        Assert.assertTrue("Status should have been " + HTTP_501, head.trim().equals(HTTP_501));
+
+        mServer.setSupportingHeadRequest(headRequestSupport);
+    }
+
+    private String getTinyHttpdImplResponse(String requestType, String filePath) throws IOException, InterruptedException {
+        if (!filePath.startsWith("/")) {
+            filePath = "/" + filePath;
+        }
+        mWriter.writeBytes(requestType + " " + filePath + " HTTP/1.1\r\n");
+        Thread.sleep(250); // Wait a while for server to be able to respond to request
+
+        StringBuilder builder = new StringBuilder();
+        while (mReader.ready()) {
+            // TODO: come up with a better way to deal with slow sending - this works but is hackish
+            if (filePath.startsWith("/XslowX")) {
+                Thread.sleep(2100); // Wait for next chunk to have been sent, otherwise it'll appear as if the response
+                // has finished being sent prematurely
+            }
+            builder.append(mReader.readLine());
+            builder.append("\n");
+        }
+
+        return builder.toString();
+    }
+
+}
-- 
cgit v1.2.3