Add webflux-netty-tls smoke test

See gh-68
This commit is contained in:
Moritz Halbritter
2022-08-08 15:21:20 +02:00
parent 029e71fc3a
commit baa5b7372f
12 changed files with 208 additions and 0 deletions

View File

@@ -50,6 +50,7 @@ smoke_tests:
- validation
- webclient
- webflux-netty
- webflux-netty-tls
- webmvc-tomcat
- webmvc-tomcat-tls
- websocket

View File

@@ -78,6 +78,7 @@ include "transactional-event-listener"
include "validation"
include "webclient"
include "webflux-netty"
include "webflux-netty-tls"
include "webmvc-tomcat"
include "webmvc-tomcat-tls"
include "websocket"

View File

@@ -0,0 +1 @@
Tests if WebFlux with Netty with TLS is working

View File

@@ -0,0 +1,22 @@
plugins {
id 'java'
id 'org.springframework.boot'
id 'org.springframework.aot.smoke-test'
id 'org.graalvm.buildtools.native'
id 'org.jetbrains.kotlin.jvm'
}
dependencies {
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation(project(":aot-smoke-test-third-party-hints"))
testImplementation("org.springframework.boot:spring-boot-starter-test")
aotTestImplementation(project(":aot-smoke-test-support"))
aotTestImplementation("io.projectreactor.netty:reactor-netty")
}
aotSmokeTest {
webApplication = true
}

View File

@@ -0,0 +1,86 @@
package com.example.webflux.tls;
import java.io.InputStream;
import java.net.URI;
import java.security.KeyStore;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.TrustManagerFactory;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import org.junit.jupiter.api.Test;
import reactor.netty.http.client.HttpClient;
import org.springframework.aot.smoketest.support.junit.AotSmokeTest;
import org.springframework.aot.smoketest.support.junit.ApplicationUrl;
import org.springframework.aot.smoketest.support.junit.ApplicationUrl.Scheme;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import static org.assertj.core.api.Assertions.assertThat;
@AotSmokeTest
class WebFluxNettyTlsApplicationAotTests {
@Test
void stringResponseBody(@ApplicationUrl(scheme = Scheme.HTTPS) URI applicationUrl) throws Exception {
WebTestClient client = buildWebClient(applicationUrl);
client.get().exchange().expectStatus().isOk().expectBody().consumeWith(
(result) -> assertThat(new String(result.getResponseBodyContent())).isEqualTo("Hello World TLS"));
}
@Test
void websocket(@ApplicationUrl(scheme = Scheme.SECURE_WEBSOCKET) URI applicationUrl) throws Exception {
WebSocketClient client = new ReactorNettyWebSocketClient(buildHttpClient());
// We can't use StepVerifier here, as it isn't designed to be used in a reactive
// pipeline
AtomicReference<List<String>> messages = new AtomicReference<>();
client.execute(URI.create(applicationUrl.resolve("/ws/count").toString()), session -> session.receive()
.map(WebSocketMessage::getPayloadAsText).collectList().doOnNext(messages::set).then())
.block(Duration.ofSeconds(10));
assertThat(messages.get()).isNotNull().containsExactly("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
}
/**
* Builds a web client for the running application. This web client is configured to
* trust the TLS certificate of the server.
* @param applicationUrl the URL to the application
* @return web client
* @throws Exception if something went wrong
*/
private static WebTestClient buildWebClient(URI applicationUrl) throws Exception {
ClientHttpConnector connector = new ReactorClientHttpConnector(buildHttpClient());
return WebTestClient.bindToServer(connector).baseUrl(applicationUrl.toString()).build();
}
/**
* Builds a http client for the running application. This http client is configured to
* trust the TLS certificate of the server.
* @return http client
* @throws Exception if something went wrong
*/
private static HttpClient buildHttpClient() throws Exception {
KeyStore trustStore = KeyStore.getInstance("jks");
try (InputStream stream = WebFluxNettyTlsApplicationAotTests.class.getResourceAsStream("/truststore.jks")) {
assertThat(stream).as("Trust store on test classpath").isNotNull();
trustStore.load(stream, null);
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SslContext sslContext = SslContextBuilder.forClient().trustManager(trustManagerFactory).build();
return HttpClient.create().secure((s) -> s.sslContext(sslContext));
}
}

Binary file not shown.

View File

@@ -0,0 +1,17 @@
package com.example.webflux.tls;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping(value = "/", produces = MediaType.TEXT_PLAIN_VALUE)
public Mono<String> greet() {
return Mono.just("Hello World TLS");
}
}

View File

@@ -0,0 +1,29 @@
package com.example.webflux.tls;
import com.example.webflux.tls.WebFluxNettyTlsApplication.KeyStoreRuntimeHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.smoketest.thirdpartyhints.NettyRuntimeHints;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportRuntimeHints;
@SpringBootApplication
@ImportRuntimeHints({ NettyRuntimeHints.class, KeyStoreRuntimeHints.class })
public class WebFluxNettyTlsApplication {
public static void main(String[] args) {
SpringApplication.run(WebFluxNettyTlsApplication.class, args);
}
static class KeyStoreRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerPattern("keystore.jks");
}
}
}

View File

@@ -0,0 +1,33 @@
package com.example.webflux.tls;
import java.time.Duration;
import java.util.Map;
import reactor.core.publisher.Flux;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
@Configuration(proxyBeanMethods = false)
class WebsocketConfig {
@Bean
WebSocketHandler webSocketHandler() {
return webSocketSession -> {
Flux<WebSocketMessage> stream = Flux.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.map(element -> webSocketSession.textMessage(Integer.toString(element)))
.delayElements(Duration.ofMillis(100));
return webSocketSession.send(stream);
};
}
@Bean
public SimpleUrlHandlerMapping body(WebSocketHandler webSocketHandler) {
Map<String, WebSocketHandler> handlers = Map.of("/ws/count", webSocketHandler);
return new SimpleUrlHandlerMapping(handlers, 10);
}
}

View File

@@ -0,0 +1,4 @@
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-alias=localhost
server.ssl.key-password=secret

Binary file not shown.

View File

@@ -0,0 +1,14 @@
package com.example.webflux.tls;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class WebFluxNettyTlsApplicationTests {
@Test
void contextLoads() {
}
}