Skip to content

Commit

Permalink
Add backports-3.8.5 coverage for QuarkusCliPomIntegrity and GzipMaxInput
Browse files Browse the repository at this point in the history
  • Loading branch information
jcarranzan committed Jun 12, 2024
1 parent 74de3e6 commit d662b79
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.quarkus.ts.http.advanced;

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

import org.jboss.resteasy.annotations.GZIP;

@Path("/gzip")
public class GzipResource {

@POST
public String gzip(@GZIP byte[] message) {
return "OK";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package io.quarkus.ts.http.advanced;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Tag;
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.response.Response;

@QuarkusScenario
public class GzipMaxInputIT {
final byte[] zero_bytes = new byte[0];
final String invalid_value = "";
final byte[] SMALL_PAYLOAD = new byte[512];
final byte[] LIMIT_PAYLOAD = new byte[100 * 1024 * 1024];
final byte[] OVER_LIMIT_PAYLOAD = new byte[200 * 1024 * 1024];

/**
*
* Tests are checking server response on different size of sent payload
* Limit is configured using quarkus.resteasy.gzip.max-input property
* (According "All configurations options" guide the property 'quarkus.resteasy.gzip.max-input' refers to
* Maximum deflated file bytes size)
* If the limit is exceeded, Resteasy will return a response with status 413("Request Entity Too Large")
*/
@QuarkusApplication(classes = { GzipResource.class }, properties = "gzip.properties")
static RestService app = new RestService();

@Test
void sendInvalidContent() {
Response response = sendStringDataToGzipEndpoint(invalid_value);
assertEquals(HttpStatus.SC_BAD_REQUEST, response.statusCode(),
"Invalid data as this void string should result in 400 BAD_REQUEST response");
}

@Test
void sendZeroBytesPayload() throws IOException {
byte[] compressedData = generateCompressedData(zero_bytes);
Response response = sendDataToGzipEndpoint(compressedData);
assertEquals(HttpStatus.SC_OK, response.statusCode(),
"The response should be 200 OK because the compression returns 2 bytes");
}

@Test
void sendPayloadBelowMaxInputLimit() throws IOException {
byte[] compressedData = generateCompressedData(SMALL_PAYLOAD);
Response response = sendDataToGzipEndpoint(compressedData);
assertEquals(HttpStatus.SC_OK, response.statusCode(),
"The response should be 200 OK because sending just 512 bytes");
}

@Tag("https://github.com/quarkusio/quarkus/issues/39636")
@Test
void sendMaximumAllowedPayload() throws IOException {
byte[] compressedData = generateCompressedData(LIMIT_PAYLOAD);
Response response = sendDataToGzipEndpoint(compressedData);
assertEquals(HttpStatus.SC_OK, response.statusCode(),
"The response should be 200 OK because sending just the limit payload configured using " +
"quarkus.resteasy.gzip.max-input=100M. This fails if the suffix format parsing is not " +
"working and RESTEasy falls back to its default which is 10M");
}

@Test
void sendMoreThanMaximumAllowedPayload() throws IOException {
byte[] compressedData = generateCompressedData(OVER_LIMIT_PAYLOAD);
Response response = sendDataToGzipEndpoint(compressedData);
assertEquals(HttpStatus.SC_REQUEST_TOO_LONG, response.statusCode(),
"The response should be 413 REQUEST_TOO_LONG when sending larger payload than the limit");
}

private Response sendDataToGzipEndpoint(byte[] data) {
return app.given()
.header(HttpHeaders.CONTENT_ENCODING, "gzip")
.body(data)
.when()
.post("/gzip")
.then()
.extract().response();
}

private Response sendStringDataToGzipEndpoint(String data) {
return app.given()
.header("Content-Encoding", "gzip")
.body(data)
.when()
.post("/gzip")
.then()
.extract().response();
}

public byte[] generateCompressedData(byte[] data) throws IOException {
byte[] result;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {
gzipOut.write(data);
gzipOut.close();
result = baos.toByteArray();
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.quarkus.ts.quarkus.cli;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Properties;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.QuarkusCliClient;
import io.quarkus.test.bootstrap.QuarkusCliRestService;
import io.quarkus.test.scenarios.QuarkusScenario;

@QuarkusScenario
public class QuarkusCliPomIntegrityIT {
/*
* This scenario is related to the backport https://github.com/quarkusio/quarkus/issues/39088
*
*/
private static final String NEW_EXTENSION = "quarkus-kafka-client";
private static final String COMMENT = "<!-- Disable native build on this module -->";

private static final String APP_NAME = "my-quarkus-app";

private static Path POM_PATH;

@Inject
static QuarkusCliClient cliClient;

@BeforeAll
public static void loadPom() {
try (InputStream input = QuarkusCliPomIntegrityIT.class.getClassLoader().getResourceAsStream("test.properties")) {
Properties properties = new Properties();
if (input == null) {
throw new IOException("Configuration file not found");
}
properties.load(input);
String rawPath = properties.getProperty("app.pom.path");
if (rawPath == null) {
throw new RuntimeException("Path configuration is missing");
}
String pathStr = rawPath
.replace("{className}", QuarkusCliPomIntegrityIT.class.getSimpleName())
.replace("{appName}", APP_NAME);
POM_PATH = Paths.get(pathStr);
} catch (IOException ex) {
throw new RuntimeException("Failed to load configuration", ex);
}

}

@Test
public void shouldKeepCommentInPomAfterAddAndRemoveExtension() throws IOException {
QuarkusCliRestService app = cliClient.createApplication(APP_NAME);
File pomFile = POM_PATH.toFile();

try (var fileWriter = new FileWriter(pomFile, true)) {
fileWriter.write(System.lineSeparator());
fileWriter.write(COMMENT);
}

// Add extension
app.installExtension(NEW_EXTENSION);
assertPomContainsComment(pomFile, "The comment after add extension still should be there");

// Remove extension
app.removeExtension(NEW_EXTENSION);
assertPomContainsComment(pomFile, "The comment after remove extension still should be there");
}

private static void assertPomContainsComment(File pom, String errMessage) throws IOException {
List<String> pomContent = Files.readAllLines(pom.toPath());
// the comment is added to the (new) last line,
// however Quarkus formats the POM file when extension is added / removed
// and removes the new line separator, so we need to look for the comment in the last line;
var lastLine = pomContent.get(pomContent.size() - 1);
Assertions.assertTrue(lastLine.contains(COMMENT), errMessage);
}
}
2 changes: 2 additions & 0 deletions quarkus-cli/src/test/resources/test.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ ts.global.generated-service.enabled=false
#this app is not expected to start, so let's fail right after
ts.pomApp.startup.timeout=PT2s
ts.pomApp.startup.check-poll-interval=PT1s
app.pom.path=target/{className}/{appName}/pom.xml

0 comments on commit d662b79

Please sign in to comment.