10BC0 Merge pull request #2991 from MasonM/remove-unused-mappings · wiremock/wiremock@4da8c0f · GitHub
[go: up one dir, main page]

Skip to content

Commit 4da8c0f

Browse files
authored
Merge pull request #2991 from MasonM/remove-unused-mappings
feat: admin API endpoints to find/remove unmatched stub mappings
2 parents 8a796d5 + 74c40ed commit 4da8c0f

File tree

11 files changed

+291
-8
lines changed

11 files changed

+291
-8
lines changed

src/main/java/com/github/tomakehurst/wiremock/WireMockServer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2011-2024 Thomas Akehurst
2+
* Copyright (C) 2011-2025 Thomas Akehurst
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -531,6 +531,11 @@ public void shutdownServer() {
531531
shutdown();
532532
}
533533

534+
@Override
535+
public ListStubMappingsResult findUnmatchedStubs() {
536+
return wireMockApp.findUnmatchedStubs();
537+
}
538+
534539
@Override
535540
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
536541
return wireMockApp.findAllStubsByMetadata(pattern);

src/main/java/com/github/tomakehurst/wiremock/admin/AdminRoutes.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2016-2024 Thomas Akehurst
2+
* Copyright (C) 2016-2025 Thomas Akehurst
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -64,6 +64,8 @@ private void initDefaultRoutes(Router router) {
6464

6565
router.add(POST, "/mappings/save", new SaveMappingsTask());
6666
router.add(POST, "/mappings/reset", new ResetToDefaultMappingsTask());
67+
router.add(GET, "/mappings/unmatched", new GetUnmatchedStubMappingsTask());
68+
router.add(DELETE, "/mappings/unmatched", new RemoveUnmatchedStubMappingsTask());
6769
router.add(GET, "/mappings/{id}", new GetStubMappingTask());
6870
router.add(PUT, "/mappings/{id}", new EditStubMappingTask());
6971
router.add(POST, "/mappings/remove", new RemoveMatchingStubMappingTask());
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2016-2025 Thomas Akehurst
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.github.tomakehurst.wiremock.admin.tasks;
17+
18+
import com.github.tomakehurst.wiremock.admin.AdminTask;
19+
import com.github.tomakehurst.wiremock.admin.model.ListStubMappingsResult;
20+
import com.github.tomakehurst.wiremock.common.url.PathParams;
21+
import com.github.tomakehurst.wiremock.core.Admin;
22+
import com.github.tomakehurst.wiremock.http.ResponseDefinition;
23+
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
24+
25+
public class GetUnmatchedStubMappingsTask implements AdminTask {
26+
27+
@Override
28+
public ResponseDefinition execute(Admin admin, ServeEvent serveEvent, PathParams pathParams) {
29+
ListStubMappingsResult result = admin.findUnmatchedStubs();
30+
return ResponseDefinition.okForJson(result);
31+
}
32+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (C) 2016-2025 Thomas Akehurst
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.github.tomakehurst.wiremock.admin.tasks;
17+
18+
import com.github.tomakehurst.wiremock.admin.AdminTask;
19+
import com.github.tomakehurst.wiremock.common.url.PathParams;
20+
import com.github.tomakehurst.wiremock.core.Admin;
21+
import com.github.tomakehurst.wiremock.http.ResponseDefinition;
22+
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
23+
24+
public class RemoveUnmatchedStubMappingsTask implements AdminTask {
25+
26+
@Override
27+
public ResponseDefinition execute(Admin admin, ServeEvent serveEvent, PathParams pathParams) {
28+
admin.findUnmatchedStubs().getMappings().forEach(admin::removeStubMapping);
29+
return ResponseDefinition.okEmptyJson();
30+
}
31+
}

src/main/java/com/github/tomakehurst/wiremock/client/HttpAdminClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,13 @@ public void shutdownServer() {
428428
postJsonAssertOkAndReturnBody(urlFor(ShutdownServerTask.class), null);
429429
}
430430

431+
@Override
432+
public ListStubMappingsResult findUnmatchedStubs() {
433+
return executeRequest(
434+
adminRoutes.requestSpecForTask(GetUnmatchedStubMappingsTask.class),
435+
ListStubMappingsResult.class);
436+
}
437+
431438
@Override
432439
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
433440
return executeRequest(

src/main/java/com/github/tomakehurst/wiremock/core/Admin.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2011-2023 Thomas Akehurst
2+
* Copyright (C) 2011-2025 Thomas Akehurst
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -106,6 +106,8 @@ public interface Admin {
106106

107107
void shutdownServer();
108108

109+
ListStubMappingsResult findUnmatchedStubs();
110+
109111
ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern);
110112

111113
void removeStubsByMetadata(StringValuePattern pattern);

src/main/java/com/github/tomakehurst/wiremock/core/WireMockApp.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2012-2024 Thomas Akehurst
2+
* Copyright (C) 2012-2025 Thomas Akehurst
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -578,6 +578,27 @@ public RecordingStatusResult getRecordingStatus() {
578578
return new RecordingStatusResult(recorder.getStatus().name());
579579
}
580580

581+
private Set<UUID> findMatchedStubIds() {
582+
return requestJournal.getAllServeEvents().stream()
583+
.filter(event -> event.getStubMapping() != null)
584+
.map(event -> event.getStubMapping().getId())
585+
.collect(Collectors.toSet());
586+
}
587+
588+
@Override
589+
public ListStubMappingsResult findUnmatchedStubs() {
590+
// Collect IDs of stub mappings that have matched at least one request in a HashSet for O(1)
591+
// lookups so this method is O(n + m), where n is the number of stubs and m is the number of
592+
// requests in the journal.
593+
// It'd be slightly more efficient to use IdentityHashMap, but that's error-prone.
594+
Set<UUID> servedStubIds = findMatchedStubIds();
595+
List<StubMapping> foundMappings =
596+
stubMappings.getAll().stream()
597+
.filter(stub -> !servedStubIds.contains(stub.getId()))
598+
.collect(Collectors.toList());
599+
return new ListStubMappingsResult(LimitAndOffsetPaginator.none(foundMappings));
600+
}
601+
581602
@Override
582603
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
583604
return new ListStubMappingsResult(

src/main/java/com/github/tomakehurst/wiremock/junit/DslWrapper.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2021-2024 Thomas Akehurst
2+
* Copyright (C) 2021-2025 Thomas Akehurst
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -231,6 +231,11 @@ public void shutdownServer() {
231231
admin.shutdownServer();
232232
}
233233

234+
@Override
235+
public ListStubMappingsResult findUnmatchedStubs() {
236+
return admin.findUnmatchedStubs();
237+
}
238+
234239
@Override
235240
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
236241
return admin.findAllStubsByMetadata(pattern);

src/main/resources/swagger/wiremock-admin-api.json

Lines changed: 88 additions & 2 deletions
432
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,85 @@
399399
}
400400
}
401401
},
402+
"/__admin/mappings/unmatched": {
403+
"get": {
404+
"operationId": "findUnmatchedStubMappings",
405+
"summary": "Find unmatched stub mappings",
406+
"description": "Find stub mappings that haven't matched any requests in the journal",
407+
"tags": [
408+
"Stub Mappings"
409+
],
410+
"responses": {
411+
"200": {
412+
"description": "Unmatched stub mappings",
413+
"content": {
414+
"application/json": {
415+
"schema": {
416+
"$ref": "#/components/schemas/stub-mappings"
417+
},
418+
"example": {
419+
"meta": {
420+
"total": 2
421+
},
422+
"mappings": [
423+
{
424+
"id": "76ada7b0-49ae-4229-91c4-396a36f18e09",
425+
"uuid": "76ada7b0-49ae-4229-91c4-396a36f18e09",
426+
"request": {
427+
"method": "GET",
428+
"url": "/search?q=things",
429+
"headers": {
430+
"Accept": {
431+
"equalTo": "application/json"
+
}
433+
}
434+
},
435+
"response": {
436+
"status": 200,
437+
"jsonBody": [
438+
"thing1",
439+
"thing2"
440+
],
441+
"headers": {
442+
"Content-Type": "application/json"
443+
}
444+
}
445+
},
446+
{
447+
"request": {
448+
"method": "POST",
449+
"urlPath": "/some/things",
450+
"bodyPatterns": [
451+
{
452+
"equalToXml": "<stuff />"
453+
}
454+
]
455+
},
456+
"response": {
457+
"status": 201
458+
}
459+
}
460+
]
461+
}
462+
}
463+
}
464+
}
465+
}
466+
},
467+
"delete": {
468+
"operationId": "removeUnmatchedStubMappings",
469+
"summary": "Remove unmatched stub mappings",
470+
"description": "Remove stub mappings that haven't matched any requests in the journal",
471+
"tags": [
472+
"Stub Mappings"
473+
],
474+
"responses": {
475+
"200": {
476+
"description": "OK"
477+
}
478+
}
479+
}
480+
},
402481
"/__admin/requests": {
403482
"get": {
404483
"operationId": "getAllRequestsInJournal",
@@ -1832,7 +1911,7 @@
18321911
]
18331912
},
18341913
"after-pattern": {
1835-
"title": "Before datetime",
1914+
"title": "After datetime",
18361915
"type": "object",
18371916
"properties": {
18381917
"after": {
@@ -1949,7 +2028,11 @@
19492028
},
19502029
"namespaceAwareness": {
19512030
"type": "string",
1952-
"enum": ["LEGACY", "STRICT", "NONE"]
2031+
"enum": [
2032+
"LEGACY",
2033+
"STRICT",
2034+
"NONE"
2035+
]
19532036
}
19542037
},
19552038
"required": [
@@ -2239,6 +2322,9 @@
22392322
"name": {
22402323
"type": "string"
22412324
},
2325+
"fileName": {
2326+
"type": "string"
2327+
},
22422328
"matchingType": {
22432329
"type": "string",
22442330
"description": "Determines whether all or any of the parts must match the criteria for an overall match.",

src/main/resources/swagger/wiremock-admin-api.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,32 @@ paths:
211211
'200':
212212
description: 'The stub mappings were successfully removed'
213213

214+
/__admin/mappings/unmatched:
215+
get:
216+
operationId: findUnmatchedStubMappings
217+
summary: Find unmatched stub mappings
218+
description: Find stub mappings that haven't matched any requests in the journal
219+
tags:
220+
- Stub Mappings
221+
responses:
222+
'200':
223+
description: Unmatched stub mappings
224+
content:
225+
application/json:
226+
schema:
227+
$ref: 'schemas/stub-mappings.yaml'
228+
example:
229+
$ref: 'examples/stub-mappings.yaml'
230+
delete:
231+
operationId: removeUnmatchedStubMappings
232+
summary: Remove unmatched stub mappings
233+
description: Remove stub mappings that haven't matched any requests in the journal
234+
tags:
235+
- Stub Mappings
236+
responses:
237+
'200':
238+
description: OK
239+
214240
/__admin/requests:
215241
get:
216242
operationId: getAllRequestsInJournal

0 commit comments

Comments
 (0)
0