-
Notifications
You must be signed in to change notification settings - Fork 739
Description
With RestAssured multipart support, we can go things like
given(spec)
.multipart("data1", new File("..'"))
.multipart("data2", new byte[] { 1 })
.multipart("data3", new FakeInputStream())The problem with this though is the RestAssuredRequestConverter, when it tries to convert the content. Only a few types are supported
private byte[] convertContent(Object content) {
if (content instanceof String) {
return ((String) content).getBytes();
} else if (content instanceof byte[]) {
return (byte[]) content;
} else if (content == null) {
return new byte[0];
} else {
throw new IllegalStateException(
"Unsupported request content: " + content.getClass().getName());
}
}You would think that the byte[] should work, but somewhere in the process, before the spec is build, it converts the byte[] into a ByteArrayInpuStream, so it fails like with all the other types.
IllegalStateException: Unsupported request content: java.io.ByteArrayInputStreamThe other types (InputStream and File) don't get converted, so you get the same exception as above, but with the respective type in the message.
As a solution, I was thinking maybe just handle the easiest case, checking for the ByteArrayInputStream, in which you can easily convert the to a byte[] without RestAssured being affected. The problems I see with this is that 1. You don't cover all other types, 2. It is dependent on the RestAssured implementation not changing. For the second point maybe just write a test to fail, if it does ever change, cross that bridge if it ever gets to that point. Not the best idea, but somehing I could live with.
Or maybe there is some other way, through some RestAssured APIs to change this behavior, without needing to touch RestDocs. Maybe some preprocess filtering. I don't know, I am no RestAssured expert.
Maybe @johanhaleby has some ideas on how this problem can best be solved.
Below is a complete runnable test that reproduces the errors.
import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.restdocs.JUnitRestDocumentation;
import com.jayway.restassured.builder.MultiPartSpecBuilder;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.specification.MultiPartSpecification;
import com.jayway.restassured.specification.RequestSpecification;
import static com.jayway.restassured.RestAssured.*;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.*;
/**
* Dependencies for test
*
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.22.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.22.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-restassured</artifactId>
<version>1.1.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
*
*/
public class RestassuredMultipartTest {
private static final String BASE_URI = "http://localhost:8080/api/";
private static final String FILE_NAME = "test.txt";
private static final String TEST_DATA = "RandomData";
@Rule
public JUnitRestDocumentation documentation
= new JUnitRestDocumentation("target/snippets");
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
private HttpServer server;
private RequestSpecification spec;
private File dataFile;
@Before
public void setUp() throws Exception {
this.server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI),
new ResourceConfig(TestResource.class)
.register(MultiPartFeature.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true)));
this.server.start();
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(this.documentation))
.setBaseUri(BASE_URI).build();
this.dataFile = this.tempFolder.newFile(FILE_NAME);
Files.write(this.dataFile.toPath(),
TEST_DATA.getBytes(StandardCharsets.UTF_16),
StandardOpenOption.APPEND);
}
@After
public void tearDown() {
this.server.stop();
}
@Path("test")
public static class TestResource {
@POST
@Produces("text/plain")
@Consumes("multipart/form-data")
public String post(@FormDataParam("data") String data,
@FormDataParam("data") FormDataContentDisposition fdcd) {
return data;
}
}
@Test
public void multiPartPassWithoutDocumentation() throws Exception {
given(this.spec)
.multiPart("data", FILE_NAME, new FileInputStream(this.dataFile))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
@Test
public void multiPartPassWithString() {
given(this.spec)
.multiPart("data", TEST_DATA)
.filter(document("multipart-string"))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
@Test
public void multiPartInputStreamTest() throws Exception {
given(this.spec)
.multiPart("data", FILE_NAME, new FileInputStream(this.dataFile),
"text/plain")
.filter(document("multipart-inputstream"))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
@Test
public void multiPartByteArrayTest() throws Exception {
given(this.spec)
.multiPart("data", FILE_NAME, Files.readAllBytes(this.dataFile.toPath()),
"text/plain")
.filter(document("multipart-byte-array"))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
@Test
public void multiPartFileTest() {
given(this.spec)
.multiPart("data", this.dataFile, "text/plain")
.filter(document("multipart-file"))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
@Test
public void multiPartWithSpecAndByteArrayTest() throws Exception {
final MultiPartSpecification multiPart = new MultiPartSpecBuilder(
Files.readAllBytes(this.dataFile.toPath()))
.controlName("data")
.mimeType("text/plain")
.build();
given(this.spec)
.multiPart(multiPart)
.filter(document("multipart-spec"))
.when()
.post("/test")
.then()
.assertThat()
.statusCode(200);
}
}