Add a RestTemplate smoke test

Closes gh-37
This commit is contained in:
Sébastien Deleuze
2023-10-10 12:58:18 +02:00
parent 075181f0d6
commit c0d44ec47c
9 changed files with 205 additions and 0 deletions

View File

@@ -0,0 +1 @@
Tests if `RestTemplate` works with Reactor Netty.

View File

@@ -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")
}

View File

@@ -0,0 +1,6 @@
version: '3'
services:
httpbin:
image: 'mccutchen/go-httpbin:v2.10.0'
ports:
- '8080'

View File

@@ -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'\\}"));
}
}

View File

@@ -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 + '\'' + '}';
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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));
}
}