Use httpbin as docker compose service

Closes gh-184
This commit is contained in:
Moritz Halbritter
2023-07-20 14:02:01 +02:00
parent aa747649a2
commit bc7195d00d
15 changed files with 247 additions and 76 deletions

View File

@@ -1,7 +1,22 @@
version: '3'
services:
httpecho:
image: 'mhalbritter/http-echo:2'
httpbin:
image: 'mccutchen/go-httpbin:v2.10.0'
ports:
- '80'
- '443'
- '8080'
httpbin_tls:
image: 'mccutchen/go-httpbin:v2.10.0'
environment:
- 'PORT=8443'
- 'HTTPS_CERT_FILE=/server-certificate'
- 'HTTPS_KEY_FILE=/server-key'
configs:
- 'server-certificate'
- 'server-key'
ports:
- '8443'
configs:
server-certificate:
file: './server.crt'
server-key:
file: './server.key'

View File

@@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAcagAwIBAgIUJL2NEOsGlUgyKo3jUur8gol3ymowCgYIKoZIzj0EAwIw
VjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT
RGVmYXVsdCBDb21wYW55IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIzMDYy
NjA4MzY0NFoYDzIxMjMwNjAyMDgzNjQ0WjBWMQswCQYDVQQGEwJYWDEVMBMGA1UE
BwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMRIw
EAYDVQQDDAlsb2NhbGhvc3QwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARm10hC6jI0
tA5dVYyYLsaS+rDXaFDbtspX/mxHk5VTfklPD06L3sXcNJeve6YQHlOTwdUzLi2y
iGuaVcljlA31iOtfQEATeSdbeFxxLjM22U+FZJ94j14XrbemtpspuTujUzBRMB0G
A1UdDgQWBBQEfrPdmYvL/w5sLHWL0eVj0f1M0DAfBgNVHSMEGDAWgBQEfrPdmYvL
/w5sLHWL0eVj0f1M0DAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA2gAMGUC
MHtVMoEKtgkOcv2fhrv0788S/yIRa6PBt8nxMa6d7mDTFGkMhBCIG168pJk9nHE+
vgIxAJ1JF2uB5PYV5nYwliOttnb8LMza7hhun1EVsfKuFgvMUD3VTgtZJ9PE4c8I
pxq8IA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,9 @@
-----BEGIN EC PARAMETERS-----
BgUrgQQAIg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCVOy3osulJ/8y+ckbBc0dAdSiLFiRcU1SFqWWsmoaCKexSBOgA8/vG
DFFqYvummn6gBwYFK4EEACKhZANiAARm10hC6jI0tA5dVYyYLsaS+rDXaFDbtspX
/mxHk5VTfklPD06L3sXcNJeve6YQHlOTwdUzLi2yiGuaVcljlA31iOtfQEATeSdb
eFxxLjM22U+FZJ94j14XrbemtpspuTs=
-----END EC PRIVATE KEY-----

View File

@@ -19,14 +19,16 @@ class RestTemplateApplicationAotTests {
void httpWorks(AssertableOutput output) {
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.untilAsserted(() -> assertThat(output).hasSingleLineContaining("http worked:"));
.untilAsserted(() -> assertThat(output)
.hasLineMatching("http: DataDto\\{url='http:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}"));
}
@Test
void httpsWorks(AssertableOutput output) {
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.untilAsserted(() -> assertThat(output).hasSingleLineContaining("https worked:"));
.untilAsserted(() -> assertThat(output)
.hasLineMatching("https: DataDto\\{url='https:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}"));
}
}

View File

