Mocking a multipart/form-data HTTP request in a unit test

4,802 views
Skip to first unread message

Thomas Thiebaud

unread,
May 27, 2015, 9:18:30 AM5/27/15
to ve...@googlegroups.com
Hi,

I created a http server using vertx3 to accept multipart files using the code from the doc

router.post("/back/application").handler(routingContext -> {  
   
Set<FileUpload> uploads = routingContext.fileUploads();
   
//...
});

Everything works fine, but now I would like to write the associated unit test.

My question is : is there a simple function (as simple as server's one) to send multipart file from vertx ? It can be usefull both for testing and writting http client...

I found some working code from vertx test, but this is quite inelegant

@Test
public void testUpload(TestContext context) {
   
HttpClient client = vertx.createHttpClient();

   
Async async = context.async();
   
HttpClientRequest request = client.post(12345, "localhost", "/back/application", rep -> {
       
//...
        async
.complete();
   
});

   
String name = "upload";
   
String fileName = "upload.txt";
   
String contentType = "application/octet-stream";

   
vertx.fileSystem().open(getClass().getClassLoader().getResource(fileName).getPath(), new OpenOptions(), res -> {
       
if (res.succeeded()) {
           
AsyncFile file = res.result();

           
String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO";
           
Buffer buffer = Buffer.buffer();
           
String header =
                   
"--" + boundary + "\r\n" +
                           
"Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + fileName + "\"\r\n" +
                           
"Content-Type: " + contentType + "\r\n" +
                           
"Content-Transfer-Encoding: binary\r\n" +
                           
"\r\n";
            buffer
.appendString(header);

           
/*
             * I am sending an empty buffer, but I would like to send the async file
             */

            buffer
.appendBuffer(Buffer.buffer(5000));

           
String footer = "\r\n--" + boundary + "--\r\n";
            buffer
.appendString(footer);
            request
.headers().set("content-length", String.valueOf(buffer.length()));
            request
.headers().set("content-type", "multipart/form-data; boundary=" + boundary);
            request
.write(buffer);
            request
.end();
       
} else {
            context
.fail();
       
}
   
});
}


Message has been deleted
Message has been deleted

Ronald van Raaphorst

unread,
Jul 3, 2017, 5:46:56 AM7/3/17
to vert.x
Hi,

I'm having the same problem I guess using vertx 3.4.2:
Your call client.post(12345, "localhost", "/back/application", rep -> { with the callback seems to have been removed.

AFAIK, in 3.4.2 there's a sendStream, sendBuffer, sendForm, sendJson and a sendJsonObject, that are new  but I can't find a way to simply test a multipart/formdata
with some form fields and a file upload. 
One way or another, the context.fileUploads() method never returns an uploaded file.

The web-client docs mention:

| at the moment multipart files are not supported, it will likely be supported in a later revision of the API.

Does that mean in 3.4.2 the test below won't work at all and file-uploads can't be tested using the web-client?
My test-code is below. Am I missing something? 

TIA
Ronald

Sorry had to delete and upload the message again - the code was truncated

@RunWith(VertxUnitRunner.class)
public class UploadHandlerTest extends AbstractBaseTest {


 
private static final Logger logger = LoggerFactory.getLogger(UploadHandlerTest.class);
 
private static HttpServer server;


 @BeforeClass
 
public static void beforeClass(TestContext context) throws Exception {
 
 
// Start a simple webserver
  server
= vertx.createHttpServer();
 
Router mainRouter;
  mainRouter
= Router.router(vertx);
 
// Directory remains empty, write access is permitted
  mainRouter
.route().handler(BodyHandler.create().setUploadsDirectory("my-uploads"));


 
// Handle the upload
  mainRouter
.route(HttpMethod.POST, "/upload").handler(h -> {
   
HttpServerRequest request = h.request();
   
HttpServerResponse response = h.response().setChunked(true);


   
Set<FileUpload> fileUploads = h.fileUploads();
   context
.assertEquals(1, fileUploads.size());     // <-- Point of failure, fileUploads.size() == 0
 
});
  server
.requestHandler(mainRouter::accept).listen(8080);
 
}

 
 
 @Test
 
public void testUpload(TestContext context) throws Exception {
   
Async async = context.async();
   
WebClient client = WebClient.create(vertx);


   
File srcFile = new File(UploadHandlerTest.class.getResource("testfile-1.pdf").toURI());
   context
.assertTrue(srcFile.exists());


   
Buffer buffer = getBuffer(srcFile);


   client
.request(HttpMethod.POST, 8080, "localhost", "/upload").
     putHeader
("accept", "application/json").
     putHeader
("content-type", "multipart/form-data; boundary=--MyBoundary").
   
     sendBuffer
(buffer, h -> {
     
if (h.failed()) {
       context
.fail(h.cause());
       
return;
     
}


     
HttpResponse<Buffer> response = h.result();
      context
.assertEquals(200, response.statusCode());
      async
.complete();
     
});
 
}
  
 
private Buffer getBuffer(File file) {
   
Buffer buffer = Buffer.buffer();
    buffer
.appendString("--MyBoundary\r\n");
    buffer
.appendString("Content-Disposition: form-data; name=\"myId\" \r\n");
    buffer
.appendString("\r\n");
    buffer
.appendString("1234");
    buffer
.appendString("\r\n");
    buffer
.appendString("--MyBoundary\r\n");
    buffer
.appendString("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n");
    buffer
.appendString("Content-Type: application/pdf\n\r\n");
    buffer
.appendString("Content-Transfer-Encoding: binary\r\n");
    buffer
.appendString("\r\n");
   
try {
     buffer
.appendBytes(Files.readAllBytes(Paths.get(file.toURI())));
     buffer
.appendString("\r\n");
   
} catch (Exception e) {
     e
.printStackTrace();
   
}
    buffer
.appendString("--MyBoundary\r\n");
   
return buffer;
   
}

Tim Fox

unread,
Jul 3, 2017, 5:48:15 AM7/3/17
to vert.x
Yes you can test using the webclient, the same as the old client. It's a little clunky as you have to prepare the multipart body yourself, see the original post in this thread for an example, or take a look at the vert.x testsuite.

Ronald van Raaphorst

unread,
Jul 3, 2017, 5:53:16 AM7/3/17
to vert.x
Ah, I see it now.

There's a difference in and

WebClient client = WebClient.create(vertx);

and

HttpClient client = vertx.createHttpClient();

The latter supports the call:

HttpClientRequest request = client.post(12345, "localhost", "/back/application", rep -> {
       
//...
        async
.complete();
   
});


while the first doesn't. My bad. Thx!
Reply all
Reply to author
Forward
0 new messages