Skip to content

Commit

Permalink
Add RESTEasy Reactive JAX-RS scenario
Browse files Browse the repository at this point in the history
Add `http/jaxrs-reactive`, which is a RESTEasy reactive equivalent of
`http/jaxrs`.
Notable differences and limitations:
- In a multipart POJO, Java type for `image` and `octet-stream` were
  changed from `InputStream` to `File` - `InputStream` is not supported
  by `resteasy-reactive`.
- Test of a functionality provided by the
  `quarkus.resteasy.multipart.input-part.default-charset` property has
  been disabled for now - it is unsupported in `resteasy-reactive`.
  quarkusio/quarkus#19527
- [FIXED] Possible bug in `resteasy-reactive` - endpoints  consuming
  `MULTIPART_FORM_DATA` cause build failure.
  quarkusio/quarkus#19404.
- Tests dealing with `text/plain` request/response have been disabled
  on Windows due to a bug.
  quarkusio/quarkus#19535
  • Loading branch information
jsmrcka committed Aug 20, 2021
1 parent 6090300 commit c2eccd7
Show file tree
Hide file tree
Showing 12 changed files with 309 additions and 0 deletions.
23 changes: 23 additions & 0 deletions http/jaxrs-reactive/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkus.ts.qe</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>jaxrs-reactive</artifactId>
<packaging>jar</packaging>
<name>Quarkus QE TS: HTTP: jaxrs-reactive</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.ts.security.core;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Deprecated
@Path("/hello")
public class GreetingResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.ts.security.core;

import java.io.File;

import javax.ws.rs.core.MediaType;

import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.RestForm;

