Skip to content

Commit 29f0ebc

Browse files
authored
Adding matcher for property existence/non-existence (#42)
- corrected handling of all matchers using numbers: a non-numeric value will now result in a non-match (no error logs will be posted as they might be plenty based on the stubs that are configured) <!-- Please describe your pull request here. --> ## References - TODO <!-- References to relevant GitHub issues and pull requests, esp. upstream and downstream changes --> ## Submitter checklist - [ ] Recommended: Join [WireMock Slack](https://slack.wiremock.org/) to get any help in `#help-contributing` or a project-specific channel like `#wiremock-java` - [ ] The PR request is well described and justified, including the body and the references - [ ] The PR title represents the desired changelog entry - [ ] The repository's code style is followed (see the contributing guide) - [ ] Test coverage that demonstrates that the change works as expected - [ ] For new features, there's necessary documentation in this pull request or in a subsequent PR to [wiremock.org](https://github.com/wiremock/wiremock.org) <!-- Put an `x` into the [ ] to show you have filled the information. The template comes from https://github.com/wiremock/.github/blob/main/.github/pull_request_template.md You can override it by creating .github/pull_request_template.md in your own repository -->
1 parent 4791cc4 commit 29f0ebc

File tree

4 files changed

+352
-141
lines changed

4 files changed

+352
-141
lines changed

README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,36 @@ behavior for requests with and without a matching context. The parameter support
617617
}
618618
```
619619

620+
### Property existence match
621+
622+
In addition to the existence of a context, you can check for the existence or absence of a property
623+
within that context. The following matchers are available:
624+
625+
- `hasProperty`
626+
- `hasNotProperty`
627+
628+
As for other matchers, templating is supported.
629+
630+
```json
631+
{
632+
"request": {
633+
"method": "GET",
634+
"urlPattern": "/test/[^\/]+/[^\/]+",
635+
"customMatcher": {
636+
"name": "state-matcher",
637+
"parameters": {
638+
"hasContext": "{{request.pathSegments.[1]}}",
639+
"hasProperty": "{{request.pathSegments.[2]}}"
640+
}
641+
}
642+
},
643+
"response": {
644+
"status": 200
645+
}
646+
}
647+
```
648+
649+
620650
### Context update count match
621651

622652
Whenever the serve event listener `recordState` is processed, the internal context update counter is increased. The number can be used
@@ -626,7 +656,7 @@ for request matching as well. The following matchers are available:
626656
- `updateCountLessThan`
627657
- `updateCountMoreThan`
628658

629-
As for other matchers, templating is supported.
659+
As for other matchers, templating is supported. In case the provided value for this check is not numeric, it is handled as non-matching. No error will be reported or logged.
630660

631661
```json
632662
{
@@ -656,7 +686,7 @@ for request matching as well. The following matchers are available:
656686
- `listSizeLessThan`
657687
- `listSizeMoreThan`
658688

659-
As for other matchers, templating is supported.
689+
As for other matchers, templating is supported. In case the provided value for this check is not numeric, it is handled as non-matching. No error will be reported or logged.
660690

661691
```json
662692
{

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

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import java.util.function.BiFunction;
3535
import java.util.stream.Collectors;
3636

37+
import static com.github.tomakehurst.wiremock.common.LocalNotifier.notifier;
38+
3739
/**
3840
* Request matcher for state.
3941
* <p>
@@ -51,12 +53,12 @@ public StateRequestMatcher(ContextManager contextManager, TemplateEngine templat
5153
this.templateEngine = templateEngine;
5254
}
5355

54-
private static List<Map.Entry<CountMatcher, Object>> getMatches(Parameters parameters) {
56+
private static List<Map.Entry<ContextMatcher, Object>> getMatches(Parameters parameters) {
5557
return parameters
5658
.entrySet()
5759
.stream()
58-
.filter(it -> CountMatcher.from(it.getKey()) != null)
59-
.map(it -> Map.entry(CountMatcher.from(it.getKey()), it.getValue()))
60+
.filter(it -> ContextMatcher.from(it.getKey()) != null)
61+
.map(it -> Map.entry(ContextMatcher.from(it.getKey()), it.getValue()))
6062
.collect(Collectors.toUnmodifiableList());
6163
}
6264

@@ -78,7 +80,7 @@ public MatchResult match(Request request, Parameters parameters) {
7880
private MatchResult hasContext(Map<String, Object> model, Parameters parameters, String template) {
7981
return contextManager.getContext(renderTemplate(model, template))
8082
.map(context -> {
81-
List<Map.Entry<CountMatcher, Object>> matchers = getMatches(parameters);
83+
List<Map.Entry<ContextMatcher, Object>> matchers = getMatches(parameters);
8284
if (matchers.isEmpty()) {
8385
return MatchResult.exactMatch();
8486
} else {
@@ -87,11 +89,11 @@ private MatchResult hasContext(Map<String, Object> model, Parameters parameters,
8789
}).orElseGet(MatchResult::noMatch);
8890
}
8991

90-
private MatchResult calculateMatch(Map<String, Object> model, Context context, List<Map.Entry<CountMatcher, Object>> matchers) {
92+
private MatchResult calculateMatch(Map<String, Object> model, Context context, List<Map.Entry<ContextMatcher, Object>> matchers) {
9193
model.put("context", ContextTemplateModel.from(context));
9294
var result = matchers
9395
.stream()
94-
.map(it -> it.getKey().evaluate(context, Long.valueOf(renderTemplate(model, it.getValue().toString()))))
96+
.map(it -> it.getKey().evaluate(context, renderTemplate(model, it.getValue().toString())))
9597
.filter(it -> !it)
9698
.count();
9799

@@ -111,26 +113,40 @@ String renderTemplate(Object context, String value) {
111113
return templateEngine.getUncachedTemplate(value).apply(context);
112114
}
113115

114-
private enum CountMatcher {
115-
updateCountEqualTo((Context context, Long value) -> context.getUpdateCount().equals(value)),
116-
updateCountLessThan((Context context, Long value) -> context.getUpdateCount() < value),
117-
updateCountMoreThan((Context context, Long value) -> context.getUpdateCount() > value),
118-
listSizeEqualTo((Context context, Long value) -> context.getList().size() == value),
119-
listSizeLessThan((Context context, Long value) -> context.getList().size() < value),
120-
listSizeMoreThan((Context context, Long value) -> context.getList().size() > value);
116+
private enum ContextMatcher {
117+
118+
hasProperty((Context c, String stringValue) -> c.getProperties().containsKey(stringValue)),
119+
hasNotProperty((Context c, String stringValue) -> !c.getProperties().containsKey(stringValue)),
120+
updateCountEqualTo((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount().equals(value))),
121+
updateCountLessThan((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount() < value)),
122+
updateCountMoreThan((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount() > value)),
123+
listSizeEqualTo((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() == value)),
124+
listSizeLessThan((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() < value)),
125+
listSizeMoreThan((Context c, String stringValue) -> withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() > value));
121126

122-
private final BiFunction<Context, Long, Boolean> evaluator;
127+
private final BiFunction<Context, String, Boolean> evaluator;
123128

124-
CountMatcher(BiFunction<Context, Long, Boolean> evaluator) {
129+
ContextMatcher(BiFunction<Context, String, Boolean> evaluator) {
125130
this.evaluator = evaluator;
126131
}
127132

128-
public static CountMatcher from(String from) {
133+
public static ContextMatcher from(String from) {
129134
return Arrays.stream(values()).filter(it -> it.name().equals(from)).findFirst().orElse(null);
130135
}
131136

132-
public boolean evaluate(Context context, Long value) {
137+
private static boolean withConvertedNumber(Context context, String stringValue, BiFunction<Context, Long, Boolean> evaluator) {
138+
try {
139+
var longValue = Long.valueOf(stringValue);
140+
return evaluator.apply(context, longValue);
141+
} catch (NumberFormatException ex) {
142+
return false;
143+
}
144+
145+
}
146+
147+
public boolean evaluate(Context context, String value) {
133148
return this.evaluator.apply(context, value);
134149
}
150+
135151
}
136152
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.wiremock.extensions.state.internal;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
5+
@JsonIgnoreProperties(ignoreUnknown = true)
6+
public class StateRequestMatcherParameters {
7+
String hasContext;
8+
9+
String hasNotContext;
10+
String updateCountEqualTo;
11+
String updateCountLessThan;
12+
String updateCountMoreThan;
13+
String listSizeEqualTo;
14+
String listSizeLessThan;
15+
String listSizeMoreThan;
16+
17+
public String getHasNotContext() {
18+
return hasNotContext;
19+
}
20+
21+
public void setHasNotContext(String hasNotContext) {
22+
this.hasNotContext = hasNotContext;
23+
}
24+
25+
public String getHasContext() {
26+
return hasContext;
27+
}
28+
29+
public void setHasContext(String hasContext) {
30+
this.hasContext = hasContext;
31+
}
32+
33+
public String getUpdateCountEqualTo() {
34+
return updateCountEqualTo;
35+
}
36+
37+
public void setUpdateCountEqualTo(String updateCountEqualTo) {
38+
this.updateCountEqualTo = updateCountEqualTo;
39+
}
40+
41+
public String getUpdateCountLessThan() {
42+
return updateCountLessThan;
43+
}
44+
45+
public void setUpdateCountLessThan(String updateCountLessThan) {
46+
this.updateCountLessThan = updateCountLessThan;
47+
}
48+
49+
public String getUpdateCountMoreThan() {
50+
return updateCountMoreThan;
51+
}
52+
53+
public void setUpdateCountMoreThan(String updateCountMoreThan) {
54+
this.updateCountMoreThan = updateCountMoreThan;
55+
}
56+
57+
public String getListSizeEqualTo() {
58+
return listSizeEqualTo;
59+
}
60+
61+
public void setListSizeEqualTo(String listSizeEqualTo) {
62+
this.listSizeEqualTo = listSizeEqualTo;
63+
}
64+
65+
public String getListSizeLessThan() {
66+
return listSizeLessThan;
67+
}
68+
69+
public void setListSizeLessThan(String listSizeLessThan) {
70+
this.listSizeLessThan = listSizeLessThan;
71+
}
72+
73+
public String getListSizeMoreThan() {
74+
return listSizeMoreThan;
75+
}
76+
77+
public void setListSizeMoreThan(String listSizeMoreThan) {
78+
this.listSizeMoreThan = listSizeMoreThan;
79+
}
80+
}

0 commit comments

Comments
 (0)