From 54d0191fdb8d2c576f3b42cd7145ef3eeef25705 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Sun, 29 Oct 2023 21:19:32 +0100 Subject: [PATCH] Add option to customize configuration on `@ConfigureWireMock` annotation (#18) Fixes #16 --- README.md | 27 +++++++++ .../wiremock/spring/ConfigureWireMock.java | 8 +++ .../WireMockConfigurationCustomizer.java | 12 ++++ .../spring/WireMockContextCustomizer.java | 20 ++++++- .../WireMockConfigurationCustomizerTest.java | 59 +++++++++++++++++++ 5 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizer.java create mode 100644 wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java diff --git a/README.md b/README.md index 59dd02b..565cb3e 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,33 @@ It can be changed with setting `stubLocation` on `@ConfigureWireMock`: @ConfigureWireMock(name = "...", property = "...", stubLocation = "my-stubs") ``` +### Advanced configuration + +More advanced configuration can be applied through configuration customizers: + +```java +@ConfigureWireMock( + name = "todo-service", + property = "todo-service.url", + configurationCustomizers = SampleConfigurationCustomizer.class +) +``` + +Where `SampleConfigurationCustomizer` is a class implementing `WireMockConfigurationCustomizer`: + +```java +class SampleConfigurationCustomizer implements WireMockConfigurationCustomizer { + + @Override + public void customize(WireMockConfiguration configuration, ConfigureWireMock options) { + // apply changes to configuration + } +} +``` + +> [!IMPORTANT] +> `WireMockConfigurationCustomizer` must have a no-arg constructor. + Sounds good? Consider [❤️ Sponsoring](https://github.com/sponsors/maciejwalkowiak) the project! Thank you! ## 🙏 Credits 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 4d5c7bc..723d38b 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 @@ -4,6 +4,7 @@ import java.lang.annotation.RetentionPolicy; import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.extension.Extension; /** @@ -50,4 +51,11 @@ * @return the extensions */ Class[] extensions() default {}; + + /** + * Customizes {@link WireMockConfiguration} used by {@link WireMockServer} instance. Customizers are ordered by their natural order in this array. Each customizer must have no-arg constructor. + * + * @return the configuration customizers classes + */ + Class[] configurationCustomizers() default {}; } diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizer.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizer.java new file mode 100644 index 0000000..6483552 --- /dev/null +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizer.java @@ -0,0 +1,12 @@ +package com.maciejwalkowiak.wiremock.spring; + +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; + +/** + * Customizes {@link WireMockConfiguration} programmatically. Can be registered with {@link ConfigureWireMock#configurationCustomizers()}. + * Customizer must have public no-arg constructor. + */ +public interface WireMockConfigurationCustomizer { + + void customize(WireMockConfiguration configuration, ConfigureWireMock options); +} 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 33e480e..1fc0c60 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 @@ -6,6 +6,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,8 +57,6 @@ public void customizeContext(ConfigurableApplicationContext context, MergedConte } private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) { - LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), options.port()); - WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name()); if (wireMockServer == null) { @@ -70,6 +69,10 @@ private void resolveOrCreateWireMockServer(ConfigurableApplicationContext contex 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(); @@ -95,6 +98,19 @@ private void resolveOrCreateWireMockServer(ConfigurableApplicationContext contex } } + 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(); } 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 new file mode 100644 index 0000000..0e1808a --- /dev/null +++ b/wiremock-spring-boot/src/test/java/com/maciejwalkowiak/wiremock/spring/WireMockConfigurationCustomizerTest.java @@ -0,0 +1,59 @@ +package com.maciejwalkowiak.wiremock.spring; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.util.TestSocketUtils; + +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 + ), +}) +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 { + + @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 { + + } + + @InjectWireMock("user-service") + private WireMockServer userService; + + @InjectWireMock("todo-service") + private WireMockServer todoService; + + @Test + void appliesConfigurationCustomizer() { + assertThat(userService.port()).isEqualTo(USER_SERVICE_PORT); + assertThat(todoService.port()).isEqualTo(TODO_SERVICE_PORT); + } + +}