@@ -2,27 +2,32 @@ package com.example.resttemplate;
import java.net.URI;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
@Component
@RegisterReflectionForBinding(DataDto.class)
class CLR implements CommandLineRunner {
private final RestTemplate restTemplate;
private final String host;
private final String httpHost;
private final int port;
private final int httpPort;
private final int tlsPort;
private final String httpsHost;
private final int httpsPort;
CLR(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.host = env("HTTPECHO_HOST", "localhost");
this.port = env("HTTPECHO_PORT_80", 8080);
this.tlsPort = env("HTTPECHO_PORT_443", 8443);
this.httpHost = env("HTTPBIN_HOST", "localhost");
this.httpsHost = env("HTTPBIN_TLS_HOST", "localhost");
this.httpPort = env("HTTPBIN_PORT_8080", 8080);
this.httpsPort = env("HTTPBIN_TLS_PORT_8443", 8443);
}
@Override
@@ -33,9 +38,9 @@ class CLR implements CommandLineRunner {
private void http() {
try {
String response = this.restTemplate
.getForObject(URI.create("http://%s:%d/".formatted(this.host, this.port)), String.class);
System.out.printf("http worked: %s%n", response);
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:");
@@ -45,9 +50,9 @@ class CLR implements CommandLineRunner {
private void https() {
try {
String response = this.restTemplate
.getForObject(URI.create("https://%s:%d/".formatted(this.host, this.tlsPort)), String.class);
System.out.printf("https worked: %s%n", response);
DataDto dto = restTemplate.getForObject(
URI.create("https://%s:%d/anything".formatted(this.httpsHost, this.httpsPort)), DataDto.class);
System.out.printf("https: %s%n", dto);
}
catch (Exception ex) {
System.out.println("https failed:");

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

@@ -1,7 +1,22 @@
version: '3'
services:
httpecho:
image: 'mhalbritter/http-echo:2'
httpbin:
image: 'mccutchen/go-httpbin:v2.10.0'
ports:
- '80'
- '443'
- '8080'
httpbin_tls:
image: 'mccutchen/go-httpbin:v2.10.0'
environment:
- 'PORT=8443'
- 'HTTPS_CERT_FILE=/server-certificate'
- 'HTTPS_KEY_FILE=/server-key'
configs:
- 'server-certificate'
- 'server-key'
ports:
- '8443'
configs:
server-certificate:
file: './server.crt'
server-key:
file: './server.key'

View File

@@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAcagAwIBAgIUJL2NEOsGlUgyKo3jUur8gol3ymowCgYIKoZIzj0EAwIw
VjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT
RGVmYXVsdCBDb21wYW55IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIzMDYy
NjA4MzY0NFoYDzIxMjMwNjAyMDgzNjQ0WjBWMQswCQYDVQQGEwJYWDEVMBMGA1UE
BwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMRIw
EAYDVQQDDAlsb2NhbGhvc3QwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARm10hC6jI0
tA5dVYyYLsaS+rDXaFDbtspX/mxHk5VTfklPD06L3sXcNJeve6YQHlOTwdUzLi2y
iGuaVcljlA31iOtfQEATeSdbeFxxLjM22U+FZJ94j14XrbemtpspuTujUzBRMB0G
A1UdDgQWBBQEfrPdmYvL/w5sLHWL0eVj0f1M0DAfBgNVHSMEGDAWgBQEfrPdmYvL
/w5sLHWL0eVj0f1M0DAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA2gAMGUC
MHtVMoEKtgkOcv2fhrv0788S/yIRa6PBt8nxMa6d7mDTFGkMhBCIG168pJk9nHE+
vgIxAJ1JF2uB5PYV5nYwliOttnb8LMza7hhun1EVsfKuFgvMUD3VTgtZJ9PE4c8I
pxq8IA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,9 @@
-----BEGIN EC PARAMETERS-----
BgUrgQQAIg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCVOy3osulJ/8y+ckbBc0dAdSiLFiRcU1SFqWWsmoaCKexSBOgA8/vG
DFFqYvummn6gBwYFK4EEACKhZANiAARm10hC6jI0tA5dVYyYLsaS+rDXaFDbtspX
/mxHk5VTfklPD06L3sXcNJeve6YQHlOTwdUzLi2yiGuaVcljlA31iOtfQEATeSdb
eFxxLjM22U+FZJ94j14XrbemtpspuTs=
-----END EC PRIVATE KEY-----

View File

@@ -17,23 +17,26 @@ class WebClientApplicationAotTests {
@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).hasSingleLineContaining("https worked:");
});
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.untilAsserted(() -> assertThat(output)
.hasLineMatching("http: DataDto\\{url='http:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}"));
}
@Test
void httpsWorks(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(30)).untilAsserted(() -> {
assertThat(output).hasSingleLineContaining("https worked:");
});
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.untilAsserted(() -> assertThat(output)
.hasLineMatching("https: DataDto\\{url='https:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}"));
}
@Test
void serviceWorks(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(30)).untilAsserted(() -> {
assertThat(output).hasSingleLineContaining("service worked:");
});
Awaitility.await()
.atMost(Duration.ofSeconds(30))
.untilAsserted(() -> assertThat(output)
.hasLineMatching("service: ExchangeDataDto\\{url='http:\\/\\/\\w+:\\d+\\/anything', method='GET'\\}"));
}
}

View File

@@ -2,12 +2,14 @@ package com.example.webclient;
import java.time.Duration;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
@Component
@RegisterReflectionForBinding(DataDto.class)
class CLR implements CommandLineRunner {
private final WebClient httpWebClient;
@@ -32,13 +34,13 @@ class CLR implements CommandLineRunner {
private void http() {
try {
String response = this.httpWebClient.get()
.uri("/")
DataDto dto = this.httpWebClient.get()
.uri("/anything")
.retrieve()
.bodyToMono(String.class)
.bodyToMono(DataDto.class)
.timeout(Duration.ofSeconds(10))
.block();
System.out.printf("http worked: %s%n", response);
System.out.printf("http: %s%n", dto);
}
catch (Exception ex) {
System.out.println("http failed:");
@@ -48,13 +50,13 @@ class CLR implements CommandLineRunner {
private void https() {
try {
String response = this.httpsWebClient.get()
.uri("/")
DataDto dto = this.httpsWebClient.get()
.uri("/anything")
.retrieve()
.bodyToMono(String.class)
.bodyToMono(DataDto.class)
.timeout(Duration.ofSeconds(10))
.block();
System.out.printf("https worked: %s%n", response);
System.out.printf("https: %s%n", dto);
}
catch (Exception ex) {
System.out.println("https failed:");
@@ -64,8 +66,8 @@ class CLR implements CommandLineRunner {
private void service() {
try {
String dto = this.dataService.getData();
System.out.printf("service worked: %s%n", dto);
ExchangeDataDto dto = this.dataService.getData();
System.out.printf("service: %s%n", dto);
}
catch (Exception ex) {
System.out.println("service failed:");

View File

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

View File

@@ -4,7 +4,7 @@ import org.springframework.web.service.annotation.GetExchange;
interface DataService {
@GetExchange("/")
String getData();
@GetExchange("/anything")
ExchangeDataDto getData();
}

View File

@@ -0,0 +1,33 @@
package com.example.webclient;
public class ExchangeDataDto {
private String url;
private String method;
public ExchangeDataDto() {
}
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 "ExchangeDataDto{" + "url='" + url + '\'' + ", method='" + method + '\'' + '}';
}
}

View File

@@ -19,27 +19,26 @@ import org.springframework.web.service.invoker.HttpServiceProxyFactory;
@Configuration(proxyBeanMethods = false)
class WebClientConfiguration {
@Bean
HttpEchoConfig httpEchoConfig() {
return HttpEchoConfig.loadFromEnv();
}
@Bean
@Qualifier("https")
WebClient webClientHttps(HttpEchoConfig httpEchoConfig, WebClient.Builder builder) throws SSLException {
WebClient webClientHttps(WebClient.Builder builder) throws SSLException {
SslContext sslContext = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
return builder.baseUrl(httpEchoConfig.httpsBaseUrl())
String host = env("HTTPBIN_TLS_HOST", "localhost");
int port = env("HTTPBIN_TLS_PORT_8443", 8443);
return builder.baseUrl("https://%s:%d/".formatted(host, port))
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
@Bean
@Qualifier("http")
WebClient webClientHttp(HttpEchoConfig httpEchoConfig, WebClient.Builder builder) {
return builder.baseUrl(httpEchoConfig.httpBaseUrl()).build();
WebClient webClientHttp(WebClient.Builder builder) {
String host = env("HTTPBIN_HOST", "localhost");
int port = env("HTTPBIN_PORT_8080", 8080);
return builder.baseUrl("http://%s:%d/".formatted(host, port)).build();
}
@Bean
@@ -49,31 +48,14 @@ class WebClientConfiguration {
return factory.createClient(DataService.class);
}
record HttpEchoConfig(String host, int port, int tlsPort) {
public static HttpEchoConfig loadFromEnv() {
String host = env("HTTPECHO_HOST", "localhost");
int port = env("HTTPECHO_PORT_80", 8080);
int tlsPort = env("HTTPECHO_PORT_443", 8443);
return new HttpEchoConfig(host, port, tlsPort);
}
private static String env(String name, String def) {
String value = System.getenv(name);
return StringUtils.hasLength(value) ? value : def;
}
String httpsBaseUrl() {
return "https://%s:%d/".formatted(this.host, this.tlsPort);
}
String httpBaseUrl() {
return "http://%s:%d/".formatted(this.host, this.port);
}
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;
}
private static int env(String name, int def) {
String value = System.getenv(name);
return StringUtils.hasLength(value) ? Integer.parseInt(value) : def;
}
}