Search code examples
javajerseydropwizard

Dropwizard DropwizardAppRule test multipart file upload


I'm currently trying to write an IT test by calling a resource that takes MultiPartFormData as input.

It work when the application starts "normaly" but doesn't when started with DropwizardAppRule helper.

Here is my code :

@Test
public void importProductAndOfferCsvShopInput() {
    // Given
    var shopId = "id";
    var multipartHeaders = headers;
    multipartHeaders.putSingle("Content-Type", "multipart/form-data");

    var file = new File("src/test/resources/import/products&offers.csv");
    var fileDataBodyPart = new FileDataBodyPart("file", file, MediaType.APPLICATION_OCTET_STREAM_TYPE);
    MultiPart multiPart = new FormDataMultiPart().bodyPart(fileDataBodyPart, MediaType.MULTIPART_FORM_DATA_TYPE);

    // When
    var response = QORUS_APP.client().target(String.format("http://localhost:%d/ui/shop-inputs/csv/%s", 8082, shopId))
                            .queryParam("importContentType", "BOTH")
                            .request()
                            .headers(multipartHeaders)
                            .post(Entity.entity(multiPart, multiPart.getMediaType()));

    // Then
    assertThat(response.getStatusInfo()).isEqualTo(Response.Status.OK);
}

QORUS_APP is intanciated like so :

public abstract class AbstractRestResourceTest {

    @ClassRule
    public static final DropwizardAppRule<Configuration> QORUS_APP = ResourceSuite.QORUS_APP;
    private static final String USER_API_KEY = "authenticatedUserApiKey";

    protected static MultivaluedMap<String, Object> headers;

    public AbstractRestResourceTest() {
        headers = new MultivaluedHashMap<>();
        headers.putSingle("Content-Type", "application/json");
        headers.putSingle("Accept", "*/*");
        headers.putSingle(NgTokenAuthFilter.AUTHORIZATION_HEADER, "Bearer " + USER_API_KEY);
    }
}

I get the following error :

MessageBodyWriter not found for media type=multipart/form-data, type=class org.glassfish.jersey.media.multipart.FormDataMultiPart, genericType=class org.glassfish.jersey.media.multipart.FormDataMultiPart. org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=multipart/form-data, type=class org.glassfish.jersey.media.multipart.FormDataMultiPart, genericType=class org.glassfish.jersey.media.multipart.FormDataMultiPart.

Note that there is the required registering of multipart in Application bootstrap :

    private List<Resource> configureJersey(Configuration config, Environment environment) {
    // adds some required features
    environment.jersey().register(MultiPartFeature.class);

UPDATE:

Thanks @paul-samsotha for taking time to answer.

I did the following:

@Test
public void importProductAndOfferCsvShopInput() {
    // Given
    var shopId = "5b03ebe9c9aa0423b4a73dce";
    var multipartHeaders = headers;
    multipartHeaders.putSingle("Content-Type", "multipart/form-data");

    var file = new File("src/test/resources/import/products&offers.csv");
    var fileDataBodyPart = new FileDataBodyPart("file", file);
    var multiPart = new FormDataMultiPart().bodyPart(fileDataBodyPart);

    // When
    var response = QORUS_APP.client()
                            .target(String.format("http://localhost:%d/ui/shop-inputs/csv/%s", 8082, shopId))
                            .register(MultiPartFeature.class)
                            .queryParam("importContentType", "BOTH")
                            .request()
                            .headers(multipartHeaders)
                            .post(Entity.entity(multiPart, multiPart.getMediaType()));

    // Then
    assertThat(response.getStatusInfo()).isEqualTo(Response.Status.OK);
}

Just like you suggest.


Solution

  • The error is occurring on the client side before it sends out the request. See the docs on Forms, it will show you that you need to register the MultiPartFeature on the client side also. You can register it either with the Client or the WebTarget. Dropwizard suggests you register it with the WebTarget, as shown in the example.

    var response = QORUS_APP.client()
            .target(...)
            .register(MultiPartFeature.class)
            ...