diff --git a/framework/webclient-netty/README.adoc b/framework/webclient-netty/README.adoc new file mode 100644 index 0000000..f29119f --- /dev/null +++ b/framework/webclient-netty/README.adoc @@ -0,0 +1 @@ +Tests if `WebClient` works with Reactor Netty. diff --git a/framework/webclient-netty/build.gradle b/framework/webclient-netty/build.gradle new file mode 100644 index 0000000..a9ae596 --- /dev/null +++ b/framework/webclient-netty/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "java" + id "org.springframework.boot" + id "org.springframework.cr.smoke-test" +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + constraints { + implementation("org.springframework:spring-web:6.1.0-SNAPSHOT") + } + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.crac:crac:$cracVersion") + implementation(project(":cr-listener")) + + testImplementation("org.springframework.boot:spring-boot-starter-test") + + appTestImplementation(project(":cr-smoke-test-support")) + appTestImplementation("org.awaitility:awaitility:4.2.0") +} diff --git a/framework/webclient-netty/docker-compose.yml b/framework/webclient-netty/docker-compose.yml new file mode 100644 index 0000000..bcb4653 --- /dev/null +++ b/framework/webclient-netty/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3' +services: + httpbin: + image: 'mccutchen/go-httpbin:v2.10.0' + ports: + - '8080' diff --git a/framework/webclient-netty/src/appTest/java/com/example/webclient/WebClientApplicationTests.java b/framework/webclient-netty/src/appTest/java/com/example/webclient/WebClientApplicationTests.java new file mode 100644 index 0000000..0a0e685 --- /dev/null +++ b/framework/webclient-netty/src/appTest/java/com/example/webclient/WebClientApplicationTests.java @@ -0,0 +1,27 @@ +package com.example.webclient; + +import java.net.http.HttpClient; +import java.time.Duration; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; + +import org.springframework.cr.smoketest.support.assertj.AssertableOutput; +import org.springframework.cr.smoketest.support.junit.ApplicationTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@ApplicationTest +class WebClientApplicationTests { + + @Test + @DisabledIfEnvironmentVariable(named = "CI", matches = "true", disabledReason = "HTTP is blocked on CI") + void httpWorks(AssertableOutput output) { + Awaitility.await() + .atMost(Duration.ofSeconds(30)) + .untilAsserted(() -> assertThat(output) + .hasLineMatching("http: DataDto\\{url='http:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}")); + } + +} diff --git a/framework/webclient-netty/src/main/java/com/example/webclient/DataDto.java b/framework/webclient-netty/src/main/java/com/example/webclient/DataDto.java new file mode 100644 index 0000000..4e9e45a --- /dev/null +++ b/framework/webclient-netty/src/main/java/com/example/webclient/DataDto.java @@ -0,0 +1,33 @@ +package com.example.webclient; + +public class DataDto { + + private String url; + + private String method; + + public DataDto() { + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + @Override + public String toString() { + return "DataDto{" + "url='" + url + '\'' + ", method='" + method + '\'' + '}'; + } + +} diff --git a/framework/webclient-netty/src/main/java/com/example/webclient/DataRequester.java b/framework/webclient-netty/src/main/java/com/example/webclient/DataRequester.java new file mode 100644 index 0000000..e5ae34c --- /dev/null +++ b/framework/webclient-netty/src/main/java/com/example/webclient/DataRequester.java @@ -0,0 +1,59 @@ +package com.example.webclient; + +import java.time.Duration; +import java.util.function.Supplier; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.SmartLifecycle; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +@Component +class DataRequester implements SmartLifecycle { + + private final WebClient webClient; + + private volatile boolean running = false; + + DataRequester(WebClient webClient) { + this.webClient = webClient; + } + + @Override + public void start() { + if (!isRunning()) { + this.running = true; + http(); + } + } + + @Override + public void stop() { + if (isRunning()) { + this.running = false; + } + } + + private void http() { + try { + DataDto dto = this.webClient.get() + .uri("/anything") + .retrieve() + .bodyToMono(DataDto.class) + .timeout(Duration.ofSeconds(10)) + .block(); + System.out.printf("http: %s%n", dto); + } + catch (Exception ex) { + System.out.println("http failed:"); + ex.printStackTrace(System.out); + } + } + + @Override + public boolean isRunning() { + return this.running; + } + +} diff --git a/framework/webclient-netty/src/main/java/com/example/webclient/WebClientApplication.java b/framework/webclient-netty/src/main/java/com/example/webclient/WebClientApplication.java new file mode 100644 index 0000000..ac4208e --- /dev/null +++ b/framework/webclient-netty/src/main/java/com/example/webclient/WebClientApplication.java @@ -0,0 +1,17 @@ +package com.example.webclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class WebClientApplication { + + public static void main(String[] args) throws InterruptedException { + SpringApplication application = new SpringApplication(WebClientApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); + Thread.currentThread().join(); // To be able to measure memory consumption + } + +} diff --git a/framework/webclient-netty/src/main/java/com/example/webclient/WebClientConfiguration.java b/framework/webclient-netty/src/main/java/com/example/webclient/WebClientConfiguration.java new file mode 100644 index 0000000..cf797dd --- /dev/null +++ b/framework/webclient-netty/src/main/java/com/example/webclient/WebClientConfiguration.java @@ -0,0 +1,32 @@ +package com.example.webclient; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.util.StringUtils; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration(proxyBeanMethods = false) +class WebClientConfiguration { + + @Bean + WebClient webClient(WebClient.Builder builder, ClientHttpConnector clientHttpConnector) { + // TODO Check why run-dev-container.sh is broken by the commented line below + //String host = env("HTTPBIN_HOST", "localhost"); + String host = "localhost"; + int port = env("HTTPBIN_PORT_8080", 8080); + return builder.baseUrl("http://%s:%d/".formatted(host, port)) + .clientConnector(clientHttpConnector).build(); + } + + private static String env(String name, String def) { + String value = System.getenv(name); + return StringUtils.hasLength(value) ? value : def; + } + + private static int env(String name, int def) { + String value = System.getenv(name); + return StringUtils.hasLength(value) ? Integer.parseInt(value) : def; + } + +} diff --git a/framework/webclient-netty/src/main/resources/application.properties b/framework/webclient-netty/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29