Skip to content

Commit

Permalink
refactor: increase test coverage (#111)
Browse files Browse the repository at this point in the history
- removed unused methods
- added tests for configruation errors
- corrected casting for StateRequestMatchers
- added tests for standalone extension initialization
- simplified handlebar helper configuration check

<!-- 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
-->
  • Loading branch information
dirkbolte authored Jan 5, 2024
1 parent af4474a commit bce4c2e
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private void deleteWhere(DeleteStateParameters.ListParameters listConfig, String
private String createContextName(String rawContext) {
var context = Optional.ofNullable(rawContext).filter(StringUtils::isNotBlank)
.map(it -> renderTemplate(model, it))
.orElseThrow(() -> new ConfigurationException("no context specified"));
.orElseThrow(() -> new ConfigurationException("No context specified"));
if (StringUtils.isBlank(context)) {
throw createConfigurationError("Context cannot be blank");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ public Object apply(Object o, Options options) {
if (StringUtils.isEmpty(contextName)) {
return handleError("'context' cannot be empty");
}
if (StringUtils.isBlank(property) && StringUtils.isBlank(list)) {
return handleError("Either 'property' or 'list' has to be set");
}
if (StringUtils.isNotBlank(property) && StringUtils.isNotBlank(list)) {
if (StringUtils.isNotBlank(property) == StringUtils.isNotBlank(list)) {
return handleError("Either 'property' or 'list' has to be set");
}
if (StringUtils.isNotBlank(property)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
import com.github.tomakehurst.wiremock.matching.MatchResult;
import com.github.tomakehurst.wiremock.matching.RequestMatcherExtension;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
import org.wiremock.extensions.state.internal.model.Context;
import org.wiremock.extensions.state.internal.ContextManager;
import org.wiremock.extensions.state.internal.model.ContextTemplateModel;
import org.wiremock.extensions.state.internal.StateExtensionMixin;
import org.wiremock.extensions.state.internal.model.Context;
import org.wiremock.extensions.state.internal.model.ContextTemplateModel;

import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -67,23 +67,23 @@ private static List<Map.Entry<ContextMatcher, Object>> getMatchers(Parameters pa
.collect(Collectors.toUnmodifiableList());
}

private static <T> T cast(Object object) {
private static <T> T mapToObject(Map<String, Object> map, Class<T> klass) {
try {
//noinspection unchecked
return (T) object;
} catch (ClassCastException ex) {
var msg = String.format("Configuration has invalid type: %s", ex.getMessage());
return Json.mapToObject(map, klass);
} catch (Exception ex) {
var msg = String.format("Cannot create pattern matcher: %s", ex.getMessage());
var prefixed = String.format("%s: %s", "StateRequestMatcher", msg);
notifier().error(prefixed);
throw new ConfigurationException(prefixed);
}
}

private static <T> T mapToObject(Map<String, Object> map, Class<T> klass) {
private static <T> T cast(Object object, Class<T> target) {
try {
return Json.mapToObject(map, klass);
} catch (Exception ex) {
var msg = String.format("Cannot create pattern matcher: %s", ex.getMessage());
//noinspection unchecked
return target.cast(object);
} catch (ClassCastException ex) {
var msg = String.format("Configuration has invalid type: %s", ex.getMessage());
var prefixed = String.format("%s: %s", "StateRequestMatcher", msg);
notifier().error(prefixed);
throw new ConfigurationException(prefixed);
Expand Down Expand Up @@ -144,11 +144,11 @@ String renderTemplate(Object context, String value) {

Object renderTemplateRecursively(Object context, Object value) {
if (value instanceof Collection) {
Collection<Object> castedCollection = cast(value);
Collection<Object> castedCollection = cast(value, Collection.class);
return castedCollection.stream().map(it -> renderTemplateRecursively(context, it)).collect(Collectors.toList());
} else if (value instanceof Map) {
var newMap = new HashMap<String, Object>();
Map<String, Object> castedMap = cast(value);
Map<String, Object> castedMap = cast(value, Map.class);
castedMap.forEach((k, v) -> newMap.put(
renderTemplate(context, k),
renderTemplateRecursively(context, v)
Expand All @@ -162,7 +162,7 @@ Object renderTemplateRecursively(Object context, Object value) {
private enum ContextMatcher {

property((Context c, Object object) -> {
Map<String, Map<String, Object>> mapValue = cast(object);
Map<String, Map<String, Object>> mapValue = cast(object, Map.class);
var results = mapValue.entrySet().stream().map(entry -> {
var patterns = mapToObject(entry.getValue(), StringValuePattern.class);
var propertyValue = c.getProperties().get(entry.getKey());
Expand All @@ -177,7 +177,7 @@ private enum ContextMatcher {
}),

list((Context c, Object object) -> {
Map<String, Map<String, Map<String, Object>>> mapValue = cast(object);
Map<String, Map<String, Map<String, Object>>> mapValue = cast(object, Map.class);
var allResults = mapValue.entrySet().stream().map(listIndexEntry -> {
Map<String, String> listEntry;
switch (listIndexEntry.getKey()) {
Expand All @@ -194,7 +194,7 @@ private enum ContextMatcher {
if (listEntry == null) {
return MatchResult.noMatch();
} else {
var results = listIndexEntry.getValue().entrySet().stream().map(entry -> {
List<MatchResult> results = listIndexEntry.getValue().entrySet().stream().map(entry -> {
var patterns = mapToObject(entry.getValue(), StringValuePattern.class);
var propertyValue = listEntry.get(entry.getKey());
return patterns.match(propertyValue);
Expand All @@ -210,35 +210,35 @@ private enum ContextMatcher {
return MatchResult.aggregate(allResults);
}),
hasProperty((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(c.getProperties().containsKey(stringValue));
}),
hasNotProperty((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(!c.getProperties().containsKey(stringValue));
}),
updateCountEqualTo((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount().equals(value)));
}),
updateCountLessThan((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount() < value));
}),
updateCountMoreThan((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getUpdateCount() > value));
}),
listSizeEqualTo((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() == value));
}),
listSizeLessThan((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() < value));
}),
listSizeMoreThan((Context c, Object object) -> {
String stringValue = cast(object);
String stringValue = cast(object, String.class);
return toMatchResult(withConvertedNumber(c, stringValue, (context, value) -> context.getList().size() > value));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,6 @@ public TransactionManager(Store<String, Object> store) {
this.store = store;
}

public <T> T withTransaction(String requestId, String contextName, Function<Transaction, T> function) {
var transactionKey = createTransactionKey(requestId);
synchronized (store) {
@SuppressWarnings("unchecked") var requestTransactions = store.get(transactionKey).map(it -> (Map<String, Transaction>) it).orElse(new HashMap<>());
var contextTransaction = requestTransactions.getOrDefault(contextName, new Transaction(contextName));
try {
return function.apply(contextTransaction);
} finally {
requestTransactions.put(contextName, contextTransaction);
store.put(transactionKey, requestTransactions);
}
}
}

public void withTransaction(String requestId, String contextName, Consumer<Transaction> consumer) {
var transactionKey = createTransactionKey(requestId);
synchronized (store) {
Expand Down Expand Up @@ -80,6 +66,4 @@ public Set<String> getContextNamesByRequestId(String requestId) {
private String createTransactionKey(String requestId) {
return TRANSACTION_KEY_PREFIX + requestId;
}


}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -751,30 +751,53 @@ public void test_ignoreUnknownExtraProperty() {
assertThat(contextManager.getContextCopy(contextName)).isEmpty();
}

private void assertListConfigurationError() {
private void assertConfigurationError(String errorMessage) {
getContext(contextName, HttpStatus.SC_INTERNAL_SERVER_ERROR,
(result) -> assertThat(result)
.hasEntrySatisfying(
"message",
message ->
assertThat(message)
.asInstanceOf(STRING)
.contains("Missing/invalid configuration for list")
.contains(errorMessage)
)
);
}

private void assertListConfigurationError() {
assertConfigurationError("Missing/invalid configuration for list");
}

private void assertContextDeletionConfigurationError() {
getContext(contextName, HttpStatus.SC_INTERNAL_SERVER_ERROR,
(result) -> assertThat(result)
.hasEntrySatisfying(
"message",
message ->
assertThat(message)
.asInstanceOf(STRING)
.contains("Missing/invalid configuration for context deletion")
)
);
assertConfigurationError("Missing/invalid configuration for context deletion");
}

@Nested
public class ContextName {

@DisplayName("fails on missing context name")
@Test
public void test_missingContextName_fail() {
createGetStub(Map.of());

assertConfigurationError("Missing/invalid configuration for context deletion");
}

@DisplayName("fails on empty context name")
@Test
public void test_emptyContextName_fail() {
createGetStub(Map.of("context", ""));

assertConfigurationError("No context specified");
}

@DisplayName("fails on template resulting in empty context name")
@Test
public void test_templateToEmptyContextName_fail() {
createGetStub(Map.of("context", "{{jsonPath '{}' '$.empty'}}"));

assertConfigurationError("Context cannot be blank");
}
}

@DisplayName("with array exact match")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.wiremock.extensions.state.functionality;

import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.wiremock.extensions.state.StandaloneStateExtension;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.assertj.core.api.Assertions.assertThat;

public class StandaloneExtensionTest {


@RegisterExtension
public static WireMockExtension wm = WireMockExtension.newInstance()
.options(
wireMockConfig().dynamicPort().dynamicHttpsPort().templatingEnabled(true).globalTemplating(true)
.extensions(new StandaloneStateExtension())
)
.build();

@Test
public void test_initialized_ok() {
assertThat(wm.getOptions().getDeclaredExtensions().getFactories()).anySatisfy(it -> {
assertThat(it).isInstanceOf(StandaloneStateExtension.class);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,13 @@ void setup() {
postAndAssertContextValue(context, contextValueThree);
}

@DisplayName("fails on invalid configuration")
@Test
void test_invalidConfiguration_fail() {
createGetStub("list", "invalid");
getAndAssertContextMatcher(context, HttpStatus.SC_INTERNAL_SERVER_ERROR);
}

@DisplayName("fails on invalid built-in matchers")
@Test
void test_evaluateBuiltinMatchers_fail() {
Expand Down
Loading

0 comments on commit bce4c2e

Please sign in to comment.