Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete vertx-http test coverage #4658 #4714

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/modules/ROOT/pages/reference/extensions/vertx-http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,18 @@ You will also need to enable serialization for the exception classes that you in
----
@RegisterForReflection(targets = { IllegalStateException.class, MyCustomException.class }, serialization = true)
----

[id="extensions-vertx-http-additional-camel-quarkus-configuration"]
== Additional Camel Quarkus configuration

[id="extensions-vertx-http-configuration-allowjavaserializedobject-option-in-native-mode"]
== allowJavaSerializedObject option in native mode

When using the `allowJavaSerializedObject` option in native mode, the support of serialization might need to be enabled.
Please, refer to the xref:user-guide/native-mode.adoc#serialization[native mode user guide] for more information.

[id="extensions-vertx-http-configuration-character-encodings"]
=== Character encodings

Check the xref:user-guide/native-mode.adoc#charsets[Character encodings section] of the Native mode guide if the application is expected to send and receive requests using non-default encodings.

8 changes: 8 additions & 0 deletions extensions/vertx-http/runtime/src/main/doc/configuration.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
== allowJavaSerializedObject option in native mode

When using the `allowJavaSerializedObject` option in native mode, the support of serialization might need to be enabled.
Please, refer to the xref:user-guide/native-mode.adoc#serialization[native mode user guide] for more information.

=== Character encodings

Check the xref:user-guide/native-mode.adoc#charsets[Character encodings section] of the Native mode guide if the application is expected to send and receive requests using non-default encodings.
10 changes: 10 additions & 0 deletions integration-tests/http/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@
<artifactId>quarkus-junit4-mock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<exclusions>
<exclusion>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- test dependencies - camel-quarkus -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,24 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.multipart.MultipartForm;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.Exchange;
import org.apache.camel.FluentProducerTemplate;
import org.apache.camel.Message;
import org.apache.camel.PropertyBindingException;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.EndpointConsumerBuilder;
import org.apache.camel.builder.EndpointProducerBuilder;
import org.apache.camel.builder.endpoint.EndpointRouteBuilder;
import org.apache.camel.http.base.HttpOperationFailedException;
import org.apache.camel.util.IOHelper;
import org.eclipse.microprofile.config.ConfigProvider;

import static org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_TYPE_FORM_URLENCODED;

