Lyudvig Petrosyan
03/21/2025, 12:06 PM/api/check
, the parameters sent specified under /api/payment
but I expected parameters set specified under /api/check
"parameters": {
"HashFields": ["Inputs", "Amount", "TransactID"],
"Token": "Secret-Token",
"Checksum": "Checksum"
}
Wiremock version: 3.3.1(I tried also latest)
Mapping file:
{
"mappings": [
{
"request": {
"urlPath": "/api/check",
"method": "POST",
"customMatcher": {
"name": "MD5Hash-matcher",
"parameters": {
"HashFields": [
"Inputs"
],
"Token": "Secret-Token",
"Checksum": "Checksum"
}
},
"bodyPatterns": [
{
"matchesJsonPath": "$.[?($.Lang)]"
},
{
"matchesJsonPath": "$.[?($.Currency)]"
},
{
"matchesJsonPath": "$.[?($.Checksum)]"
},
{
"matchesJsonPath": "$[?(@.Inputs)]"
}
]
},
"response": {
"status": 200,
"bodyFileName": "goodwin/api/checkResponse_{{jsonPath request.body '$.Inputs[0]'}}.json"
},
"metadata": {
"serviceName": "GoodWin",
"serviceId": "97",
"action": "check",
"description": ""
}
},
{
"request": {
"urlPath": "/api/payment",
"method": "POST",
"customMatcher": {
"name": "MD5Hash-matcher",
"parameters": {
"HashFields": [
"Inputs",
"Amount",
"TransactID"
],
"Token": "Secret-Token",
"Checksum": "Checksum"
}
},
"bodyPatterns": [
{
"matchesJsonPath": "$.[?($.Lang)]"
},
{
"matchesJsonPath": "$.[?($.Currency)]"
},
{
"matchesJsonPath": "$[?(@.Checksum && @.Checksum =~ /^[a-f0-9]{32}$/)]"
},
{
"matchesJsonPath": "$[?(@.Inputs)]"
},
{
"matchesJsonPath": "$[?($.DtTime)]"
},
{
"matchesJsonPath": "$.[?($.Amount)]"
},
{
"matchesJsonPath": "$.[?($.TransactID)]"
}
]
},
"response": {
"status": 200,
"bodyFileName": "goodwin/api/paymentResponse_{{jsonPath request.body '$.Inputs[0]'}}.json"
},
"metadata": {
"serviceName": "GoodWin",
"serviceId": "97",
"action": "pay",
"description": ""
}
}
]
}
Extension Matcher class:
package org.wiremock.extensions.matchers;
import com.github.tomakehurst.wiremock.core.ConfigurationException;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.matching.MatchResult;
import com.github.tomakehurst.wiremock.matching.RequestMatcherExtension;
import static com.github.tomakehurst.wiremock.common.LocalNotifier.notifier;
import static org.wiremock.helpers.HashFieldsHelper.getConcatenatedValues;
import static org.wiremock.helpers.MD5HashGenerator.calculateMD5Hash;
import static org.wiremock.helpers.RequestHelper.extractJsonPathValue;
/**
* Custom WireMock request matcher that validates a request based on an MD5 hash.
* The computed hash is generated using specific JSON fields then
* compared against the provided checksum in the request body.
*
* <p><b>Required Parameters:</b></p>
* <ul>
* <li><b>HashFields (String Array)</b>: The JSON fields whose values will be concatenated and hashed.
* * These fields must exist in the request body and be specified in the WireMock mapping file.</li>
* * <li><b>Token (String)</b>: A token provided in the WireMock mapping, which is prepended to the concatenated hash values before computing the checksum.</li>
* * <li><b>Checksum (String)</b>: The JSON path (provided in the WireMock mapping) to locate the expected MD5 hash in the request body.</li>
* </ul>
*
* <p><b>Example WireMock Mapping:</b></p>
* <pre>
* {
* "request": {
* "method": "POST",
* "url": "/api/payment",
* "customMatcher": {
* "name": "MD5Hash-matcher",
* "parameters": {
* "HashFields": ["Inputs","Amount","TransactID"],
* "Token": "Secret-Token",
* "Checksum": "Checksum"
* }
* }
* }
* </pre>
*/
public class GoodwinMD5HashMatcher extends RequestMatcherExtension {
private static final String hashFields = "HashFields";
private static final String token = "Token";
private static final String checksum = "Checksum";
@Override
public String getName() {
return "MD5Hash-matcher";
}
@Override
public MatchResult match(Request request, Parameters parameters) {
try {
String requestPath = request.getUrl();
notifier().info("Request Path: " + requestPath + " | Parameters: " + parameters.values());
String requestBody = request.getBodyAsString();
String computedChecksum = calculateMD5Hash(
String.format("%s%s", parameters.getString(token), getConcatenatedValues(hashFields, requestBody, parameters))
).toLowerCase();
String providedChecksum = extractJsonPathValue(requestBody, parameters.getString(checksum));
if (providedChecksum.equals(computedChecksum)) {
return MatchResult.exactMatch();
} else {
String errorMessage = "Checksum mismatch: expected '" + computedChecksum + "' but got '" + providedChecksum + "'";
notifier().error(errorMessage);
throw new ConfigurationException(errorMessage);
}
} catch (Exception e) {
String errorMessage = "Error processing request: " + e.getClass().getSimpleName() + " - " + e.getMessage();
notifier().error(errorMessage);
throw new ConfigurationException(errorMessage);
}
}
}
Thank you in advance for your help.Lee Turner
03/28/2025, 9:36 AMLyudvig Petrosyan
04/01/2025, 12:13 PM1_mapping
, 2_mapping
, and 3_mapping
, it always sends the parameters from 3_mapping
.Lee Turner
04/01/2025, 1:12 PMLee Turner
04/02/2025, 10:47 AMLee Turner
04/02/2025, 11:14 AMLyudvig Petrosyan
04/02/2025, 11:20 AMLyudvig Petrosyan
04/02/2025, 11:21 AMLee Turner
04/02/2025, 12:04 PMcreateStubMatchesJsonPathPOST
method so I can take a look at what that is doing ?Lyudvig Petrosyan
04/02/2025, 12:08 PMpackage org.wiremock.helpers;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.Json;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import java.util.Map;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
import static org.wiremock.AbstractTestBase.wm;
public class WiremockStubHelper {
public static void createStubMatchesJsonPathPOST(String urlPath,
String matcherName,
Map<String, Object> matcherParams,
Map<String, String> requestFields,
Map<String, String> responseBody,
HttpHeaders headers) {
wm.stubFor(
<http://WireMock.post|WireMock.post>(urlPathMatching(urlPath))
.andMatching(matcherName, Parameters.from(matcherParams))
.withRequestBody(
requestFields.entrySet().stream()
.map(entry -> WireMock.matchingJsonPath(entry.getKey()))
.reduce((a, b) -> a.and(b))
.orElseThrow()
)
.willReturn(
WireMock.ok()
.withHeaders(headers)
.withJsonBody(Json.node(Json.write(responseBody)))
)
);
}
}
Lee Turner
04/02/2025, 12:08 PMLee Turner
04/02/2025, 12:17 PMLyudvig Petrosyan
04/02/2025, 12:21 PMLee Turner
04/02/2025, 12:29 PMLyudvig Petrosyan
04/02/2025, 12:33 PMLyudvig Petrosyan
04/02/2025, 1:00 PMLee Turner
04/02/2025, 1:53 PM3.12.1
Could you try updating to the latest version of wiremock and giving that a try first ?Lyudvig Petrosyan
04/02/2025, 2:47 PMLee Turner
04/02/2025, 2:47 PM