Skip to content

Commit 6880eab

Browse files
authored
feat!: simplify mappings lookup (refs #95) (#101)
1 parent 270e49a commit 6880eab

File tree

9 files changed

+223
-74
lines changed

9 files changed

+223
-74
lines changed

src/main/java/org/wiremock/spring/ConfigureWireMock.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.github.tomakehurst.wiremock.extension.ExtensionFactory;
77
import java.lang.annotation.Retention;
88
import java.lang.annotation.RetentionPolicy;
9+
import java.util.List;
910
import org.springframework.beans.factory.annotation.Autowired;
1011

1112
/**
@@ -15,6 +16,17 @@
1516
*/
1617
@Retention(RetentionPolicy.RUNTIME)
1718
public @interface ConfigureWireMock {
19+
public static final List<String> DEFAULT_FILES_UNDER_DIRECTORY =
20+
List.of(
21+
"wiremock",
22+
"stubs",
23+
"mappings",
24+
"src/test/resources/wiremock",
25+
"src/test/resources/stubs",
26+
"src/test/resources/mappings",
27+
"src/integtest/resources/wiremock",
28+
"src/integtest/resources/stubs",
29+
"src/integtest/resources/mappings");
1830

1931
/**
2032
* Port on which WireMock server is going to listen.
@@ -80,20 +92,21 @@
8092
String[] httpsBaseUrlProperties() default {"wiremock.server.httpsBaseUrl"};
8193

8294
/**
83-
* Classpaths to pass to {@link WireMockConfiguration#usingFilesUnderClasspath(String)}. First one
84-
* that is found will be used. If a {@link #name()} is supplied, it will first look for {@link
85-
* #filesUnderClasspath()}/{@link #name()} enabling different mappings for differently named
86-
* WireMocks.
95+
* Classpaths to pass to {@link WireMockConfiguration#usingFilesUnderClasspath(String)}. See also
96+
* {@link #filesUnderDirectory()}.
8797
*/
88-
String[] filesUnderClasspath() default {};
98+
String filesUnderClasspath() default "";
8999

90100
/**
91101
* Directory paths to pass to {@link WireMockConfiguration#usingFilesUnderDirectory(String)}.
92-
* First one that is found will be used. If a {@link #name()} is supplied, it will first look for
93-
* {@link #filesUnderClasspath()}/{@link #name()} enabling different mappings for differently
94-
* named WireMocks.
102+
* First existing directory will be used if list is given.
103+
*
104+
* <p>It will search for mocks in this order:
105+
* <li>In filesystem {@link #filesUnderDirectory()}
106+
* <li>In classpath {@link #filesUnderClasspath()}
107+
* <li>In filesystem {@link #DEFAULT_FILES_UNDER_DIRECTORY}
95108
*/
96-
String[] filesUnderDirectory() default {"wiremock", "stubs", "mappings"};
109+
String[] filesUnderDirectory() default {};
97110

98111
/**
99112
* WireMock extensions to register in {@link WireMockServer}.

src/main/java/org/wiremock/spring/internal/WireMockServerCreator.java

Lines changed: 38 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -48,32 +48,7 @@ public WireMockServer createWireMockServer(
4848
serverOptions.port(serverHttpPort);
4949
}
5050
serverOptions.notifier(new Slf4jNotifier(options.name()));
51-
52-
this.configureFilesUnderDirectory(options.filesUnderDirectory(), "/" + options.name())
53-
.ifPresentOrElse(
54-
present -> this.usingFilesUnderDirectory(serverOptions, present),
55-
() -> {
56-
this.configureFilesUnderDirectory(options.filesUnderDirectory(), "")
57-
.ifPresentOrElse(
58-
present -> this.usingFilesUnderDirectory(serverOptions, present),
59-
() -> {
60-
this.logger.info("No mocks found under directory");
61-
this.configureFilesUnderClasspath(
62-
options.filesUnderClasspath(), "/" + options.name())
63-
.ifPresentOrElse(
64-
present -> this.usingFilesUnderClasspath(serverOptions, present),
65-
() -> {
66-
this.configureFilesUnderClasspath(
67-
options.filesUnderClasspath(), "")
68-
.ifPresentOrElse(
69-
present ->
70-
this.usingFilesUnderClasspath(serverOptions, present),
71-
() -> {
72-
this.logger.info("No mocks found under classpath");
73-
});
74-
});
75-
});
76-
});
51+
configureMappings(options, serverOptions);
7752

7853
if (options.extensionFactories().length > 0) {
7954
serverOptions.extensionFactories(options.extensionFactories());
@@ -173,6 +148,30 @@ public WireMockServer createWireMockServer(
173148
return newServer;
174149
}
175150

151+
private void configureMappings(ConfigureWireMock options, WireMockConfiguration serverOptions) {
152+
boolean isFilesUnderDirectorySupplied = options.filesUnderDirectory().length != 0;
153+
boolean isFilesUnderClasspathSupplied = !options.filesUnderClasspath().isEmpty();
154+
if (isFilesUnderDirectorySupplied) {
155+
Optional<String> foundFilesUnderDirectoryOpt =
156+
this.findFirstExistingDirectory(options.filesUnderDirectory());
157+
if (foundFilesUnderDirectoryOpt.isEmpty()) {
158+
throw new IllegalStateException(
159+
"Cannot find configured mappings directory " + options.filesUnderDirectory());
160+
}
161+
this.usingFilesUnderDirectory(serverOptions, foundFilesUnderDirectoryOpt.get());
162+
} else if (isFilesUnderClasspathSupplied) {
163+
this.usingFilesUnderClasspath(serverOptions, options.filesUnderClasspath());
164+
} else {
165+
Optional<String> fondFilesUnderDirOpt =
166+
this.findFirstExistingDirectory(
167+
ConfigureWireMock.DEFAULT_FILES_UNDER_DIRECTORY.toArray(new String[0]));
168+
fondFilesUnderDirOpt.ifPresent(s -> this.usingFilesUnderDirectory(serverOptions, s));
169+
if (fondFilesUnderDirOpt.isEmpty()) {
170+
this.logger.info("No mocks found under directory");
171+
}
172+
}
173+
}
174+
176175
private int getServerHttpPortProperty(
177176
final ConfigurableEnvironment environment, final ConfigureWireMock options) {
178177
if (!options.usePortFromPredefinedPropertyIfFound()) {
@@ -217,61 +216,40 @@ private int getServerHttpsPortProperty(
217216
.orElse(options.httpsPort());
218217
}
219218

220-
private WireMockConfiguration usingFilesUnderClasspath(
219+
private void usingFilesUnderClasspath(
221220
final WireMockConfiguration serverOptions, final String resource) {
222221
this.logger.info("Serving WireMock mappings from classpath resource: " + resource);
223-
return serverOptions.usingFilesUnderClasspath(resource);
222+
serverOptions.usingFilesUnderClasspath(resource);
224223
}
225224

226-
private WireMockConfiguration usingFilesUnderDirectory(
225+
private void usingFilesUnderDirectory(
227226
final WireMockConfiguration serverOptions, final String dir) {
228227
this.logger.info("Serving WireMock mappings from directory: " + dir);
229-
return serverOptions.usingFilesUnderDirectory(dir);
230-
}
231-
232-
private Optional<String> configureFilesUnderClasspath(
233-
final String[] filesUnderClasspath, final String suffix) {
234-
final List<String> alternatives =
235-
List.of(filesUnderClasspath).stream()
236-
.map(it -> it + suffix)
237-
.filter(
238-
it -> {
239-
final String name = "/" + it;
240-
final boolean exists = WireMockContextCustomizer.class.getResource(name) != null;
241-
this.logger.info(
242-
"Looking for mocks in classpath " + name + "... " + (exists ? "found" : ""));
243-
return exists;
244-
})
245-
.toList();
246-
if (alternatives.size() > 1) {
247-
throw new IllegalStateException(
248-
"Found several filesUnderClasspath: "
249-
+ alternatives.stream().collect(Collectors.joining(", ")));
250-
}
251-
return alternatives.stream().findFirst();
228+
serverOptions.usingFilesUnderDirectory(dir);
252229
}
253230

254-
private Optional<String> configureFilesUnderDirectory(
255-
final String[] filesUnderDirectory, final String suffix) {
231+
private Optional<String> findFirstExistingDirectory(final String... filesUnderDirectory) {
256232
final List<String> alternatives =
257233
Stream.of(filesUnderDirectory)
258-
.map(it -> it + suffix)
259234
.filter(
260235
it -> {
261236
final File name = Path.of(it).toFile();
262-
final boolean exists = name.exists();
237+
final boolean exists =
238+
Path.of(it, "mappings").toFile().exists()
239+
|| Path.of(it, "__files").toFile().exists();
263240
this.logger.info(
264241
"Looking for mocks in directory " + name + "... " + (exists ? "found" : ""));
265242
return exists;
266243
})
267244
.toList();
268245
final String alternativesString = alternatives.stream().collect(Collectors.joining(", "));
269-
if (alternatives.size() > 1) {
270-
throw new IllegalStateException("Found several filesUnderDirectory: " + alternativesString);
271-
}
272246
this.logger.debug(
273247
"Found " + alternativesString + " in " + Path.of("").toFile().getAbsolutePath());
274-
return alternatives.stream().findFirst();
248+
Optional<String> firstMatch = alternatives.stream().findFirst();
249+
if (firstMatch.isPresent()) {
250+
this.logger.info("Using mocks from " + firstMatch.get());
251+
}
252+
return firstMatch;
275253
}
276254

277255
@SuppressFBWarnings
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package usecases;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.github.tomakehurst.wiremock.WireMockServer;
6+
import io.restassured.RestAssured;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.wiremock.spring.ConfigureWireMock;
10+
import org.wiremock.spring.EnableWireMock;
11+
import org.wiremock.spring.InjectWireMock;
12+
13+
@SpringBootTest
14+
@EnableWireMock({@ConfigureWireMock(name = DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME)})
15+
class DefaultDirectoryTest {
16+
public static final String DEFAULT_DIRECTORY_WM_NAME = "test-mappings";
17+
18+
@InjectWireMock(DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME)
19+
private WireMockServer wiremock;
20+
21+
@Test
22+
void usesStubFiles() {
23+
RestAssured.baseURI = "http://localhost:" + this.wiremock.port();
24+
final String actual =
25+
RestAssured.when().get("/1").then().statusCode(200).extract().asPrettyString();
26+
assertThat(actual)
27+
.isEqualToIgnoringWhitespace(
28+
"""
29+
{
30+
"name": "Stuff",
31+
"id": 1
32+
}
33+
""");
34+
}
35+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package usecases;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.github.tomakehurst.wiremock.WireMockServer;
6+
import io.restassured.RestAssured;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.wiremock.spring.ConfigureWireMock;
10+
import org.wiremock.spring.EnableWireMock;
11+
import org.wiremock.spring.InjectWireMock;
12+
13+
@SpringBootTest
14+
@EnableWireMock({
15+
@ConfigureWireMock(
16+
name = DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME,
17+
filesUnderClasspath = "custom-location")
18+
})
19+
class FilesUnderClasspathOverDefaultDirectoryTest {
20+
21+
@InjectWireMock(DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME)
22+
private WireMockServer wiremock;
23+
24+
@Test
25+
void usesStubFiles() {
26+
RestAssured.baseURI = "http://localhost:" + this.wiremock.port();
27+
final String actual =
28+
RestAssured.when()
29+
.get("/classpathmappings")
30+
.then()
31+
.statusCode(200)
32+
.extract()
33+
.asPrettyString();
34+
assertThat(actual)
35+
.isEqualToIgnoringWhitespace(
36+
"""
37+
[
38+
{
39+
"id": 1,
40+
"title": "custom location todo 1",
41+
"userId": 1
42+
},
43+
{
44+
"id": 2,
45+
"title": "custom location todo 2",
46+
"userId": 1
47+
}
48+
]
49+
""");
50+
}
51+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package usecases;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import com.github.tomakehurst.wiremock.WireMockServer;
6+
import io.restassured.RestAssured;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.wiremock.spring.ConfigureWireMock;
10+
import org.wiremock.spring.EnableWireMock;
11+
import org.wiremock.spring.InjectWireMock;
12+
13+
@SpringBootTest
14+
@EnableWireMock({
15+
@ConfigureWireMock(
16+
name = DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME,
17+
filesUnderDirectory = "src/test/resources/custom-location")
18+
})
19+
class FilesUnderDirectoryOverDefaultDirectoryTest {
20+
21+
@InjectWireMock(DefaultDirectoryTest.DEFAULT_DIRECTORY_WM_NAME)
22+
private WireMockServer wiremock;
23+
24+
@Test
25+
void usesStubFiles() {
26+
RestAssured.baseURI = "http://localhost:" + this.wiremock.port();
27+
RestAssured.when().get("/1").then().statusCode(404).extract().asPrettyString();
28+
final String actual =
29+
RestAssured.when()
30+
.get("/classpathmappings")
31+
.then()
32+
.statusCode(200)
33+
.extract()
34+
.asPrettyString();
35+
assertThat(actual)
36+
.isEqualToIgnoringWhitespace(
37+
"""
38+
[
39+
{
40+
"id": 1,
41+
"title": "custom location todo 1",
42+
"userId": 1
43+
},
44+
{
45+
"id": 2,
46+
"title": "custom location todo 2",
47+
"userId": 1
48+
}
49+
]
50+
""");
51+
}
52+
}

src/test/java/usecases/ResetWireMockBetweenTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
@ConfigureWireMock(
2323
name = "wm1",
2424
portProperties = "wm1.server.port",
25-
baseUrlProperties = "wm1.server.url"),
25+
baseUrlProperties = "wm1.server.url",
26+
filesUnderClasspath = "nomocks"),
2627
@ConfigureWireMock(
2728
name = "wm2",
2829
portProperties = "wm2.server.port",
29-
baseUrlProperties = "wm2.server.url")
30+
baseUrlProperties = "wm2.server.url",
31+
filesUnderClasspath = "nomocks")
3032
})
3133
class ResetWireMockBetweenTest {
3234

src/test/java/usecases/ResetWireMockDisabledBetweenTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
name = "wm1",
2525
portProperties = "wm1.server.port",
2626
baseUrlProperties = "wm1.server.url",
27-
resetWireMockServer = false),
27+
resetWireMockServer = false,
28+
filesUnderClasspath = "nomocks"),
2829
@ConfigureWireMock(
2930
name = "wm2",
3031
portProperties = "wm2.server.port",
31-
baseUrlProperties = "wm2.server.url")
32+
baseUrlProperties = "wm2.server.url",
33+
filesUnderClasspath = "nomocks")
3234
})
3335
class ResetWireMockDisabledBetweenTest {
3436

src/test/java/usecases/SingleNamedWireMockTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
@EnableWireMock({
1717
@ConfigureWireMock(
1818
name = "user-client",
19-
filesUnderClasspath = {"wiremock/user-client"},
19+
filesUnderClasspath = "wiremock/user-client",
2020
baseUrlProperties = "user-client.url")
2121
})
2222
class SingleNamedWireMockTest {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"request": {
3+
"method": "GET",
4+
"url": "/1"
5+
},
6+
"response": {
7+
"headers": {
8+
"Content-Type": "application/json"
9+
},
10+
"jsonBody": {
11+
"name": "Stuff",
12+
"id": 1
13+
},
14+
"status": 200
15+
}
16+
}

0 commit comments

Comments
 (0)