Skip to content

Commit 4fff07c

Browse files
committed
GH-28: attribute "property" and "properties" co-exist for soft migration
1 parent 5a0ae9b commit 4fff07c

File tree

4 files changed

+148
-122
lines changed

4 files changed

+148
-122
lines changed

Diff for: README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ WireMock extensions can be registered independently with each `@ConfigureWireMoc
6262

6363
### Single vs Multiple Property Injection
6464

65-
The concept of single property injection can be described as wiring _one_ `WireMockServer` to _one_ property.
65+
The concept of single property injection can be described as wiring _one_ `WireMockServer` instance to _one_ property.
6666

6767
```java
6868
@SpringBootTest
@@ -86,12 +86,12 @@ class AppIT {
8686
}
8787
```
8888

89-
The concept of multiple property injection can be described as wiring _one_ `WireMockServer` to _multiple_ properties.
89+
The concept of multiple property injection can be described as wiring _one_ `WireMockServer` instance to _multiple_ properties.
9090

9191
```java
9292
@SpringBootTest
9393
@EnableWireMock({
94-
@ConfigureWireMock(name = "services", property = {
94+
@ConfigureWireMock(name = "services", properties = {
9595
"app.client-apis.foo.base-path",
9696
"app.client-apis.bar.base-path",
9797
"app.client-apis.mojo.base-path"})

Diff for: wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,21 @@
2929
*/
3030
String name();
3131

32+
/**
33+
* The name of Spring property to inject the {@link WireMockServer#baseUrl()}
34+
*
35+
* @deprecated please use {@link ConfigureWireMock#properties()}
36+
* @return the name of Spring property to inject the {@link WireMockServer#baseUrl()}
37+
*/
38+
@Deprecated(since = "2.1.3")
39+
String property() default "";
40+
3241
/**
3342
* Names of Spring properties to inject the {@link WireMockServer#baseUrl()}.
3443
*
3544
* @return names of Spring properties to inject the {@link WireMockServer#baseUrl()}.
3645
*/
37-
String[] property() default "";
38-
46+
String[] properties() default {};
3947
/**
4048
* The location of WireMock stub files. By default, stubs are resolved from classpath location <code>wiremock-server-name/mappings/</code>.
4149
*
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,175 @@
11
package com.maciejwalkowiak.wiremock.spring;
22

3-
import java.util.Arrays;
4-
import java.util.List;
5-
import java.util.Objects;
3+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
64

75
import com.github.tomakehurst.wiremock.WireMockServer;
86
import com.github.tomakehurst.wiremock.common.Notifier;
97
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.Objects;
11+
import java.util.stream.Collectors;
1012
import org.junit.platform.commons.util.ReflectionUtils;
1113
import org.junit.platform.commons.util.StringUtils;
1214
import org.slf4j.Logger;
1315
import org.slf4j.LoggerFactory;
14-
1516
import org.springframework.boot.test.util.TestPropertyValues;
1617
import org.springframework.context.ConfigurableApplicationContext;
1718
import org.springframework.context.event.ContextClosedEvent;
1819
import org.springframework.core.env.Environment;
1920
import org.springframework.test.context.ContextCustomizer;
2021
import org.springframework.test.context.MergedContextConfiguration;
2122

22-
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
23-
2423
/**
2524
* Attaches properties with urls pointing to {@link WireMockServer} instances to the Spring {@link Environment}.
2625
*
2726
* @author Maciej Walkowiak
2827
*/
2928
public class WireMockContextCustomizer implements ContextCustomizer {
30-
private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class);
31-
32-
private final List<ConfigureWireMock> configuration;
33-
34-
/**
35-
* Creates an instance of {@link WireMockContextCustomizer}.
36-
*
37-
* @param configurations the configurations
38-
*/
39-
public WireMockContextCustomizer(List<ConfigureWireMock> configurations) {
40-
this.configuration = configurations;
41-
}
4229

43-
/**
44-
* Creates an instance of {@link WireMockContextCustomizer}.
45-
*
46-
* @param configurations the configurations
47-
*/
48-
public WireMockContextCustomizer(ConfigureWireMock[] configurations) {
49-
this(Arrays.asList(configurations));
50-
}
51-
52-
@Override
53-
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
54-
for (ConfigureWireMock configureWiremock : configuration) {
55-
resolveOrCreateWireMockServer(context, configureWiremock);
56-
}
30+
private static final Logger LOGGER = LoggerFactory.getLogger(WireMockContextCustomizer.class);
31+
32+
private final List<ConfigureWireMock> configuration;
33+
34+
/**
35+
* Creates an instance of {@link WireMockContextCustomizer}.
36+
*
37+
* @param configurations the configurations
38+
*/
39+
public WireMockContextCustomizer(List<ConfigureWireMock> configurations) {
40+
this.configuration = configurations;
41+
}
42+
43+
/**
44+
* Creates an instance of {@link WireMockContextCustomizer}.
45+
*
46+
* @param configurations the configurations
47+
*/
48+
public WireMockContextCustomizer(ConfigureWireMock[] configurations) {
49+
this(Arrays.asList(configurations));
50+
}
51+
52+
@Override
53+
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
54+
for (ConfigureWireMock configureWiremock : configuration) {
55+
resolveOrCreateWireMockServer(context, configureWiremock);
5756
}
57+
}
5858

59-
private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) {
60-
WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name());
59+
private void resolveOrCreateWireMockServer(ConfigurableApplicationContext context, ConfigureWireMock options) {
60+
WireMockServer wireMockServer = Store.INSTANCE.findWireMockInstance(context, options.name());
6161

62-
if (wireMockServer == null) {
63-
// create & start wiremock server
64-
WireMockConfiguration serverOptions = options()
65-
.usingFilesUnderClasspath(resolveStubLocation(options))
66-
.port(options.port())
67-
.notifier(new Slf4jNotifier(true));
62+
if (wireMockServer == null) {
63+
// create & start wiremock server
64+
WireMockConfiguration serverOptions = options()
65+
.usingFilesUnderClasspath(resolveStubLocation(options))
66+
.port(options.port())
67+
.notifier(new Slf4jNotifier(true));
6868

69-
if (options.extensions().length > 0) {
70-
serverOptions.extensions(options.extensions());
71-
}
69+
if (options.extensions().length > 0) {
70+
serverOptions.extensions(options.extensions());
71+
}
7272

73-
applyCustomizers(options, serverOptions);
73+
applyCustomizers(options, serverOptions);
7474

75-
LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber());
75+
LOGGER.info("Configuring WireMockServer with name '{}' on port: {}", options.name(), serverOptions.portNumber());
7676

77-
WireMockServer newServer = new WireMockServer(serverOptions);
78-
newServer.start();
77+
WireMockServer newServer = new WireMockServer(serverOptions);
78+
newServer.start();
7979

80-
LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl());
80+
LOGGER.info("Started WireMockServer with name '{}':{}", options.name(), newServer.baseUrl());
8181

82-
// save server to store
83-
Store.INSTANCE.store(context, options.name(), newServer);
82+
// save server to store
83+
Store.INSTANCE.store(context, options.name(), newServer);
8484

85-
// add shutdown hook
86-
context.addApplicationListener(event -> {
87-
if (event instanceof ContextClosedEvent) {
88-
LOGGER.info("Stopping WireMockServer with name '{}'", options.name());
89-
newServer.stop();
90-
}
91-
});
92-
93-
// configure Spring environment property
94-
Arrays.stream(options.property()).forEach(propertyName -> {
95-
String property = propertyName + "=" + newServer.baseUrl();
96-
LOGGER.debug("Adding property '{}' to Spring application context", property);
97-
TestPropertyValues.of(property).applyTo(context.getEnvironment());
98-
});
99-
} else {
100-
LOGGER.info("WireMockServer with name '{}' is already configured", options.name());
85+
// add shutdown hook
86+
context.addApplicationListener(event -> {
87+
if (event instanceof ContextClosedEvent) {
88+
LOGGER.info("Stopping WireMockServer with name '{}'", options.name());
89+
newServer.stop();
10190
}
91+
});
92+
93+
// configure Spring environment property
94+
List<String> propertyNames;
95+
if (StringUtils.isNotBlank(options.property())) {
96+
propertyNames = List.of(options.property());
97+
} else {
98+
propertyNames = Arrays.asList(options.properties()).stream()
99+
.filter(StringUtils::isNotBlank)
100+
.collect(Collectors.toList());
101+
}
102+
propertyNames.forEach(propertyName -> {
103+
String property = propertyName + "=" + newServer.baseUrl();
104+
LOGGER.debug("Adding property '{}' to Spring application context", property);
105+
TestPropertyValues.of(property).applyTo(context.getEnvironment());
106+
});
107+
} else {
108+
LOGGER.info("WireMockServer with name '{}' is already configured", options.name());
102109
}
103-
104-
private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) {
105-
for (Class<? extends WireMockConfigurationCustomizer> customizer : options.configurationCustomizers()) {
106-
try {
107-
ReflectionUtils.newInstance(customizer).customize(serverOptions, options);
108-
} catch (Exception e) {
109-
if (e instanceof NoSuchMethodException) {
110-
LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e);
111-
}
112-
throw e;
113-
}
110+
}
111+
112+
private static void applyCustomizers(ConfigureWireMock options, WireMockConfiguration serverOptions) {
113+
for (Class<? extends WireMockConfigurationCustomizer> customizer : options.configurationCustomizers()) {
114+
try {
115+
ReflectionUtils.newInstance(customizer).customize(serverOptions, options);
116+
} catch (Exception e) {
117+
if (e instanceof NoSuchMethodException) {
118+
LOGGER.error("Customizer {} must have a no-arg constructor", customizer, e);
114119
}
120+
throw e;
121+
}
115122
}
123+
}
116124

117-
private String resolveStubLocation(ConfigureWireMock options) {
118-
return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation();
119-
}
125+
private String resolveStubLocation(ConfigureWireMock options) {
126+
return StringUtils.isBlank(options.stubLocation()) ? "wiremock/" + options.name() : options.stubLocation();
127+
}
120128

121-
@Override
122-
public boolean equals(Object o) {
123-
if (this == o)
124-
return true;
125-
if (o == null || getClass() != o.getClass())
126-
return false;
127-
WireMockContextCustomizer that = (WireMockContextCustomizer) o;
128-
return Objects.equals(configuration, that.configuration);
129+
@Override
130+
public boolean equals(Object o) {
131+
if (this == o) {
132+
return true;
129133
}
130-
131-
@Override
132-
public int hashCode() {
133-
return Objects.hash(configuration);
134+
if (o == null || getClass() != o.getClass()) {
135+
return false;
134136
}
137+
WireMockContextCustomizer that = (WireMockContextCustomizer) o;
138+
return Objects.equals(configuration, that.configuration);
139+
}
135140

136-
// ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223
137-
static class Slf4jNotifier implements Notifier {
141+
@Override
142+
public int hashCode() {
143+
return Objects.hash(configuration);
144+
}
138145

139-
private static final Logger log = LoggerFactory.getLogger("WireMock");
146+
// ported from: https://github.com/spring-cloud/spring-cloud-contract/commit/44c634d0e9e82515d2fba66343530eb7d2ba8223
147+
static class Slf4jNotifier implements Notifier {
140148

141-
private final boolean verbose;
149+
private static final Logger log = LoggerFactory.getLogger("WireMock");
142150

143-
Slf4jNotifier(boolean verbose) {
144-
this.verbose = verbose;
145-
}
151+
private final boolean verbose;
146152

147-
@Override
148-
public void info(String message) {
149-
if (verbose) {
150-
log.info(message);
151-
}
152-
}
153+
Slf4jNotifier(boolean verbose) {
154+
this.verbose = verbose;
155+
}
153156

154-
@Override
155-
public void error(String message) {
156-
log.error(message);
157-
}
157+
@Override
158+
public void info(String message) {
159+
if (verbose) {
160+
log.info(message);
161+
}
162+
}
158163

159-
@Override
160-
public void error(String message, Throwable t) {
161-
log.error(message, t);
162-
}
164+
@Override
165+
public void error(String message) {
166+
log.error(message);
167+
}
163168

169+
@Override
170+
public void error(String message, Throwable t) {
171+
log.error(message, t);
164172
}
173+
174+
}
165175
}

Diff for: wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package app;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
4+
35
import com.github.tomakehurst.wiremock.WireMockServer;
46
import com.maciejwalkowiak.wiremock.spring.ConfigureWireMock;
57
import com.maciejwalkowiak.wiremock.spring.EnableWireMock;
68
import com.maciejwalkowiak.wiremock.spring.InjectWireMock;
79
import org.junit.jupiter.api.Nested;
810
import org.junit.jupiter.api.Test;
9-
1011
import org.springframework.beans.factory.annotation.Autowired;
1112
import org.springframework.boot.autoconfigure.SpringBootApplication;
1213
import org.springframework.boot.test.context.SpringBootTest;
1314
import org.springframework.core.env.Environment;
1415

15-
import static org.assertj.core.api.Assertions.assertThat;
16-
1716
public class WireMockSpringExtensionTest {
1817

1918
@SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class)
@@ -65,20 +64,29 @@ private void assertWireMockServer(WireMockServer wireMockServer, String property
6564
}
6665

6766
@SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class)
68-
@EnableWireMock(@ConfigureWireMock(name = "user-service", property = {"user-service.url", "todo-service.url"}))
67+
@EnableWireMock({
68+
@ConfigureWireMock(name = "user-service", properties = {"user-service.url", "todo-service.url"}),
69+
@ConfigureWireMock(name = "mojo-service", property = "mojo-service.url", properties = {"other-service.url"})
70+
})
6971
@Nested
7072
class MultiplePropertiesBindingTest {
7173

7274
@InjectWireMock("user-service")
7375
private WireMockServer userServiceWireMockServer;
7476

77+
@InjectWireMock("mojo-service")
78+
private WireMockServer mojoServiceWireMockServer;
79+
7580
@Autowired
7681
private Environment environment;
7782

7883
@Test
7984
void bindsUrlToMultipleProperties() {
8085
assertThat(environment.getProperty("user-service.url")).isEqualTo(userServiceWireMockServer.baseUrl());
8186
assertThat(environment.getProperty("todo-service.url")).isEqualTo(userServiceWireMockServer.baseUrl());
87+
// single property binding takes precedence over multiple properties binding
88+
assertThat(environment.getProperty("mojo-service.url")).isEqualTo(mojoServiceWireMockServer.baseUrl());
89+
assertThat(environment.getProperty("other-service.url")).isNull();
8290
}
8391
}
8492

0 commit comments

Comments
 (0)