From a0ddd4b200af13ce0df7fa9a2b3760509b37df10 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Tue, 5 Mar 2024 08:22:08 +0100 Subject: [PATCH 01/12] GH-28: add support for multiple property binding --- .../wiremock/spring/ConfigureWireMock.java | 6 +- .../spring/WireMockContextCustomizer.java | 6 +- .../WireMockConfigurationCustomizerTest.java | 121 ++++++++++-------- 3 files changed, 72 insertions(+), 61 deletions(-) diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java index 723d38b..d014b25 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java @@ -30,11 +30,11 @@ String name(); /** - * The name of Spring property to inject the {@link WireMockServer#baseUrl()} + * Names of Spring properties to bind the {@link WireMockServer#baseUrl()} to. * - * @return the name of Spring property to inject the {@link WireMockServer#baseUrl()} + * @return names of Spring properties to bind the {@link WireMockServer#baseUrl()} to. */ - String property() default ""; + String[] property() default ""; /** * The location of WireMock stub files. By default, stubs are resolved from classpath location wiremock-server-name/mappings/. diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java index 94ddcb2..1058097 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java @@ -91,11 +91,11 @@ private void resolveOrCreateWireMockServer(ConfigurableApplicationContext contex }); // configure Spring environment property - if (StringUtils.isNotBlank(options.property())) { - String property = options.property() + "=" + newServer.baseUrl(); + Arrays.stream(options.property()).forEach(propertyName -> { + String property = propertyName + "=" + newServer.baseUrl(); LOGGER.debug("Adding property '{}' to Spring application context", property); TestPropertyValues.of(property).applyTo(context.getEnvironment()); - } + }); } else { LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); } diff --git a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java index 6387041..1bdd2c1 100644 --- a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -1,87 +1,98 @@ package com.maciejwalkowiak.wiremock.spring; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; - +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.core.env.Environment; import org.springframework.test.util.TestSocketUtils; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - @SpringBootTest(classes = WireMockConfigurationCustomizerTest.AppConfiguration.class) @EnableWireMock({ - @ConfigureWireMock( - name = "user-service", - property = "user-service.url", - configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class - ), - @ConfigureWireMock( - name = "todo-service", - property = "todo-service.url", - configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class - ), + @ConfigureWireMock( + name = "user-service", + property = "user-service.url", + configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class + ), + @ConfigureWireMock( + name = "todo-service", + property = {"todo-service.url", "bar-service.url"}, + configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class + ), }) @ExtendWith(OutputCaptureExtension.class) class WireMockConfigurationCustomizerTest { - private static final int USER_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - private static final int TODO_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - static class SampleConfigurationCustomizer implements WireMockConfigurationCustomizer { + private static final int USER_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); + private static final int TODO_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - @Override - public void customize(WireMockConfiguration configuration, ConfigureWireMock options) { - if (options.name().equals("user-service")) { - configuration.port(USER_SERVICE_PORT); - } else { - configuration.port(TODO_SERVICE_PORT); - } - } + static class SampleConfigurationCustomizer implements WireMockConfigurationCustomizer { + + @Override + public void customize(WireMockConfiguration configuration, ConfigureWireMock options) { + if (options.name().equals("user-service")) { + configuration.port(USER_SERVICE_PORT); + } else { + configuration.port(TODO_SERVICE_PORT); + } } + } - @SpringBootApplication - static class AppConfiguration { + @SpringBootApplication + static class AppConfiguration { - } + } - @InjectWireMock("user-service") - private WireMockServer userService; + @InjectWireMock("user-service") + private WireMockServer userService; - @InjectWireMock("todo-service") - private WireMockServer todoService; + @InjectWireMock("todo-service") + private WireMockServer todoService; - @Test - void appliesConfigurationCustomizer() { - assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); - assertThat(todoService.port()).isEqualTo(TODO_SERVICE_PORT); - } + @Test + void appliesProperty(@Autowired Environment environment) { + // TODO: @Maciej is there a programmatic way for accessing the @ConfigureWireMock ? + Stream.of("todo-service.url", "bar-service.url").forEach(property -> + assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + TODO_SERVICE_PORT)); + Stream.of("user-service.url").forEach(property -> + assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + USER_SERVICE_PORT)); + } - @Test - void outputsWireMockLogs(CapturedOutput capturedOutput) throws IOException, InterruptedException { - userService.stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + @Test + void appliesConfigurationCustomizer() { + assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); + assertThat(todoService.port()).isEqualTo(TODO_SERVICE_PORT); + } - HttpClient httpClient = HttpClient.newHttpClient(); - HttpResponse response = httpClient.send( - HttpRequest.newBuilder().GET().uri(URI.create("http://localhost:" + userService.port() + "/test")).build(), - HttpResponse.BodyHandlers.ofString()); - assertThat(response.body()).isEqualTo("Hello World!"); - assertThat(capturedOutput.getAll()) - .as("Must contain debug logging for WireMock") - .contains("Matched response definition:"); - } + @Test + void outputsWireMockLogs(CapturedOutput capturedOutput) throws IOException, InterruptedException { + userService.stubFor(get(urlEqualTo("/test")) + .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + + HttpClient httpClient = HttpClient.newHttpClient(); + HttpResponse response = httpClient.send( + HttpRequest.newBuilder().GET().uri(URI.create("http://localhost:" + userService.port() + "/test")).build(), + HttpResponse.BodyHandlers.ofString()); + assertThat(response.body()).isEqualTo("Hello World!"); + assertThat(capturedOutput.getAll()) + .as("Must contain debug logging for WireMock") + .contains("Matched response definition:"); + } } From 3547884bf499acff510a1fa8484787e70372508f Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Tue, 5 Mar 2024 08:25:30 +0100 Subject: [PATCH 02/12] GH-28: add support for multiple property injection --- .../maciejwalkowiak/wiremock/spring/ConfigureWireMock.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java index d014b25..b26fdc8 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java @@ -30,9 +30,9 @@ String name(); /** - * Names of Spring properties to bind the {@link WireMockServer#baseUrl()} to. + * Names of Spring properties to inject the {@link WireMockServer#baseUrl()}. * - * @return names of Spring properties to bind the {@link WireMockServer#baseUrl()} to. + * @return names of Spring properties to inject the {@link WireMockServer#baseUrl()}. */ String[] property() default ""; From cab84bfb9b82ac73f06cea9c68ae9f51c1974bee Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Tue, 5 Mar 2024 08:56:47 +0100 Subject: [PATCH 03/12] GH-28: add support for multiple property injection --- .../WireMockConfigurationCustomizerTest.java | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java index 1bdd2c1..973e088 100644 --- a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -1,20 +1,17 @@ package com.maciejwalkowiak.wiremock.spring; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; @@ -23,76 +20,79 @@ import org.springframework.core.env.Environment; import org.springframework.test.util.TestSocketUtils; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.assertj.core.api.Assertions.assertThat; + @SpringBootTest(classes = WireMockConfigurationCustomizerTest.AppConfiguration.class) @EnableWireMock({ - @ConfigureWireMock( - name = "user-service", - property = "user-service.url", - configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class - ), - @ConfigureWireMock( - name = "todo-service", - property = {"todo-service.url", "bar-service.url"}, - configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class - ), + @ConfigureWireMock( + name = "user-service", + property = "user-service.url", + configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class + ), + @ConfigureWireMock( + name = "todo-service", + property = {"todo-service.url", "bar-service.url"}, + configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class + ), }) @ExtendWith(OutputCaptureExtension.class) class WireMockConfigurationCustomizerTest { + private static final int USER_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); + private static final int TODO_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - private static final int USER_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - private static final int TODO_SERVICE_PORT = TestSocketUtils.findAvailableTcpPort(); - - static class SampleConfigurationCustomizer implements WireMockConfigurationCustomizer { + static class SampleConfigurationCustomizer implements WireMockConfigurationCustomizer { - @Override - public void customize(WireMockConfiguration configuration, ConfigureWireMock options) { - if (options.name().equals("user-service")) { - configuration.port(USER_SERVICE_PORT); - } else { - configuration.port(TODO_SERVICE_PORT); - } + @Override + public void customize(WireMockConfiguration configuration, ConfigureWireMock options) { + if (options.name().equals("user-service")) { + configuration.port(USER_SERVICE_PORT); + } else { + configuration.port(TODO_SERVICE_PORT); + } + } } - } - @SpringBootApplication - static class AppConfiguration { + @SpringBootApplication + static class AppConfiguration { - } - - @InjectWireMock("user-service") - private WireMockServer userService; + } - @InjectWireMock("todo-service") - private WireMockServer todoService; + @InjectWireMock("user-service") + private WireMockServer userService; - @Test - void appliesProperty(@Autowired Environment environment) { - // TODO: @Maciej is there a programmatic way for accessing the @ConfigureWireMock ? - Stream.of("todo-service.url", "bar-service.url").forEach(property -> - assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + TODO_SERVICE_PORT)); - Stream.of("user-service.url").forEach(property -> - assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + USER_SERVICE_PORT)); - } + @InjectWireMock("todo-service") + private WireMockServer todoService; - @Test - void appliesConfigurationCustomizer() { - assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); - assertThat(todoService.port()).isEqualTo(TODO_SERVICE_PORT); - } + @Test + void appliesProperty(@Autowired Environment environment) { + // TODO: @Maciej is there a programmatic way for accessing the @ConfigureWireMock ? + Stream.of("todo-service.url", "bar-service.url").forEach(property -> + assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + TODO_SERVICE_PORT)); + Stream.of("user-service.url").forEach(property -> + assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + USER_SERVICE_PORT)); + } + @Test + void appliesConfigurationCustomizer() { + assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); + assertThat(todoService.port()).isEqualTo(TODO_SERVICE_PORT); + } - @Test - void outputsWireMockLogs(CapturedOutput capturedOutput) throws IOException, InterruptedException { - userService.stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); + @Test + void outputsWireMockLogs(CapturedOutput capturedOutput) throws IOException, InterruptedException { + userService.stubFor(get(urlEqualTo("/test")) + .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - HttpClient httpClient = HttpClient.newHttpClient(); - HttpResponse response = httpClient.send( - HttpRequest.newBuilder().GET().uri(URI.create("http://localhost:" + userService.port() + "/test")).build(), - HttpResponse.BodyHandlers.ofString()); - assertThat(response.body()).isEqualTo("Hello World!"); - assertThat(capturedOutput.getAll()) - .as("Must contain debug logging for WireMock") - .contains("Matched response definition:"); - } + HttpClient httpClient = HttpClient.newHttpClient(); + HttpResponse response = httpClient.send( + HttpRequest.newBuilder().GET().uri(URI.create("http://localhost:" + userService.port() + "/test")).build(), + HttpResponse.BodyHandlers.ofString()); + assertThat(response.body()).isEqualTo("Hello World!"); + assertThat(capturedOutput.getAll()) + .as("Must contain debug logging for WireMock") + .contains("Matched response definition:"); + } } From f23391cba50d245b8c919a29e3e4df00b0ad8ebe Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Tue, 5 Mar 2024 08:57:30 +0100 Subject: [PATCH 04/12] GH-28: add support for multiple property injection --- .../wiremock/spring/WireMockConfigurationCustomizerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java index 973e088..d1cc53e 100644 --- a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -74,6 +74,7 @@ void appliesProperty(@Autowired Environment environment) { Stream.of("user-service.url").forEach(property -> assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + USER_SERVICE_PORT)); } + @Test void appliesConfigurationCustomizer() { assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); From 08d40436d697de126df12e11eeae596ec830a739 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Tue, 5 Mar 2024 09:46:28 +0100 Subject: [PATCH 05/12] GH-28: add support for multiple property injection --- .../wiremock/spring/WireMockConfigurationCustomizerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java index d1cc53e..8840d1d 100644 --- a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -67,7 +67,7 @@ static class AppConfiguration { private WireMockServer todoService; @Test - void appliesProperty(@Autowired Environment environment) { + void appliesPropertyInjection(@Autowired Environment environment) { // TODO: @Maciej is there a programmatic way for accessing the @ConfigureWireMock ? Stream.of("todo-service.url", "bar-service.url").forEach(property -> assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + TODO_SERVICE_PORT)); From 4a85af06f01e86eabd2ba6388b5f19f9ebdb60d7 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 29 Mar 2024 18:04:03 +0100 Subject: [PATCH 06/12] polish tests --- .../java/app/WireMockSpringExtensionTest.java | 99 ++++++++++++------- .../WireMockConfigurationCustomizerTest.java | 14 +-- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java index 8a11925..3062189 100644 --- a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java +++ b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java @@ -4,6 +4,7 @@ import com.maciejwalkowiak.wiremock.spring.ConfigureWireMock; import com.maciejwalkowiak.wiremock.spring.EnableWireMock; import com.maciejwalkowiak.wiremock.spring.InjectWireMock; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,54 +14,76 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) -@EnableWireMock({ - @ConfigureWireMock(name = "user-service", property = "user-service.url"), - @ConfigureWireMock(name = "todo-service", property = "todo-service.url"), - @ConfigureWireMock(name = "noproperty-service") -}) public class WireMockSpringExtensionTest { - @SpringBootApplication - static class AppConfiguration { + @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) + @EnableWireMock({ + @ConfigureWireMock(name = "user-service", property = "user-service.url"), + @ConfigureWireMock(name = "todo-service", property = "todo-service.url"), + @ConfigureWireMock(name = "noproperty-service") + }) + @Nested + class SinglePropertyBindingTest { - } + @InjectWireMock("todo-service") + private WireMockServer todoWireMockServer; - @InjectWireMock("todo-service") - private WireMockServer todoWireMockServer; + @Autowired + private Environment environment; - @Autowired - private Environment environment; + @Test + void createsWiremockWithClassLevelConfigureWiremock(@InjectWireMock("user-service") WireMockServer wireMockServer) { + assertWireMockServer(wireMockServer, "user-service.url"); + } - @Test - void createsWiremockWithClassLevelConfigureWiremock(@InjectWireMock("user-service") WireMockServer wireMockServer) { - assertWireMockServer(wireMockServer, "user-service.url"); - } + @Test + void createsWiremockWithFieldLevelConfigureWiremock() { + assertWireMockServer(todoWireMockServer, "todo-service.url"); + } + + @Test + void doesNotSetPropertyWhenNotProvided(@InjectWireMock("noproperty-service") WireMockServer wireMockServer) { + assertThat(wireMockServer) + .as("inject wiremock sets null when not configured") + .isNotNull(); + } - @Test - void createsWiremockWithFieldLevelConfigureWiremock() { - assertWireMockServer(todoWireMockServer, "todo-service.url"); + private void assertWireMockServer(WireMockServer wireMockServer, String property) { + assertThat(wireMockServer) + .as("creates WireMock instance") + .isNotNull(); + assertThat(wireMockServer.baseUrl()) + .as("WireMock baseUrl is set") + .isNotNull(); + assertThat(wireMockServer.port()) + .as("sets random port") + .isNotZero(); + assertThat(environment.getProperty(property)) + .as("sets Spring property") + .isEqualTo(wireMockServer.baseUrl()); + } } - @Test - void doesNotSetPropertyWhenNotProvided(@InjectWireMock("noproperty-service") WireMockServer wireMockServer) { - assertThat(wireMockServer) - .as("creates WireMock instance") - .isNotNull(); + @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) + @EnableWireMock(@ConfigureWireMock(name = "user-service", property = {"user-service.url", "todo-service.url"})) + @Nested + class MultiplePropertiesBindingTest { + + @InjectWireMock("user-service") + private WireMockServer userServiceWireMockServer; + + @Autowired + private Environment environment; + + @Test + void bindsUrlToMultipleProperties() { + assertThat(environment.getProperty("user-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); + assertThat(environment.getProperty("todo-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); + } } - private void assertWireMockServer(WireMockServer wireMockServer, String property) { - assertThat(wireMockServer) - .as("creates WireMock instance") - .isNotNull(); - assertThat(wireMockServer.baseUrl()) - .as("WireMock baseUrl is set") - .isNotNull(); - assertThat(wireMockServer.port()) - .as("sets random port") - .isNotZero(); - assertThat(environment.getProperty(property)) - .as("sets Spring property") - .isEqualTo(wireMockServer.baseUrl()); + @SpringBootApplication + static class AppConfiguration { + } } diff --git a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java index 8840d1d..6387041 100644 --- a/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -8,16 +8,13 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.core.env.Environment; import org.springframework.test.util.TestSocketUtils; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; @@ -34,7 +31,7 @@ ), @ConfigureWireMock( name = "todo-service", - property = {"todo-service.url", "bar-service.url"}, + property = "todo-service.url", configurationCustomizers = WireMockConfigurationCustomizerTest.SampleConfigurationCustomizer.class ), }) @@ -66,15 +63,6 @@ static class AppConfiguration { @InjectWireMock("todo-service") private WireMockServer todoService; - @Test - void appliesPropertyInjection(@Autowired Environment environment) { - // TODO: @Maciej is there a programmatic way for accessing the @ConfigureWireMock ? - Stream.of("todo-service.url", "bar-service.url").forEach(property -> - assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + TODO_SERVICE_PORT)); - Stream.of("user-service.url").forEach(property -> - assertThat(environment.getProperty(property)).isEqualTo("http://localhost:" + USER_SERVICE_PORT)); - } - @Test void appliesConfigurationCustomizer() { assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); From 730f3cf9b831dc9aaeac6efad701d966f2d82924 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Mon, 1 Apr 2024 17:12:26 +0200 Subject: [PATCH 07/12] GH-28: add support for multiple property injection --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/README.md b/README.md index ed7a927..ad00be5 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,58 @@ WireMock extensions can be registered independently with each `@ConfigureWireMoc @ConfigureWireMock(name = "...", property = "...", extensions = { ... }) ``` +### Single vs Multiple Property Injection + +The concept of single property injection can be described as wiring _one_ `WireMockServer` to _one_ property. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "foo-service", property = "app.client-apis.foo.base-path"}), + @ConfigureWireMock(name = "bar-service", property = "app.client-apis.bar.base-path"}), + @ConfigureWireMock(name = "mojo-service", property = "app.client-apis.mojo.base-path"}) +}) +class AppIT { + @InjectWireMock("foo-service") + private WireMockServer fooService; + @InjectWireMock("bar-service") + private WireMockServer barService; + @InjectWireMock("mojo-service") + private WireMockServer mojoService; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The concept of multiple property injection can be described as wiring _one_ `WireMockServer` to _multiple_ properties. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "services", property = { + "app.client-apis.foo.base-path", + "app.client-apis.bar.base-path", + "app.client-apis.mojo.base-path"}) +}) +class AppIT { + + @InjectWireMock("services") + private WireMockServer services; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The *single* property injection provides a high level of isolation when mocking and stubbing 3rd pary RESTful api, because every service +is associated to its own dedicated `WireMockServer` instance. +The *multiple* property injections provides a less complex test setup at the cost of isolation. + ### Customizing mappings directory By default, each `WireMockServer` is configured to load mapping files from a classpath directory `wiremock/{server-name}/mappings`. From bf35f1a49f160a3de48ec4966e1a6488ff512ab2 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Mon, 1 Apr 2024 17:59:12 +0200 Subject: [PATCH 08/12] GH-28: add support for multiple property injection --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ad00be5..4e9b3e8 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,9 @@ class AppIT { private WireMockServer mojoService; @Test - void contextLoads() { - // your test code - } + void contextLoads() { + // your test code + } } ``` @@ -101,10 +101,10 @@ class AppIT { @InjectWireMock("services") private WireMockServer services; - @Test - void contextLoads() { - // your test code - } + @Test + void contextLoads() { + // your test code + } } ``` From d9fc958a56b27c67c9545c9c4e3fd64117a39fc7 Mon Sep 17 00:00:00 2001 From: rfelgent Date: Tue, 2 Apr 2024 06:45:49 +0200 Subject: [PATCH 09/12] GH-28: add support for multiple property injection (updated README.md) (#31) * GH-28: add support for multiple property injection * GH-28: add support for multiple property injection --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/README.md b/README.md index ed7a927..4e9b3e8 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,58 @@ WireMock extensions can be registered independently with each `@ConfigureWireMoc @ConfigureWireMock(name = "...", property = "...", extensions = { ... }) ``` +### Single vs Multiple Property Injection + +The concept of single property injection can be described as wiring _one_ `WireMockServer` to _one_ property. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "foo-service", property = "app.client-apis.foo.base-path"}), + @ConfigureWireMock(name = "bar-service", property = "app.client-apis.bar.base-path"}), + @ConfigureWireMock(name = "mojo-service", property = "app.client-apis.mojo.base-path"}) +}) +class AppIT { + @InjectWireMock("foo-service") + private WireMockServer fooService; + @InjectWireMock("bar-service") + private WireMockServer barService; + @InjectWireMock("mojo-service") + private WireMockServer mojoService; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The concept of multiple property injection can be described as wiring _one_ `WireMockServer` to _multiple_ properties. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "services", property = { + "app.client-apis.foo.base-path", + "app.client-apis.bar.base-path", + "app.client-apis.mojo.base-path"}) +}) +class AppIT { + + @InjectWireMock("services") + private WireMockServer services; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The *single* property injection provides a high level of isolation when mocking and stubbing 3rd pary RESTful api, because every service +is associated to its own dedicated `WireMockServer` instance. +The *multiple* property injections provides a less complex test setup at the cost of isolation. + ### Customizing mappings directory By default, each `WireMockServer` is configured to load mapping files from a classpath directory `wiremock/{server-name}/mappings`. From 4fff07c2f0cae6b283c7b2cb926f21ab985cd1de Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Thu, 4 Apr 2024 10:18:50 +0200 Subject: [PATCH 10/12] GH-28: attribute "property" and "properties" co-exist for soft migration --- README.md | 6 +- .../wiremock/spring/ConfigureWireMock.java | 12 +- .../spring/WireMockContextCustomizer.java | 236 +++++++++--------- .../java/app/WireMockSpringExtensionTest.java | 16 +- 4 files changed, 148 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index 4e9b3e8..36d7c52 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ WireMock extensions can be registered independently with each `@ConfigureWireMoc ### Single vs Multiple Property Injection -The concept of single property injection can be described as wiring _one_ `WireMockServer` to _one_ property. +The concept of single property injection can be described as wiring _one_ `WireMockServer` instance to _one_ property. ```java @SpringBootTest @@ -86,12 +86,12 @@ class AppIT { } ``` -The concept of multiple property injection can be described as wiring _one_ `WireMockServer` to _multiple_ properties. +The concept of multiple property injection can be described as wiring _one_ `WireMockServer` instance to _multiple_ properties. ```java @SpringBootTest @EnableWireMock({ - @ConfigureWireMock(name = "services", property = { + @ConfigureWireMock(name = "services", properties = { "app.client-apis.foo.base-path", "app.client-apis.bar.base-path", "app.client-apis.mojo.base-path"}) diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java index b26fdc8..4a22b02 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java @@ -29,13 +29,21 @@ */ String name(); + /** + * The name of Spring property to inject the {@link WireMockServer#baseUrl()} + * + * @deprecated please use {@link ConfigureWireMock#properties()} + * @return the name of Spring property to inject the {@link WireMockServer#baseUrl()} + */ + @Deprecated(since = "2.1.3") + String property() default ""; + /** * Names of Spring properties to inject the {@link WireMockServer#baseUrl()}. * * @return names of Spring properties to inject the {@link WireMockServer#baseUrl()}. */ - String[] property() default ""; - + String[] properties() default {}; /** * The location of WireMock stub files. By default, stubs are resolved from classpath location wiremock-server-name/mappings/. * diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java index 1058097..78f792a 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java @@ -1,17 +1,18 @@ package com.maciejwalkowiak.wiremock.spring; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; @@ -19,147 +20,156 @@ import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - /** * Attaches properties with urls pointing to {@link WireMockServer} instances to the Spring {@link Environment}. * * @author Maciej Walkowiak */ public class WireMockContextCustomizer implements ContextCustomizer { - private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class); - - private final List configuration; - - /** - * Creates an instance of {@link WireMockContextCustomizer}. - * - * @param configurations the configurations - */ - public WireMockContextCustomizer(List configurations) { - this.configuration = configurations; - } - /** - * Creates an instance of {@link WireMockContextCustomizer}. - * - * @param configurations the configurations - */ - public WireMockContextCustomizer(ConfigureWireMock[] configurations) { - this(Arrays.asList(configurations)); - } - - @Override - public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { - for (ConfigureWireMock configureWiremock : configuration) { - resolveOrCreateWireMockServer(context, configureWiremock); - } + private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class); + + private final List configuration; + + /** + * Creates an instance of {@link WireMockContextCustomizer}. + * + * @param configurations the configurations + */ + public WireMockContextCustomizer(List configurations) { + this.configuration = configurations; + } + + /** + * Creates an instance of {@link WireMockContextCustomizer}. + * + * @param configurations the configurations + */ + public WireMockContextCustomizer(ConfigureWireMock[] configurations) { + this(Arrays.asList(configurations)); + } + + @Override + public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { + for (ConfigureWireMock configureWiremock : configuration) { + resolveOrCreateWireMockServer(context, configureWiremock); } + } - private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) { - WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name()); + private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) { + WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name()); - if (wireMockServer == null) { - // create & start wiremock server - WireMockConfiguration serverOptions = options() - .usingFilesUnderClasspath(resolveStubLocation(options)) - .port(options.port()) - .notifier(new Slf4jNotifier(true)); + if (wireMockServer == null) { + // create & start wiremock server + WireMockConfiguration serverOptions = options() + .usingFilesUnderClasspath(resolveStubLocation(options)) + .port(options.port()) + .notifier(new Slf4jNotifier(true)); - if (options.extensions().length > 0) { - serverOptions.extensions(options.extensions()); - } + if (options.extensions().length > 0) { + serverOptions.extensions(options.extensions()); + } - applyCustomizers(options, serverOptions); + applyCustomizers(options, serverOptions); - LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber()); + LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber()); - WireMockServer newServer = new WireMockServer(serverOptions); - newServer.start(); + WireMockServer newServer = new WireMockServer(serverOptions); + newServer.start(); - LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl()); + LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl()); - // save server to store - Store.INSTANCE.store(context, options.name(), newServer); + // save server to store + Store.INSTANCE.store(context, options.name(), newServer); - // add shutdown hook - context.addApplicationListener(event -> { - if (event instanceof ContextClosedEvent) { - LOGGER.info("Stopping WireMockServer with name '{}'", options.name()); - newServer.stop(); - } - }); - - // configure Spring environment property - Arrays.stream(options.property()).forEach(propertyName -> { - String property = propertyName + "=" + newServer.baseUrl(); - LOGGER.debug("Adding property '{}' to Spring application context", property); - TestPropertyValues.of(property).applyTo(context.getEnvironment()); - }); - } else { - LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); + // add shutdown hook + context.addApplicationListener(event -> { + if (event instanceof ContextClosedEvent) { + LOGGER.info("Stopping WireMockServer with name '{}'", options.name()); + newServer.stop(); } + }); + + // configure Spring environment property + List propertyNames; + if (StringUtils.isNotBlank(options.property())) { + propertyNames = List.of(options.property()); + } else { + propertyNames = Arrays.asList(options.properties()).stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + } + propertyNames.forEach(propertyName -> { + String property = propertyName + "=" + newServer.baseUrl(); + LOGGER.debug("Adding property '{}' to Spring application context", property); + TestPropertyValues.of(property).applyTo(context.getEnvironment()); + }); + } else { + LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); } - - private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) { - for (Class customizer : options.configurationCustomizers()) { - try { - ReflectionUtils.newInstance(customizer).customize(serverOptions, options); - } catch (Exception e) { - if (e instanceof NoSuchMethodException) { - LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e); - } - throw e; - } + } + + private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) { + for (Class customizer : options.configurationCustomizers()) { + try { + ReflectionUtils.newInstance(customizer).customize(serverOptions, options); + } catch (Exception e) { + if (e instanceof NoSuchMethodException) { + LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e); } + throw e; + } } + } - private String resolveStubLocation(ConfigureWireMock options) { - return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation(); - } + private String resolveStubLocation(ConfigureWireMock options) { + return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation(); + } - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - WireMockContextCustomizer that = (WireMockContextCustomizer) o; - return Objects.equals(configuration, that.configuration); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public int hashCode() { - return Objects.hash(configuration); + if (o == null || getClass() != o.getClass()) { + return false; } + WireMockContextCustomizer that = (WireMockContextCustomizer) o; + return Objects.equals(configuration, that.configuration); + } - // ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223 - static class Slf4jNotifier implements Notifier { + @Override + public int hashCode() { + return Objects.hash(configuration); + } - private static final Logger log = LoggerFactory.getLogger("WireMock"); + // ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223 + static class Slf4jNotifier implements Notifier { - private final boolean verbose; + private static final Logger log = LoggerFactory.getLogger("WireMock"); - Slf4jNotifier(boolean verbose) { - this.verbose = verbose; - } + private final boolean verbose; - @Override - public void info(String message) { - if (verbose) { - log.info(message); - } - } + Slf4jNotifier(boolean verbose) { + this.verbose = verbose; + } - @Override - public void error(String message) { - log.error(message); - } + @Override + public void info(String message) { + if (verbose) { + log.info(message); + } + } - @Override - public void error(String message, Throwable t) { - log.error(message, t); - } + @Override + public void error(String message) { + log.error(message); + } + @Override + public void error(String message, Throwable t) { + log.error(message, t); } + + } } diff --git a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java index 3062189..7aba3d0 100644 --- a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java +++ b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java @@ -1,19 +1,18 @@ package app; +import static org.assertj.core.api.Assertions.assertThat; + import com.github.tomakehurst.wiremock.WireMockServer; import com.maciejwalkowiak.wiremock.spring.ConfigureWireMock; import com.maciejwalkowiak.wiremock.spring.EnableWireMock; import com.maciejwalkowiak.wiremock.spring.InjectWireMock; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.env.Environment; -import static org.assertj.core.api.Assertions.assertThat; - public class WireMockSpringExtensionTest { @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) @@ -65,13 +64,19 @@ private void assertWireMockServer(WireMockServer wireMockServer, String property } @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) - @EnableWireMock(@ConfigureWireMock(name = "user-service", property = {"user-service.url", "todo-service.url"})) + @EnableWireMock({ + @ConfigureWireMock(name = "user-service", properties = {"user-service.url", "todo-service.url"}), + @ConfigureWireMock(name = "mojo-service", property = "mojo-service.url", properties = {"other-service.url"}) + }) @Nested class MultiplePropertiesBindingTest { @InjectWireMock("user-service") private WireMockServer userServiceWireMockServer; + @InjectWireMock("mojo-service") + private WireMockServer mojoServiceWireMockServer; + @Autowired private Environment environment; @@ -79,6 +84,9 @@ class MultiplePropertiesBindingTest { void bindsUrlToMultipleProperties() { assertThat(environment.getProperty("user-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); assertThat(environment.getProperty("todo-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); + // single property binding takes precedence over multiple properties binding + assertThat(environment.getProperty("mojo-service.url")).isEqualTo(mojoServiceWireMockServer.baseUrl()); + assertThat(environment.getProperty("other-service.url")).isNull(); } } From deba20374640aba7c3c149099b190a679a2b43f1 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Thu, 4 Apr 2024 10:25:47 +0200 Subject: [PATCH 11/12] GH-28: attribute "property" and "properties" co-exist for soft migration --- .../spring/WireMockContextCustomizer.java | 255 +++++++++--------- 1 file changed, 127 insertions(+), 128 deletions(-) diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java index 78f792a..e7e62be 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java @@ -1,18 +1,18 @@ package com.maciejwalkowiak.wiremock.spring; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; @@ -20,156 +20,155 @@ import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + /** * Attaches properties with urls pointing to {@link WireMockServer} instances to the Spring {@link Environment}. * * @author Maciej Walkowiak */ public class WireMockContextCustomizer implements ContextCustomizer { + private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class); - private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class); - - private final List configuration; - - /** - * Creates an instance of {@link WireMockContextCustomizer}. - * - * @param configurations the configurations - */ - public WireMockContextCustomizer(List configurations) { - this.configuration = configurations; - } - - /** - * Creates an instance of {@link WireMockContextCustomizer}. - * - * @param configurations the configurations - */ - public WireMockContextCustomizer(ConfigureWireMock[] configurations) { - this(Arrays.asList(configurations)); - } - - @Override - public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { - for (ConfigureWireMock configureWiremock : configuration) { - resolveOrCreateWireMockServer(context, configureWiremock); - } - } - - private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) { - WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name()); - - if (wireMockServer == null) { - // create & start wiremock server - WireMockConfiguration serverOptions = options() - .usingFilesUnderClasspath(resolveStubLocation(options)) - .port(options.port()) - .notifier(new Slf4jNotifier(true)); - - if (options.extensions().length > 0) { - serverOptions.extensions(options.extensions()); - } - - applyCustomizers(options, serverOptions); + private final List configuration; - LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber()); - - WireMockServer newServer = new WireMockServer(serverOptions); - newServer.start(); + /** + * Creates an instance of {@link WireMockContextCustomizer}. + * + * @param configurations the configurations + */ + public WireMockContextCustomizer(List configurations) { + this.configuration = configurations; + } - LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl()); + /** + * Creates an instance of {@link WireMockContextCustomizer}. + * + * @param configurations the configurations + */ + public WireMockContextCustomizer(ConfigureWireMock[] configurations) { + this(Arrays.asList(configurations)); + } - // save server to store - Store.INSTANCE.store(context, options.name(), newServer); + @Override + public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { + for (ConfigureWireMock configureWiremock : configuration) { + resolveOrCreateWireMockServer(context, configureWiremock); + } + } - // add shutdown hook - context.addApplicationListener(event -> { - if (event instanceof ContextClosedEvent) { - LOGGER.info("Stopping WireMockServer with name '{}'", options.name()); - newServer.stop(); + private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) { + WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name()); + + if (wireMockServer == null) { + // create & start wiremock server + WireMockConfiguration serverOptions = options() + .usingFilesUnderClasspath(resolveStubLocation(options)) + .port(options.port()) + .notifier(new Slf4jNotifier(true)); + + if (options.extensions().length > 0) { + serverOptions.extensions(options.extensions()); + } + + applyCustomizers(options, serverOptions); + + LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber()); + + WireMockServer newServer = new WireMockServer(serverOptions); + newServer.start(); + + LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl()); + + // save server to store + Store.INSTANCE.store(context, options.name(), newServer); + + // add shutdown hook + context.addApplicationListener(event -> { + if (event instanceof ContextClosedEvent) { + LOGGER.info("Stopping WireMockServer with name '{}'", options.name()); + newServer.stop(); + } + }); + + // configure Spring environment property + List propertyNames; + if (StringUtils.isNotBlank(options.property())) { + propertyNames = List.of(options.property()); + } else { + propertyNames = Arrays.stream(options.properties()) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + } + propertyNames.forEach(propertyName -> { + String property = propertyName + "=" + newServer.baseUrl(); + LOGGER.debug("Adding property '{}' to Spring application context", property); + TestPropertyValues.of(property).applyTo(context.getEnvironment()); + }); + } else { + LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); } - }); - - // configure Spring environment property - List propertyNames; - if (StringUtils.isNotBlank(options.property())) { - propertyNames = List.of(options.property()); - } else { - propertyNames = Arrays.asList(options.properties()).stream() - .filter(StringUtils::isNotBlank) - .collect(Collectors.toList()); - } - propertyNames.forEach(propertyName -> { - String property = propertyName + "=" + newServer.baseUrl(); - LOGGER.debug("Adding property '{}' to Spring application context", property); - TestPropertyValues.of(property).applyTo(context.getEnvironment()); - }); - } else { - LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); } - } - - private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) { - for (Class customizer : options.configurationCustomizers()) { - try { - ReflectionUtils.newInstance(customizer).customize(serverOptions, options); - } catch (Exception e) { - if (e instanceof NoSuchMethodException) { - LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e); + + private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) { + for (Class customizer : options.configurationCustomizers()) { + try { + ReflectionUtils.newInstance(customizer).customize(serverOptions, options); + } catch (Exception e) { + if (e instanceof NoSuchMethodException) { + LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e); + } + throw e; + } } - throw e; - } } - } - private String resolveStubLocation(ConfigureWireMock options) { - return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation(); - } + private String resolveStubLocation(ConfigureWireMock options) { + return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation(); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + WireMockContextCustomizer that = (WireMockContextCustomizer) o; + return Objects.equals(configuration, that.configuration); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public int hashCode() { + return Objects.hash(configuration); } - WireMockContextCustomizer that = (WireMockContextCustomizer) o; - return Objects.equals(configuration, that.configuration); - } - @Override - public int hashCode() { - return Objects.hash(configuration); - } + // ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223 + static class Slf4jNotifier implements Notifier { - // ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223 - static class Slf4jNotifier implements Notifier { + private static final Logger log = LoggerFactory.getLogger("WireMock"); - private static final Logger log = LoggerFactory.getLogger("WireMock"); + private final boolean verbose; - private final boolean verbose; + Slf4jNotifier(boolean verbose) { + this.verbose = verbose; + } - Slf4jNotifier(boolean verbose) { - this.verbose = verbose; - } + @Override + public void info(String message) { + if (verbose) { + log.info(message); + } + } - @Override - public void info(String message) { - if (verbose) { - log.info(message); - } - } + @Override + public void error(String message) { + log.error(message); + } - @Override - public void error(String message) { - log.error(message); - } + @Override + public void error(String message, Throwable t) { + log.error(message, t); + } - @Override - public void error(String message, Throwable t) { - log.error(message, t); } - - } } From 5e07b3fe7f275830be1ebd4dba1d22745b7237f5 Mon Sep 17 00:00:00 2001 From: felgentraeger Date: Thu, 4 Apr 2024 10:29:18 +0200 Subject: [PATCH 12/12] GH-28: attribute "property" and "properties" co-exist for soft migration --- .../src/test/java/app/WireMockSpringExtensionTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java index 7aba3d0..0a13647 100644 --- a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java +++ b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java @@ -1,18 +1,19 @@ package app; -import static org.assertj.core.api.Assertions.assertThat; - import com.github.tomakehurst.wiremock.WireMockServer; import com.maciejwalkowiak.wiremock.spring.ConfigureWireMock; import com.maciejwalkowiak.wiremock.spring.EnableWireMock; import com.maciejwalkowiak.wiremock.spring.InjectWireMock; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.env.Environment; +import static org.assertj.core.api.Assertions.assertThat; + public class WireMockSpringExtensionTest { @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) @@ -65,8 +66,8 @@ private void assertWireMockServer(WireMockServer wireMockServer, String property @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) @EnableWireMock({ - @ConfigureWireMock(name = "user-service", properties = {"user-service.url", "todo-service.url"}), - @ConfigureWireMock(name = "mojo-service", property = "mojo-service.url", properties = {"other-service.url"}) + @ConfigureWireMock(name = "user-service", properties = {"user-service.url", "todo-service.url"}), + @ConfigureWireMock(name = "mojo-service", property = "mojo-service.url", properties = {"other-service.url"}) }) @Nested class MultiplePropertiesBindingTest {