diff --git a/framework/resttemplate-netty/README.adoc b/framework/resttemplate-netty/README.adoc new file mode 100644 index 0000000..454dd2c --- /dev/null +++ b/framework/resttemplate-netty/README.adoc @@ -0,0 +1 @@ +Tests if `RestTemplate` works with Reactor Netty. diff --git a/framework/resttemplate-netty/build.gradle b/framework/resttemplate-netty/build.gradle new file mode 100644 index 0000000..a9ae596 --- /dev/null +++ b/framework/resttemplate-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/resttemplate-netty/docker-compose.yml b/framework/resttemplate-netty/docker-compose.yml new file mode 100644 index 0000000..bcb4653 --- /dev/null +++ b/framework/resttemplate-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/resttemplate-netty/src/appTest/java/com/example/resttemplate/RestTemplateApplicationTests.java b/framework/resttemplate-netty/src/appTest/java/com/example/resttemplate/RestTemplateApplicationTests.java new file mode 100644 index 0000000..5458a84 --- /dev/null +++ b/framework/resttemplate-netty/src/appTest/java/com/example/resttemplate/RestTemplateApplicationTests.java @@ -0,0 +1,26 @@ +package com.example.resttemplate; + +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 RestTemplateApplicationTests { + + @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/resttemplate-netty/src/main/java/com/example/resttemplate/DataDto.java b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/DataDto.java new file mode 100644 index 0000000..39442b4 --- /dev/null +++ b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/DataDto.java @@ -0,0 +1,33 @@ +package com.example.resttemplate; + +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/resttemplate-netty/src/main/java/com/example/resttemplate/DataRequester.java b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/DataRequester.java new file mode 100644 index 0000000..adaf866 --- /dev/null +++ b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/DataRequester.java @@ -0,0 +1,71 @@ +package com.example.resttemplate; + +import java.net.URI; + +import org.springframework.context.SmartLifecycle; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; + +@Component +class DataRequester implements SmartLifecycle { + + private final RestTemplate restTemplate; + + private volatile boolean running = false; + + private final String httpHost; + + private final int httpPort; + + DataRequester(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + // TODO Check why run-dev-container.sh is broken by the commented line below + // this.httpHost = env("HTTPBIN_HOST", "localhost"); + this.httpHost = "localhost"; + this.httpPort = env("HTTPBIN_PORT_8080", 8080); + } + + @Override + public void start() { + if (!isRunning()) { + this.running = true; + http(); + } + } + + @Override + public void stop() { + if (isRunning()) { + this.running = false; + } + } + + public void http() { + try { + DataDto dto = restTemplate.getForObject( + URI.create("http://%s:%d/anything".formatted(this.httpHost, this.httpPort)), DataDto.class); + 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; + } + + 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/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateApplication.java b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateApplication.java new file mode 100644 index 0000000..bb173dc --- /dev/null +++ b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateApplication.java @@ -0,0 +1,17 @@ +package com.example.resttemplate; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RestTemplateApplication { + + public static void main(String[] args) throws InterruptedException { + SpringApplication application = new SpringApplication(RestTemplateApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); + Thread.currentThread().join(); // To be able to measure memory consumption + } + +} diff --git a/framework/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateConfiguration.java b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateConfiguration.java new file mode 100644 index 0000000..6c4ff1f --- /dev/null +++ b/framework/resttemplate-netty/src/main/java/com/example/resttemplate/RestTemplateConfiguration.java @@ -0,0 +1,31 @@ +package com.example.resttemplate; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ReactorNettyClientRequestFactory; +import org.springframework.http.client.reactive.ReactorResourceFactory; +import org.springframework.web.client.RestTemplate; + +@Configuration(proxyBeanMethods = false) +class RestTemplateConfiguration { + + @Bean + RestTemplate restTemplate(RestTemplateBuilder builder, ClientHttpRequestFactory requestFactory) { + return builder.defaultHeader("User-Agent", "RestTemplateApplication") + .requestFactory(() -> requestFactory) + .build(); + } + + @Bean + ReactorResourceFactory resourceFactory() { + return new ReactorResourceFactory(); + } + + @Bean + ClientHttpRequestFactory requestFactory(ReactorResourceFactory resourceFactory) { + return new ReactorNettyClientRequestFactory(resourceFactory, mapper -> mapper.compress(true)); + } + +} diff --git a/framework/resttemplate-netty/src/main/resources/application.properties b/framework/resttemplate-netty/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29