mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
remote address bug
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package io.quarkus.amazon.lambda.http;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
@@ -37,7 +38,14 @@ public class LambdaHttpHandler implements RequestHandler<AwsProxyRequest, AwsPro
|
||||
}
|
||||
|
||||
public AwsProxyResponse handleRequest(AwsProxyRequest request, Context context) {
|
||||
VirtualClientConnection connection = VirtualClientConnection.connect(VertxHttpRecorder.VIRTUAL_HTTP);
|
||||
InetSocketAddress clientAddress = null;
|
||||
if (request.getRequestContext() != null && request.getRequestContext().getIdentity() != null) {
|
||||
if (request.getRequestContext().getIdentity().getSourceIp() != null) {
|
||||
clientAddress = new InetSocketAddress(request.getRequestContext().getIdentity().getSourceIp(), 443);
|
||||
}
|
||||
}
|
||||
|
||||
VirtualClientConnection connection = VirtualClientConnection.connect(VertxHttpRecorder.VIRTUAL_HTTP, clientAddress);
|
||||
try {
|
||||
return nettyDispatch(connection, request);
|
||||
} catch (Exception e) {
|
||||
@@ -48,9 +56,7 @@ public class LambdaHttpHandler implements RequestHandler<AwsProxyRequest, AwsPro
|
||||
|
||||
}
|
||||
|
||||
private AwsProxyResponse nettyDispatch(VirtualClientConnection connection,
|
||||
AwsProxyRequest request)
|
||||
throws Exception {
|
||||
private AwsProxyResponse nettyDispatch(VirtualClientConnection connection, AwsProxyRequest request) throws Exception {
|
||||
String path = request.getPath();
|
||||
if (request.getMultiValueQueryStringParameters() != null && !request.getMultiValueQueryStringParameters().isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder(path);
|
||||
|
||||
@@ -88,7 +88,7 @@ public class VirtualChannel extends AbstractChannel {
|
||||
|
||||
protected volatile State state;
|
||||
protected volatile VirtualAddress localAddress;
|
||||
protected volatile VirtualAddress remoteAddress;
|
||||
protected volatile SocketAddress remoteAddress;
|
||||
protected volatile ChannelPromise connectPromise;
|
||||
protected volatile boolean readInProgress;
|
||||
protected volatile boolean writeInProgress;
|
||||
@@ -123,8 +123,8 @@ public class VirtualChannel extends AbstractChannel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualAddress remoteAddress() {
|
||||
return (VirtualAddress) super.remoteAddress();
|
||||
public SocketAddress remoteAddress() {
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.quarkus.netty.runtime.virtual;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@@ -14,17 +15,17 @@ import io.netty.util.internal.PlatformDependent;
|
||||
*
|
||||
*/
|
||||
public class VirtualClientConnection {
|
||||
protected VirtualAddress address;
|
||||
protected SocketAddress clientAddress;
|
||||
protected BlockingQueue<Object> queue = new LinkedBlockingQueue<>();
|
||||
protected boolean connected = true;
|
||||
protected VirtualChannel peer;
|
||||
|
||||
VirtualClientConnection(VirtualAddress address) {
|
||||
this.address = address;
|
||||
VirtualClientConnection(SocketAddress clientAddress) {
|
||||
this.clientAddress = clientAddress;
|
||||
}
|
||||
|
||||
public VirtualAddress clientAddress() {
|
||||
return address;
|
||||
public SocketAddress clientAddress() {
|
||||
return clientAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +105,21 @@ public class VirtualClientConnection {
|
||||
* @return
|
||||
*/
|
||||
public static VirtualClientConnection connect(final VirtualAddress remoteAddress) {
|
||||
return connect(remoteAddress, remoteAddress);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish a virtual intra-JVM connection
|
||||
*
|
||||
* @param remoteAddress
|
||||
* @param clientAddress
|
||||
* @return
|
||||
*/
|
||||
public static VirtualClientConnection connect(VirtualAddress remoteAddress, SocketAddress clientAddress) {
|
||||
if (clientAddress == null)
|
||||
clientAddress = remoteAddress;
|
||||
|
||||
Channel boundChannel = VirtualChannelRegistry.get(remoteAddress);
|
||||
if (boundChannel == null) {
|
||||
throw new RuntimeException("No virtual channel available");
|
||||
@@ -113,9 +129,8 @@ public class VirtualClientConnection {
|
||||
}
|
||||
|
||||
VirtualServerChannel serverChannel = (VirtualServerChannel) boundChannel;
|
||||
VirtualClientConnection conn = new VirtualClientConnection(remoteAddress);
|
||||
VirtualClientConnection conn = new VirtualClientConnection(clientAddress);
|
||||
conn.peer = serverChannel.serve(conn);
|
||||
return conn;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.vertx.core.Handler;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.net.SocketAddress;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
|
||||
/**
|
||||
@@ -95,8 +96,12 @@ public class VertxRequestHandler implements Handler<RoutingContext> {
|
||||
HttpServerResponse response = request.response();
|
||||
VertxHttpResponse vertxResponse = new VertxHttpResponse(request, dispatcher.getProviderFactory(),
|
||||
request.method(), allocator, output);
|
||||
// client address may not be available with VirtualHttp
|
||||
SocketAddress socketAddress = request.remoteAddress();
|
||||
String host = socketAddress != null ? socketAddress.host() : null;
|
||||
|
||||
VertxHttpRequest vertxRequest = new VertxHttpRequest(ctx, headers, uriInfo, request.rawMethod(),
|
||||
request.remoteAddress().host(), dispatcher.getDispatcher(), vertxResponse, false);
|
||||
host, dispatcher.getDispatcher(), vertxResponse, false);
|
||||
vertxRequest.setInputStream(is);
|
||||
try {
|
||||
ResteasyContext.pushContext(SecurityContext.class, new QuarkusResteasySecurityContext(request));
|
||||
|
||||
116
integration-tests/amazon-lambda-http-resteasy/pom.xml
Normal file
116
integration-tests/amazon-lambda-http-resteasy/pom.xml
Normal file
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>quarkus-integration-tests-parent</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<version>999-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>quarkus-integration-test-amazon-lambda-http-resteasy</artifactId>
|
||||
<name>Quarkus - Integration Tests - Amazon Lambda HTTP Resteasy</name>
|
||||
<description>Test with Resteasy Standalone and Amazon Lambda HTTP</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-amazon-lambda-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-test-amazon-lambda</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native-image</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<native.image.path>
|
||||
${project.build.directory}/${project.build.finalName}-runner
|
||||
</native.image.path>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>native-image</id>
|
||||
<goals>
|
||||
<goal>native-image</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<reportErrorsAtRuntime>false</reportErrorsAtRuntime>
|
||||
<cleanupServer>true</cleanupServer>
|
||||
<enableHttpUrlHandler>true</enableHttpUrlHandler>
|
||||
<graalvmHome>${graalvmHome}</graalvmHome>
|
||||
<enableJni>false</enableJni>
|
||||
<debugBuildProcess>false</debugBuildProcess>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,43 @@
|
||||
package io.quarkus.it.amazon.lambda;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/hello")
|
||||
public class GreetingResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String hello() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
public String hello(String name) {
|
||||
return "hello " + name;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public byte[] hello(byte[] bytes) {
|
||||
if (bytes[0] != 0 || bytes[1] != 1 || bytes[2] != 2 || bytes[3] != 3) {
|
||||
throw new RuntimeException("bad input");
|
||||
}
|
||||
byte[] rtn = { 4, 5, 6 };
|
||||
return rtn;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("empty")
|
||||
public void empty() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
quarkus.lambda.enable-polling-jvm-mode=true
|
||||
quarkus.http.virtual=true
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.quarkus.it.amazon.lambda;
|
||||
|
||||
import io.quarkus.test.junit.NativeImageTest;
|
||||
|
||||
@NativeImageTest
|
||||
public class AmazonLambdaSimpleIT extends AmazonLambdaSimpleTestCase {
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package io.quarkus.it.amazon.lambda;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.quarkus.amazon.lambda.http.model.AwsProxyRequest;
|
||||
import io.quarkus.amazon.lambda.http.model.AwsProxyResponse;
|
||||
import io.quarkus.amazon.lambda.http.model.Headers;
|
||||
import io.quarkus.amazon.lambda.test.LambdaClient;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
|
||||
@QuarkusTest
|
||||
public class AmazonLambdaSimpleTestCase {
|
||||
|
||||
@Test
|
||||
public void testGetText() throws Exception {
|
||||
testGetText("/hello");
|
||||
}
|
||||
|
||||
private String body(AwsProxyResponse response) {
|
||||
if (!response.isBase64Encoded())
|
||||
return response.getBody();
|
||||
return new String(Base64.decodeBase64(response.getBody()));
|
||||
}
|
||||
|
||||
private void testGetText(String path) {
|
||||
AwsProxyRequest request = new AwsProxyRequest();
|
||||
request.setHttpMethod("GET");
|
||||
request.setPath(path);
|
||||
AwsProxyResponse out = LambdaClient.invoke(AwsProxyResponse.class, request);
|
||||
Assertions.assertEquals(out.getStatusCode(), 200);
|
||||
Assertions.assertEquals(body(out), "hello");
|
||||
Assertions.assertTrue(out.getMultiValueHeaders().getFirst("Content-Type").startsWith("text/plain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404() throws Exception {
|
||||
AwsProxyRequest request = new AwsProxyRequest();
|
||||
request.setHttpMethod("GET");
|
||||
request.setPath("/nowhere");
|
||||
AwsProxyResponse out = LambdaClient.invoke(AwsProxyResponse.class, request);
|
||||
Assertions.assertEquals(out.getStatusCode(), 404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostText() throws Exception {
|
||||
testPostText("/hello");
|
||||
}
|
||||
|
||||
private void testPostText(String path) {
|
||||
AwsProxyRequest request = new AwsProxyRequest();
|
||||
request.setHttpMethod("POST");
|
||||
request.setMultiValueHeaders(new Headers());
|
||||
request.getMultiValueHeaders().add("Content-Type", "text/plain");
|
||||
request.setPath(path);
|
||||
request.setBody("Bill");
|
||||
AwsProxyResponse out = LambdaClient.invoke(AwsProxyResponse.class, request);
|
||||
Assertions.assertEquals(out.getStatusCode(), 200);
|
||||
Assertions.assertEquals(body(out), "hello Bill");
|
||||
Assertions.assertTrue(out.getMultiValueHeaders().getFirst("Content-Type").startsWith("text/plain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostBinary() throws Exception {
|
||||
AwsProxyRequest request = new AwsProxyRequest();
|
||||
byte[] bytes = { 0, 1, 2, 3 };
|
||||
String body = Base64.encodeBase64String(bytes);
|
||||
request.setHttpMethod("POST");
|
||||
request.setMultiValueHeaders(new Headers());
|
||||
request.getMultiValueHeaders().add("Content-Type", MediaType.APPLICATION_OCTET_STREAM);
|
||||
request.setPath("/hello");
|
||||
request.setBody(body);
|
||||
request.setIsBase64Encoded(true);
|
||||
AwsProxyResponse out = LambdaClient.invoke(AwsProxyResponse.class, request);
|
||||
Assertions.assertEquals(out.getStatusCode(), 200);
|
||||
Assertions.assertEquals(out.getMultiValueHeaders().getFirst("Content-Type"), MediaType.APPLICATION_OCTET_STREAM);
|
||||
Assertions.assertTrue(out.isBase64Encoded());
|
||||
byte[] rtn = Base64.decodeBase64(out.getBody());
|
||||
Assertions.assertEquals(rtn[0], 4);
|
||||
Assertions.assertEquals(rtn[1], 5);
|
||||
Assertions.assertEquals(rtn[2], 6);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostEmpty() throws Exception {
|
||||
AwsProxyRequest request = new AwsProxyRequest();
|
||||
request.setHttpMethod("POST");
|
||||
request.setMultiValueHeaders(new Headers());
|
||||
request.setPath("/hello/empty");
|
||||
AwsProxyResponse out = LambdaClient.invoke(AwsProxyResponse.class, request);
|
||||
Assertions.assertEquals(out.getStatusCode(), 204);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,6 +61,7 @@
|
||||
<module>test-extension</module>
|
||||
<module>amazon-lambda</module>
|
||||
<module>amazon-lambda-http-it</module>
|
||||
<module>amazon-lambda-http-resteasy</module>
|
||||
<module>kogito</module>
|
||||
<module>kogito-maven</module>
|
||||
<module>kubernetes</module>
|
||||
@@ -73,6 +74,7 @@
|
||||
<module>resteasy-jackson</module>
|
||||
<module>jgit</module>
|
||||
<module>virtual-http</module>
|
||||
<module>virtual-http-resteasy</module>
|
||||
<module>artemis-core</module>
|
||||
<module>artemis-jms</module>
|
||||
<module>maven</module>
|
||||
|
||||
113
integration-tests/virtual-http-resteasy/pom.xml
Normal file
113
integration-tests/virtual-http-resteasy/pom.xml
Normal file
@@ -0,0 +1,113 @@
|
||||
<?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>
|
||||
<artifactId>quarkus-integration-tests-parent</artifactId>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<version>999-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>quarkus-integration-test-virtual-http-resteasy</artifactId>
|
||||
<name>Quarkus - Integration Tests - Virtual Http Resteasy Standalone</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-azure-functions-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure.functions</groupId>
|
||||
<artifactId>azure-functions-java-library</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native-image</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>native-image</id>
|
||||
<goals>
|
||||
<goal>native-image</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<cleanupServer>true</cleanupServer>
|
||||
<enableHttpUrlHandler>true</enableHttpUrlHandler>
|
||||
<graalvmHome>${graalvmHome}</graalvmHome>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.quarkus.it.virtual;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/hello")
|
||||
public class GreetingResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String hello() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
public String hello(String name) {
|
||||
return "hello " + name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
quarkus.http.virtual=true
|
||||
@@ -0,0 +1,140 @@
|
||||
package io.quarkus.it.virtual;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.microsoft.azure.functions.ExecutionContext;
|
||||
import com.microsoft.azure.functions.HttpMethod;
|
||||
import com.microsoft.azure.functions.HttpResponseMessage;
|
||||
import com.microsoft.azure.functions.HttpStatus;
|
||||
|
||||
import io.quarkus.azure.functions.resteasy.runtime.Function;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.restassured.RestAssured;
|
||||
|
||||
/**
|
||||
* Unit test for Function class.
|
||||
*/
|
||||
@QuarkusTest
|
||||
public class FunctionTest {
|
||||
@Test
|
||||
public void testJaxrs() throws Exception {
|
||||
String uri = "https://foo.com/hello";
|
||||
testGET(uri);
|
||||
testPOST(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotFound() {
|
||||
final HttpRequestMessageMock req = new HttpRequestMessageMock();
|
||||
req.setUri(URI.create("https://nowhere.com/badroute"));
|
||||
req.setHttpMethod(HttpMethod.GET);
|
||||
|
||||
// Invoke
|
||||
final HttpResponseMessage ret = new Function().run(req, new ExecutionContext() {
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvocationId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFunctionName() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Verify
|
||||
Assertions.assertEquals(ret.getStatus(), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttp() {
|
||||
// assure that socket is created in dev/test mode
|
||||
RestAssured.when().get("/hello").then()
|
||||
.contentType("text/plain")
|
||||
.body(equalTo("hello"));
|
||||
|
||||
RestAssured.given().contentType("text/plain").body("Bill").post("/hello").then()
|
||||
.contentType("text/plain")
|
||||
.body(containsString("hello Bill"));
|
||||
}
|
||||
|
||||
private void testGET(String uri) {
|
||||
final HttpRequestMessageMock req = new HttpRequestMessageMock();
|
||||
req.setUri(URI.create(uri));
|
||||
req.setHttpMethod(HttpMethod.GET);
|
||||
|
||||
// Invoke
|
||||
final HttpResponseMessage ret = new Function().run(req, new ExecutionContext() {
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvocationId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFunctionName() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Verify
|
||||
Assertions.assertEquals(ret.getStatus(), HttpStatus.OK);
|
||||
Assertions.assertEquals("hello", new String((byte[]) ret.getBody(), StandardCharsets.UTF_8));
|
||||
String contentType = ret.getHeader("Content-Type");
|
||||
Assertions.assertNotNull(contentType);
|
||||
Assertions.assertTrue(MediaType.valueOf(contentType).isCompatible(MediaType.TEXT_PLAIN_TYPE));
|
||||
}
|
||||
|
||||
private void testPOST(String uri) {
|
||||
final HttpRequestMessageMock req = new HttpRequestMessageMock();
|
||||
req.setUri(URI.create(uri));
|
||||
req.setHttpMethod(HttpMethod.POST);
|
||||
req.setBody("Bill".getBytes());
|
||||
req.getHeaders().put("Content-Type", "text/plain");
|
||||
|
||||
// Invoke
|
||||
final HttpResponseMessage ret = new Function().run(req, new ExecutionContext() {
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvocationId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFunctionName() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Verify
|
||||
Assertions.assertEquals(ret.getStatus(), HttpStatus.OK);
|
||||
Assertions.assertEquals("hello Bill", new String((byte[]) ret.getBody(), StandardCharsets.UTF_8));
|
||||
String contentType = ret.getHeader("Content-Type");
|
||||
Assertions.assertNotNull(contentType);
|
||||
Assertions.assertTrue(MediaType.valueOf(contentType).isCompatible(MediaType.TEXT_PLAIN_TYPE));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package io.quarkus.it.virtual;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.microsoft.azure.functions.HttpMethod;
|
||||
import com.microsoft.azure.functions.HttpRequestMessage;
|
||||
import com.microsoft.azure.functions.HttpResponseMessage;
|
||||
import com.microsoft.azure.functions.HttpStatus;
|
||||
import com.microsoft.azure.functions.HttpStatusType;
|
||||
|
||||
public class HttpRequestMessageMock implements HttpRequestMessage<Optional<byte[]>> {
|
||||
protected URI uri;
|
||||
protected HttpMethod httpMethod;
|
||||
protected Map<String, String> headers = new HashMap<>();
|
||||
protected Map<String, String> queryParameters = new HashMap<>();
|
||||
protected byte[] body;
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpMethod getHttpMethod() {
|
||||
return httpMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getQueryParameters() {
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> getBody() {
|
||||
return Optional.ofNullable(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseMessage.Builder createResponseBuilder(HttpStatus httpStatus) {
|
||||
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(httpStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseMessage.Builder createResponseBuilder(HttpStatusType httpStatusType) {
|
||||
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(httpStatusType);
|
||||
}
|
||||
|
||||
public void setUri(URI uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void setHttpMethod(HttpMethod httpMethod) {
|
||||
this.httpMethod = httpMethod;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public void setQueryParameters(Map<String, String> queryParameters) {
|
||||
this.queryParameters = queryParameters;
|
||||
}
|
||||
|
||||
public void setBody(byte[] body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package io.quarkus.it.virtual;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.microsoft.azure.functions.HttpResponseMessage;
|
||||
import com.microsoft.azure.functions.HttpStatus;
|
||||
import com.microsoft.azure.functions.HttpStatusType;
|
||||
|
||||
/**
|
||||
* The mock for HttpResponseMessage, can be used in unit tests to verify if the
|
||||
* returned response by HTTP trigger function is correct or not.
|
||||
*/
|
||||
public class HttpResponseMessageMock implements HttpResponseMessage {
|
||||
private int httpStatusCode;
|
||||
private HttpStatusType httpStatus;
|
||||
private Object body;
|
||||
private Map<String, String> headers;
|
||||
|
||||
public HttpResponseMessageMock(final HttpStatusType status, final Map<String, String> headers, final Object body) {
|
||||
this.httpStatus = status;
|
||||
this.httpStatusCode = status.value();
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatusType getStatus() {
|
||||
return this.httpStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String key) {
|
||||
return this.headers.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getBody() {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
public static class HttpResponseMessageBuilderMock implements HttpResponseMessage.Builder {
|
||||
private Object body;
|
||||
private int httpStatusCode;
|
||||
private Map<String, String> headers = new HashMap<>();
|
||||
private HttpStatusType httpStatus;
|
||||
|
||||
public Builder status(HttpStatus status) {
|
||||
this.httpStatusCode = status.value();
|
||||
this.httpStatus = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder status(final HttpStatusType httpStatusType) {
|
||||
this.httpStatusCode = httpStatusType.value();
|
||||
this.httpStatus = httpStatusType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseMessage.Builder header(final String key, final String value) {
|
||||
this.headers.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseMessage.Builder body(final Object body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseMessage build() {
|
||||
return new HttpResponseMessageMock(this.httpStatus, this.headers, this.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user