public class MultipartBody {

@RestForm("text")
@PartType(MediaType.TEXT_PLAIN)
public String text;

@RestForm("image")
@PartType("image/png")
public File image;

@RestForm("data")
@PartType(MediaType.APPLICATION_OCTET_STREAM)
public File data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.quarkus.ts.security.core;

import java.io.IOException;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.reactive.MultipartForm;

@Path("/multipart")
public class MultipartResource {

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.MULTIPART_FORM_DATA)
public MultipartBody postForm(@MultipartForm MultipartBody multipartBody) {
return multipartBody;
}

@POST
@Path("/text")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String postFormReturnText(@MultipartForm MultipartBody multipartBody) {
return multipartBody.text;
}

@POST
@Path("/image")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public byte[] postFormReturnFile(@MultipartForm MultipartBody multipartBody) throws IOException {
return IOUtils.toByteArray(multipartBody.image.toURI());
}

@POST
@Path("/data")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public byte[] postFormReturnData(@MultipartForm MultipartBody multipartBody) throws IOException {
return IOUtils.toByteArray(multipartBody.data.toURI());
}

@POST
@Path("/echo")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String echo(String requestBody) {
return requestBody;
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.ts.security.core;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;

import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.QuarkusApplication;
import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.MultiPartSpecification;

// TODO: There is no resteasy-reactive equivalent so far. See https://github.com/quarkusio/quarkus/issues/19527
@Disabled
@QuarkusScenario
public class AsciiMultipartResourceIT {

public static final String TEXT_WITH_DIACRITICS = "Přikrášlený žloťoučký kůň úpěl ďábelské ódy.";
private static final String EXPECTED_ASCII_TEXT = new String(TEXT_WITH_DIACRITICS.getBytes(StandardCharsets.UTF_8),
StandardCharsets.US_ASCII);

@QuarkusApplication
static RestService app = new RestService().withProperties("us-asscii.properties");

@Test
public void testMultipartText() {
MultiPartSpecification multiPartSpecification = new MultiPartSpecBuilder(TEXT_WITH_DIACRITICS)
.controlName("text")
.header("Content-Type", "text/plain")
.charset(StandardCharsets.UTF_8)
.build();

app.given().multiPart(multiPartSpecification)
.post("/multipart/text")
.then()
.statusCode(200)
.contentType(ContentType.TEXT)
.body(not(equalTo(TEXT_WITH_DIACRITICS)))
.body(equalTo(EXPECTED_ASCII_TEXT));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.ts.security.core;

import static org.hamcrest.CoreMatchers.is;

import org.junit.jupiter.api.Test;

import io.quarkus.test.scenarios.QuarkusScenario;
import io.restassured.RestAssured;

@QuarkusScenario
public class BaseQuarkusBundleIT {

@Test
public void testQuarkusEndpoint() {
RestAssured.given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("hello"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.quarkus.ts.security.core;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Random;

import javax.ws.rs.core.MediaType;

import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;

import io.quarkus.test.scenarios.QuarkusScenario;
import io.restassured.RestAssured;
import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.MultiPartSpecification;

@QuarkusScenario
public class MultipartResourceIT {

private static final String IMAGE_FILE_NAME = "/quarkus.png";
private static final String TEXT_WITH_DIACRITICS = "Přikrášlený žloťoučký kůň úpěl ďábelské ódy.";
private static byte[] randomBytes = new byte[120];
private static File imageFile;
private static byte[] imageBytes;

@BeforeAll
public static void beforeAll() throws IOException {
imageFile = new File(MultipartResourceIT.class.getResource(IMAGE_FILE_NAME).getFile());
imageBytes = IOUtils.toByteArray(MultipartResourceIT.class.getResourceAsStream(IMAGE_FILE_NAME));
new Random().nextBytes(randomBytes);
}

@Test
public void testMultipartIsSendAndReceived() {
whenSendMultipartData("/multipart")
.contentType("multipart/form-data");
}

// TODO: https://github.com/quarkusio/quarkus/issues/19535
@DisabledOnOs(OS.WINDOWS)
@Test
public void testTextVersionOfMultipart() {
whenSendMultipartData("/multipart/echo")
.contentType(ContentType.TEXT)
.body(
containsString("Content-Disposition: form-data; name=\"text\""),
containsString("Content-Disposition: form-data; name=\"data\"; filename=\"random.dat\""),
containsString("Content-Disposition: form-data; name=\"image\"; filename=\"quarkus.png\""),
containsString(TEXT_WITH_DIACRITICS));
}

// TODO: https://github.com/quarkusio/quarkus/issues/19535
@DisabledOnOs(OS.WINDOWS)
@Test
public void testTextPartFromMultipart() {
whenSendMultipartData("/multipart/text")
.contentType(ContentType.TEXT)
.body(equalTo(TEXT_WITH_DIACRITICS));
}

@Test
public void testImagePartFromMultipart() {
byte[] receivedBytes = whenSendMultipartData("/multipart/image")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.extract().asByteArray();
assertThat(receivedBytes, equalTo(imageBytes));
}

@Test
public void testDataPartFromMultipart() {
byte[] receivedBytes = whenSendMultipartData("/multipart/data")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.extract().asByteArray();
assertThat(receivedBytes, equalTo(randomBytes));
}

private ValidatableResponse whenSendMultipartData(String path) {
MultiPartSpecification textSpec = new MultiPartSpecBuilder(TEXT_WITH_DIACRITICS)
.controlName("text")
.mimeType("text/plain")
.charset(StandardCharsets.UTF_8)
.build();
MultiPartSpecification dataSpec = new MultiPartSpecBuilder(randomBytes)
.controlName("data")
.fileName("random.dat")
.header("Content-Type", "application/octet-stream")
.build();
MultiPartSpecification imageSpec = new MultiPartSpecBuilder(imageFile)
.controlName("image")
.fileName("quarkus.png")
.mimeType("image/png")
.build();

return RestAssured.given()
.contentType("multipart/form-data")
.multiPart(textSpec)
.multiPart(imageSpec)
.multiPart(dataSpec)
.post(path)
.then()
.statusCode(200);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.ts.security.core;

import io.quarkus.test.scenarios.OpenShiftScenario;

@OpenShiftScenario
public class OpenShiftMultipartResourceIT extends MultipartResourceIT {
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions http/jaxrs-reactive/src/test/resources/us-asscii.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# TODO: There is no resteasy-reactive equivalent so far. See https://github.com/quarkusio/quarkus/issues/19527
#quarkus.resteasy.multipart.input-part.default-charset=us-ascii
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@
<module>http/http-advanced</module>
<module>http/http-static</module>
<module>http/jaxrs</module>
<module>http/jaxrs-reactive</module>
<module>http/reactive-routes</module>
<module>http/rest-client</module>
<module>http/servlet-undertow</module>
Expand Down

0 comments on commit c2eccd7

Please sign in to comment.