Skip to content

Commit e56f4f3

Browse files
committed
provide Admin API to inspect and delete contexts
1 parent fe04422 commit e56f4f3

File tree

5 files changed

+433
-3
lines changed

5 files changed

+433
-3
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,13 +1243,28 @@ For any kind of usage with parallel write requests, it's recommended to use a di
12431243

12441244
# Debugging
12451245

1246+
## Logging and responses
1247+
12461248
In general, you can increase verbosity, either by [register a notifier](https://wiremock.org/3.x/docs/configuration/#notification-logging)
12471249
and setting `verbose=true` or starting WireMock standalone (or docker) with `verbose=true`.
12481250

12491251
- EventListeners and Matchers report errors with WireMock-internal exceptions. Additionally, errors are logged.
1250-
In order to see them, [register a notifier](https://wiremock.org/3.x/docs/configuration/#notification-logging).
1252+
For to see them, [register a notifier](https://wiremock.org/3.x/docs/configuration/#notification-logging).
12511253
- Response templating errors are printed in the actual response body.
1252-
- Various actions and decisions of this extensions are logged on info level, along with the context they are happening in.
1254+
- Various actions and decisions of this extension are logged on info level, along with the context they are happening in.
1255+
1256+
## Admin API
1257+
1258+
The extension provides an admin API endpoint to retrieve the current state of the context store as well as to delete contexts:
1259+
1260+
| Endpoint | Method | Description | Example |
1261+
|-----------------------------------------------|--------|-----------------------------------------------------------------------------------------|--------------------------------------------------------|
1262+
| `/__admin/state-extension/contexts` | GET | Retrieves all context names (or an empty list if there are none). Always returns `200`. | `GET http://localhost:8080/__admin/state` |
1263+
| `/__admin/state-extension/contexts/{context}` | GET | Retrieve internal structure of a context. Returns `404` if the context does not exist. | `GET http://localhost:8080/__admin/state/myContext` |
1264+
| `/__admin/state-extension/contexts` | DELETE | Deletes all contexts. Always returns `204`. | `DELETE http://localhost:8080/__admin/state` |
1265+
| `/__admin/state-extension/contexts/{context}` | DELETE | Deletes a single context. Always returns `204`. | `DELETE http://localhost:8080/__admin/state/myContext` |
1266+
1267+
**Note:** The admin API intentionally does not provide `PUT` or `POST` methods for security and stability reasons.
12531268

12541269
# Examples
12551270

src/main/java/org/wiremock/extensions/state/StateExtension.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.github.tomakehurst.wiremock.store.Store;
2222
import org.wiremock.extensions.state.extensions.DeleteStateEventListener;
2323
import org.wiremock.extensions.state.extensions.RecordStateEventListener;
24+
import org.wiremock.extensions.state.extensions.StateAdminApiExtension;
2425
import org.wiremock.extensions.state.extensions.requestmatcher.StateRequestMatcher;
2526
import org.wiremock.extensions.state.extensions.StateTemplateHelperProviderExtension;
2627
import org.wiremock.extensions.state.extensions.TransactionEventListener;
@@ -64,13 +65,15 @@ public List<Extension> create(WireMockServices services) {
6465
var deleteStateEventListener = new DeleteStateEventListener(contextManager, services);
6566
var transactionEventListener = new TransactionEventListener(transactionManager);
6667
var stateRequestMatcher = new StateRequestMatcher(contextManager, services);
68+
var adminApiExtension = new StateAdminApiExtension(contextManager, services);
6769

6870
return List.of(
6971
recordStateEventListener,
7072
deleteStateEventListener,
7173
transactionEventListener,
7274
stateRequestMatcher,
73-
stateTemplateHelperProviderExtension
75+
stateTemplateHelperProviderExtension,
76+
adminApiExtension
7477
);
7578
}
7679
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (C) 2023 Dirk Bolte
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 org.wiremock.extensions.state.extensions;
17+
18+
import com.github.tomakehurst.wiremock.admin.AdminTask;
19+
import com.github.tomakehurst.wiremock.admin.Router;
20+
import com.github.tomakehurst.wiremock.extension.AdminApiExtension;
21+
import com.github.tomakehurst.wiremock.extension.WireMockServices;
22+
import com.github.tomakehurst.wiremock.http.RequestMethod;
23+
import com.github.tomakehurst.wiremock.http.ResponseDefinition;
24+
import org.wiremock.extensions.state.internal.ContextManager;
25+
import org.wiremock.extensions.state.internal.StateExtensionMixin;
26+
import org.wiremock.extensions.state.internal.model.Context;
27+
28+
import java.util.Optional;
29+
import java.util.UUID;
30+
31+
/**
32+
* ADMIN API extension to show and manage context contents.
33+
* <p>
34+
* DO NOT REGISTER directly. Use {@link org.wiremock.extensions.state.StateExtension} instead.
35+
*
36+
* @see org.wiremock.extensions.state.StateExtension
37+
*/
38+
public class StateAdminApiExtension implements AdminApiExtension, StateExtensionMixin {
39+
40+
private final WireMockServices wireMockServices;
41+
private final ContextManager contextManager;
42+
43+
44+
public StateAdminApiExtension(ContextManager contextManager, WireMockServices services) {
45+
this.contextManager = contextManager;
46+
this.wireMockServices = services;
47+
}
48+
49+
@Override
50+
public String getName() {
51+
return "stateAdminApi";
52+
}
53+
54+
55+
@Override
56+
public void contributeAdminApiRoutes(Router router) {
57+
router.add(RequestMethod.GET, createPath("contexts"), getContexts());
58+
router.add(RequestMethod.GET, createPath("contexts/{context}"), getContext());
59+
router.add(RequestMethod.DELETE, createPath("contexts/{context}"), deleteContext());
60+
61+
}
62+
63+
private AdminTask getContexts() {
64+
return (admin, serveEvent, pathParams) -> ResponseDefinition.okForJson(contextManager.getAllContextNames());
65+
}
66+
67+
private AdminTask getContext() {
68+
return (admin, serveEvent, pathParams) -> {
69+
Optional<Context> context = contextManager.getContextCopy(pathParams.get("context"));
70+
return context.map(ResponseDefinition::okForJson).orElseGet(ResponseDefinition::notFound);
71+
};
72+
}
73+
74+
private AdminTask deleteContext() {
75+
return (admin, serveEvent, pathParams) -> {
76+
contextManager.deleteContext(UUID.randomUUID().toString(), pathParams.get("context"));
77+
return ResponseDefinition.noContent();
78+
};
79+
}
80+
81+
private String createPath(String path) {
82+
return String.format("/state-extension/%s", path);
83+
}
84+
}

src/main/java/org/wiremock/extensions/state/internal/ContextManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import org.wiremock.extensions.state.internal.model.Context;
2020

2121
import java.util.LinkedList;
22+
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Optional;
2425
import java.util.function.Consumer;
2526
import java.util.function.Supplier;
27+
import java.util.stream.Collectors;
2628

2729
import static org.wiremock.extensions.state.internal.ExtensionLogger.logger;
2830

@@ -44,6 +46,17 @@ private static Supplier<Context> createNewContext(String contextName) {
4446
};
4547
}
4648

49+
/**
50+
*
51+
*/
52+
public List<String> getAllContextNames() {
53+
return store
54+
.getAllKeys()
55+
.filter((it) -> it.startsWith(CONTEXT_KEY_PREFIX))
56+
.map((it) -> it.replace(CONTEXT_KEY_PREFIX, ""))
57+
.collect(Collectors.toList());
58+
}
59+
4760
/**
4861
* Searches for the context by the given name.
4962
*

0 commit comments

Comments
 (0)