@Path("/test/client")
@ApplicationScoped
public class HttpResource {
Expand Down Expand Up @@ -379,6 +387,105 @@ public String vertxHttpSerializedException(@QueryParam("test-port") int port) {
return exchange.getException().getClass().getName();
}

@Path("/vertx-http/multipart-form-params")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String vertxHttpMultipartFormParams(@QueryParam("test-port") int port,
@QueryParam("organization") String organization,
@QueryParam("project") String project) {
return producerTemplate
.toF("vertx-http:http://localhost:%d/service/multipart-form-params", port)
.withBody("organization=" + organization + "&project=" + project)
.withHeader(Exchange.CONTENT_TYPE, CONTENT_TYPE_FORM_URLENCODED)
.request(String.class);
}

@Path("/vertx-http/multipart-form-data")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String vertxHttpMultipartFormData(@QueryParam("test-port") int port) {

MultipartForm form = MultipartForm.create();
form.binaryFileUpload("part-1", "test1.txt", Buffer.buffer("part1=content1".getBytes(StandardCharsets.UTF_8)),
"text/plain");
form.binaryFileUpload("part-2", "test2.xml",
Buffer.buffer("<part2 value=\"content2\"/>".getBytes(StandardCharsets.UTF_8)), "text/xml");

return producerTemplate
.toF("vertx-http:http://localhost:%d/service/multipart-form-data", port)
.withBody(form)
.request(String.class);
}

@Path("/vertx-http/custom-vertx-options")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String vertxHttpCustomVertxOptions(@QueryParam("test-port") int port) {
try {
producerTemplate
.toF("vertx-http:http://localhost:%d/service/custom-vertx-options?vertxOptions=#myVertxOptions", port)
.request();
return "NOT_EXPECTED: the custom vertxOptions should have triggered a ResolveEndpointFailedException";
} catch (ResolveEndpointFailedException refex) {
Throwable firstLevelExceptionCause = refex.getCause();
if (firstLevelExceptionCause instanceof PropertyBindingException) {
if (firstLevelExceptionCause.getCause() instanceof IllegalArgumentException) {
return "OK: the custom vertxOptions has triggered the expected exception";
}
return "NOT_EXPECTED: the 2nd level exception cause should be of type IllegalArgumentException";
} else {
return "NOT_EXPECTED: the 1st level exception cause should be of type PropertyBindingException";
}
}
}

@Path("/vertx-http/session-management")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String vertxHttpSessionManagement(@QueryParam("test-port") int port) {
String vertxHttpBaseUri = "vertx-http:http://localhost:" + port + "/service/session-management";
Exchange result = producerTemplate
.toF("%s/secure?sessionManagement=true&cookieStore=#myVertxCookieStore", vertxHttpBaseUri)
.request(Exchange.class);

HttpOperationFailedException exception = result.getException(HttpOperationFailedException.class);
if (exception.getStatusCode() != 403) {
return "NOT_EXPECTED: The first request in the session is expected to return HTTP 403";
}

result = producerTemplate
.toF("%s/login?sessionManagement=true&cookieStore=#myVertxCookieStore", vertxHttpBaseUri)
.withHeader("username", "my-username")
.withHeader("password", "my-password")
.request(Exchange.class);

Message msg = result.getMessage();
if (msg == null) {
return "NOT_EXPECTED: The second request in the session should return a message";
} else {
String setCookieHeader = msg.getHeader("Set-Cookie", String.class);
if (setCookieHeader == null || !setCookieHeader.contains("sessionId=my-session-id-123")) {
return "NOT_EXPECTED: The message should have a Set-Cookie String header containing \"sessionId=my-session-id-123\"";
}
}

return producerTemplate
.toF("%s/secure?sessionManagement=true&cookieStore=#myVertxCookieStore", vertxHttpBaseUri)
.request(String.class);
}

@Path("/vertx-http/buffer-conversion-with-charset")
@GET
public byte[] vertxBufferConversionWithCharset(@QueryParam("string") String string, @QueryParam("charset") String charset) {
Buffer buffer = producerTemplate
.to("direct:vertx-http-buffer-conversion-with-charset")
.withBody(string)
.withHeader(Exchange.CONTENT_TYPE, "text/plain;charset=" + charset)
.request(Buffer.class);

return buffer.getBytes();
}

// *****************************
//
// Send dynamic tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import javax.inject.Named;

import io.quarkus.runtime.annotations.RegisterForReflection;
import io.vertx.core.buffer.Buffer;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
Expand Down Expand Up @@ -77,6 +78,8 @@ public void process(Exchange exchange) throws Exception {
from("netty-http:http://0.0.0.0:{{camel.netty-http.test-port}}/test/server/myService")
.transform().constant("Hello from myService");

from("direct:vertx-http-buffer-conversion-with-charset")
.convertBodyTo(Buffer.class);
}

@Named
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@
*/
package org.apache.camel.quarkus.component.http.it;

import java.util.Map;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.CookieParam;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;

@Path("/service")
@ApplicationScoped
Expand All @@ -41,4 +49,53 @@ public String get() {
public String toUpper(String message) {
return message.toUpperCase();
}

@POST
@Path("/multipart-form-params")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public String multipartFormParams(@FormParam("organization") String organization, @FormParam("project") String project) {
return String.format("multipartFormParams(%s, %s)", organization, project);
}

@POST
@Path("/multipart-form-data")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String multipartFormData(Map<String, String> parts) {
if (parts.size() != 2 || !parts.keySet().contains("part-1") || !parts.keySet().contains("part-2")) {
throw new IllegalArgumentException(
"There should be exactly 2 parts named \"part-1\" and \"parts-2\" in the multipart upload");
}
return String.format("multipartFormData(%s, %s)", parts.get("part-1"), parts.get("part-2"));
}

@GET
@Path("/custom-vertx-options")
public void customVertxOptions() {
// We are not expected to pass here as the Vert.x HTTP client should throw IllegalArgumentException
}

@GET
@Path("/session-management/secure")
@Produces(MediaType.TEXT_PLAIN)
public String getSecuredContent(@CookieParam("sessionId") String cookie) {
if ("my-session-id-123".equals(cookie)) {
return "Some secret content";
} else {
throw new ForbiddenException("A cookie with session id is needed to access the secured content");
}
}

@GET
@Path("/session-management/login")
@Produces(MediaType.TEXT_PLAIN)
public Response login(@HeaderParam("username") String username, @HeaderParam("password") String password) {
if ("my-username".equals(username) && "my-password".equals(password)) {
NewCookie cookie = new NewCookie("sessionId", "my-session-id-123");
return Response.ok().cookie(cookie).build();
}
throw new ForbiddenException("Wrong username/password, no cookie will be created");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.quarkus.component.http.it;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.Produces;

import io.vertx.core.VertxOptions;
import io.vertx.ext.web.client.spi.CookieStore;

@ApplicationScoped
public class VertxClientRelatedBeansProducer {

@Singleton
@Produces
@Named("myVertxOptions")
VertxOptions createOptions() {
// Setting an inconsistent value to generate an IllegalArgumentException on first Vertx.x HTTP client request
return new VertxOptions().setMaxEventLoopExecuteTime(0);
}

@ApplicationScoped
@Produces
@Named("myVertxCookieStore")
CookieStore createCookieStore() {
return CookieStore.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# Quarkus
#
quarkus.native.resources.includes = jsse/*,restcountries/*
quarkus.native.add-all-charsets = true
quarkus.camel.native.reflection.serialization-enabled = true

# Basic authentication configuration
Expand Down