Skip to content

Commit 684c029

Browse files
committed
Improve HTTP server file upload tests with very large file upload test.
1 parent e8bba33 commit 684c029

File tree

1 file changed

+146
-50
lines changed

1 file changed

+146
-50
lines changed

vertx-core/src/test/java/io/vertx/tests/http/fileupload/HttpServerFileUploadTest.java

Lines changed: 146 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@
1111
package io.vertx.tests.http.fileupload;
1212

1313
import io.netty.handler.codec.DecoderException;
14-
import io.vertx.core.Context;
15-
import io.vertx.core.Future;
16-
import io.vertx.core.MultiMap;
17-
import io.vertx.core.Vertx;
14+
import io.vertx.core.*;
1815
import io.vertx.core.buffer.Buffer;
1916
import io.vertx.core.file.AsyncFile;
20-
import io.vertx.core.http.HttpConnection;
21-
import io.vertx.core.http.HttpHeaders;
22-
import io.vertx.core.http.HttpMethod;
23-
import io.vertx.core.http.RequestOptions;
17+
import io.vertx.core.http.*;
18+
import io.vertx.core.internal.ContextInternal;
19+
import io.vertx.core.streams.WriteStream;
2420
import io.vertx.test.core.TestUtils;
2521
import io.vertx.test.http.HttpTestBase;
2622
import org.junit.Rule;
@@ -113,6 +109,51 @@ public void testFormUploadLargeFileStreamToDisk() {
113109
testFormUploadFile(TestUtils.randomAlphaString(4 * 1024 * 1024), false, true, false, false);
114110
}
115111

