Issue #3888 - Adding testcase to demonstrate Huge file Resource issue

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
Joakim Erdfelt 2019-07-18 11:47:37 -05:00
parent 6f9495f5c1
commit aef58168d0
1 changed files with 189 additions and 0 deletions

View File

@ -0,0 +1,189 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.webapp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.PathResource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class HugeResourceTest
{
private static final long KB = 1024;
private static final long MB = 1024 * KB;
private static final long GB = 1024 * MB;
public static Path hugeStaticBase;
public static Path outputDir;
public Server server;
@BeforeAll
public static void prepareStaticFiles() throws IOException
{
hugeStaticBase = MavenTestingUtils.getTargetTestingPath(HugeResourceTest.class.getSimpleName() + "-huge-static-base");
FS.ensureDirExists(hugeStaticBase);
makeStaticFile(hugeStaticBase.resolve("test-1g.dat"), 1 * GB);
makeStaticFile(hugeStaticBase.resolve("test-4g.dat"), 4 * GB);
makeStaticFile(hugeStaticBase.resolve("test-10g.dat"), 10 * GB);
outputDir = MavenTestingUtils.getTargetTestingPath(HugeResourceTest.class.getSimpleName() + "-huge-static-outputdir");
FS.ensureEmpty(outputDir);
}
@AfterAll
public static void cleanupHugeStaticFiles()
{
FS.ensureDeleted(hugeStaticBase);
FS.ensureDeleted(outputDir);
}
private static void makeStaticFile(Path staticFile, long size) throws IOException
{
byte[] buf = new byte[(int)(1 * MB)];
Arrays.fill(buf, (byte)'x');
ByteBuffer src = ByteBuffer.wrap(buf);
if (Files.exists(staticFile) && Files.size(staticFile) == size)
{
// all done, nothing left to do.
return;
}
System.err.printf("Creating %,d byte file: %s ...%n", size, staticFile.getFileName());
try (SeekableByteChannel channel = Files.newByteChannel(staticFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING))
{
long remaining = size;
while (remaining > 0)
{
ByteBuffer slice = src.slice();
int len = buf.length;
if (remaining < Integer.MAX_VALUE)
{
len = Math.min(buf.length, (int)remaining);
slice.limit(len);
}
channel.write(slice);
remaining -= len;
}
}
System.err.println(" Done");
}
@BeforeEach
public void startServer() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setBaseResource(new PathResource(hugeStaticBase));
HandlerList handlers = new HandlerList();
handlers.addHandler(context);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
}
@AfterEach
public void stopServer() throws Exception
{
server.stop();
}
@Test
public void testDownload_1G() throws IOException
{
download(server.getURI().resolve("/test-1g.dat"), 1 * GB);
}
@Test
public void testDownload_4G() throws IOException
{
download(server.getURI().resolve("/test-4g.dat"), 4 * GB);
}
@Test
public void testDownload_10G() throws IOException
{
download(server.getURI().resolve("/test-10g.dat"), 10 * GB);
}
private void download(URI destUri, long expectedSize) throws IOException
{
HttpURLConnection http = (HttpURLConnection)destUri.toURL().openConnection();
assertThat("HTTP Response Code", http.getResponseCode(), is(200));
// if a Content-Length is provided, test it
String contentLength = http.getHeaderField("Content-Length");
if (contentLength != null)
{
long contentLengthLong = Long.parseLong(contentLength);
assertThat("Http Response Header: \"Content-Length: " + contentLength + "\"", contentLengthLong, is(expectedSize));
}
// Download the file
String filename = destUri.getPath();
int idx = filename.lastIndexOf('/');
if (idx >= 0)
{
filename = filename.substring(idx + 1);
}
Path outputFile = outputDir.resolve(filename);
try (OutputStream out = Files.newOutputStream(outputFile);
InputStream in = http.getInputStream())
{
IO.copy(in, out);
}
// Verify the file download size
assertThat("Downloaded Files Size: " + filename, Files.size(outputFile), is(expectedSize));
}
}