112+
@Test
113+
public void testFormUploadVeryLargeFileStreamToDisk() {
114+
long one_kb = 1024L;
115+
long one_mb = one_kb * 1024L;
116+
long one_gb = one_mb * 1024L;
117+
// long length = one_gb * 10L;
118+
long length = one_mb + 128; // 128MB
119+
Content content = new Content() {
120+
@Override
121+
public long length() {
122+
return length;
123+
}
124+
Buffer chunk_1k = TestUtils.randomBuffer(1024);
125+
long chunkLength = chunk_1k.length();
126+
private void pump(long remaining, WriteStream<Buffer> out, Promise<Void> done) {
127+
while (!out.writeQueueFull()) {
128+
if (remaining > chunkLength) {
129+
out.write(chunk_1k);
130+
remaining -= chunkLength;
131+
} else {
132+
Buffer last = chunk_1k.slice(0, (int)remaining);
133+
out.write(last).onComplete(done);
134+
return;
135+
}
136+
}
137+
long propagated = remaining;
138+
// System.out.println("Full - remaining is " + propagated + "M");
139+
out.drainHandler(v -> {
140+
pump(propagated, out, done);
141+
});
142+
}
143+
@Override
144+
public Future<Void> write(WriteStream<Buffer> out) {
145+
Promise<Void> done = ((ContextInternal)vertx.getOrCreateContext()).promise();
146+
pump(length, out, done);
147+
return done.future();
148+
}
149+
@Override
150+
public boolean verify(Buffer expected) {
151+
return true;
152+
}
153+
};
154+
testFormUploadFile("tmp-0.txt", "tmp-0.txt", content, false, true, false, false);
155+
}
156+
116157
@Test
117158
public void testFormUploadWithExtFilename() {
118159
testFormUploadFile(null, "%c2%a3%20and%20%e2%82%ac%20rates", "the-content", false, true, false, false);
@@ -182,13 +223,58 @@ private void testFormUploadFile(String contentStr, boolean includeLength, boolea
182223
testFormUploadFile("tmp-0.txt", "tmp-0.txt", contentStr, includeLength, streamToDisk, abortClient, cancelStream);
183224
}
184225

226+
interface Content {
227+
228+
long length();
229+
230+
Future<Void> write(WriteStream<Buffer> out);
231+
232+
boolean verify(Buffer expected);
233+
}
234+
185235
private void testFormUploadFile(String filename,
186236
String extFilename,
187237
String contentStr,
188238
boolean includeLength,
189239
boolean streamToDisk,
190240
boolean abortClient,
191241
boolean cancelStream) {
242+
testFormUploadFile(filename, extFilename, Buffer.buffer(contentStr, "UTF-8"), includeLength,
243+
streamToDisk, abortClient, cancelStream);
244+
}
245+
246+
private void testFormUploadFile(String filename,
247+
String extFilename,
248+
Buffer contentBytes,
249+
boolean includeLength,
250+
boolean streamToDisk,
251+
boolean abortClient,
252+
boolean cancelStream) {
253+
Content content = new Content() {
254+
@Override
255+
public long length() {
256+
return contentBytes.length();
257+
}
258+
@Override
259+
public Future<Void> write(WriteStream<Buffer> out) {
260+
return out.write(contentBytes);
261+
}
262+
@Override
263+
public boolean verify(Buffer expected) {
264+
return contentBytes.equals(expected);
265+
}
266+
};
267+
testFormUploadFile(filename, extFilename, content, includeLength, streamToDisk, abortClient, cancelStream);
268+
269+
}
270+
271+
private void testFormUploadFile(String filename,
272+
String extFilename,
273+
Content content,
274+
boolean includeLength,
275+
boolean streamToDisk,
276+
boolean abortClient,
277+
boolean cancelStream) {
192278
String expectedFilename;
193279
try {
194280
if (extFilename != null) {
@@ -203,8 +289,6 @@ private void testFormUploadFile(String filename,
203289

204290
waitFor(2);
205291

206-
Buffer content = Buffer.buffer(contentStr);
207-
208292
AtomicInteger attributeCount = new AtomicInteger();
209293

210294
AtomicReference<HttpConnection> clientConn = new AtomicReference<>();
@@ -216,6 +300,7 @@ private void testFormUploadFile(String filename,
216300
};
217301

218302
server.requestHandler(req -> {
303+
219304
Context requestContext = vertx.getOrCreateContext();
220305
if (req.method() == HttpMethod.POST) {
221306
assertEquals(req.path(), "/form");
@@ -249,7 +334,7 @@ private void testFormUploadFile(String filename,
249334
});
250335
upload.endHandler(v -> {
251336
assertFalse(abortClient);
252-
assertEquals(content, tot);
337+
assertTrue(content.verify(tot));
253338
assertTrue(upload.isSizeAvailable());
254339
assertEquals(content.length(), upload.size());
255340
assertNull(upload.file());
@@ -259,9 +344,15 @@ private void testFormUploadFile(String filename,
259344
uploadedFileName = new File(testDir, UUID.randomUUID().toString()).getPath();
260345
upload.streamToFileSystem(uploadedFileName).onComplete(ar -> {
261346
if (ar.succeeded()) {
262-
Buffer uploaded = vertx.fileSystem().readFileBlocking(uploadedFileName);
263-
assertEquals(content.length(), uploaded.length());
264-
assertEquals(content, uploaded);
347+
File f = new File(uploadedFileName);
348+
if (f.length() < 10 * 1024 * 1024) {
349+
Buffer uploaded = vertx.fileSystem().readFileBlocking(uploadedFileName);
350+
assertEquals(content.length(), uploaded.length());
351+
assertTrue(content.verify(uploaded));
352+
} else {
353+
// We check the size only
354+
assertEquals(f.length(), content.length());
355+
}
265356
AsyncFile file = upload.file();
266357
assertNotNull(file);
267358
try {
@@ -278,7 +369,7 @@ private void testFormUploadFile(String filename,
278369
if (cancelStream) {
279370
BooleanSupplier test = () -> {
280371
File f = new File(uploadedFileName);
281-
if (f.length() == contentStr.length() / 2) {
372+
if (f.length() == content.length() / 2) {
282373
assertTrue(upload.cancelStreamToFileSystem());
283374
long now = System.currentTimeMillis();
284375
vertx.setPeriodic(10, id -> {
@@ -314,42 +405,47 @@ private void testFormUploadFile(String filename,
314405
}
315406
});
316407

317-
server.listen(testAddress).onComplete(onSuccess(s -> {
318-
client.request(new RequestOptions(requestOptions)
319-
.setMethod(HttpMethod.POST)
320-
.setURI("/form"))
321-
.onComplete(onSuccess(req -> {
322-
String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO";
323-
String epi = "\r\n" +
324-
"--" + boundary + "--\r\n";
325-
String pro = "--" + boundary + "\r\n" +
326-
"Content-Disposition: form-data; name=\"file\"" + (filename == null ? "" : "; filename=\"" + filename + "\"" ) + (extFilename == null ? "" : "; filename*=\"UTF-8''" + extFilename) + "\"\r\n" +
327-
"Content-Type: image/gif\r\n" +
328-
(includeLength ? "Content-Length: " + contentStr.length() + "\r\n" : "") +
329-
"\r\n";
330-
req.headers().set("content-length", "" + (pro + contentStr + epi).length());
331-
req.headers().set("content-type", "multipart/form-data; boundary=" + boundary);
332-
Future<Void> fut = req.end(pro + contentStr + epi);
333-
if (abortClient) {
334-
fut.onComplete(onSuccess(v -> {
335-
clientConn.set(req.connection());
336-
checkClose.run();
337-
}));
338-
}
339-
if (abortClient) {
340-
req.response().onComplete(ar -> complete());
341-
} else {
342-
req.response().onComplete(onSuccess(resp -> {
343-
assertEquals(200, resp.statusCode());
344-
resp.bodyHandler(body -> {
345-
assertEquals(0, body.length());
346-
});
347-
assertEquals(0, attributeCount.get());
348-
complete();
349-
}));
350-
}
408+
server.listen(testAddress).await();
409+
410+
HttpClientRequest request = client.request(new RequestOptions(requestOptions)
411+
.setMethod(HttpMethod.POST)
412+
.setURI("/form")).await();
413+
String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO";
414+
String epi = "\r\n" +
415+
"--" + boundary + "--\r\n";
416+
String pro = "--" + boundary + "\r\n" +
417+
"Content-Disposition: form-data; name=\"file\"" + (filename == null ? "" : "; filename=\"" + filename + "\"" ) + (extFilename == null ? "" : "; filename*=\"UTF-8''" + extFilename) + "\"\r\n" +
418+
"Content-Type: image/gif\r\n" +
419+
(includeLength ? "Content-Length: " + Long.toUnsignedString(content.length()) + "\r\n" : "") +
420+
"\r\n";
421+
422+
request.headers().set(HttpHeaders.CONTENT_LENGTH, Long.toUnsignedString((((long) pro.length() + content.length() + (long) epi.length()))));
423+
// request.setChunked(true);
424+
request.headers().set(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
425+
426+
vertx.runOnContext(v1 -> {
427+
request.write(pro);
428+
Future<Void> fut = content.write(request).compose(v -> request.end(epi));
429+
if (abortClient) {
430+
fut.onComplete(onSuccess(v -> {
431+
clientConn.set(request.connection());
432+
checkClose.run();
351433
}));
352-
}));
434+
}
435+
if (abortClient) {
436+
request.response().onComplete(ar -> complete());
437+
} else {
438+
request.response().onComplete(onSuccess(resp -> {
439+
assertEquals(200, resp.statusCode());
440+
resp.bodyHandler(body -> {
441+
assertEquals(0, body.length());
442+
});
443+
assertEquals(0, attributeCount.get());
444+
complete();
445+
}));
446+
}
447+
});
448+
353449
await();
354450
}
355451

0 commit comments

Comments
 (0)