Multiple matches for request body in wiremock - java

Recently learned request matching in wiremock (http://wiremock.org/docs/request-matching/). Curious about what happens when a request's body matches more than one mappings (defined for same url path with different conditions and returns different json response)?

Technically, WireMock won't ever match twice -- once it finds a singular match, it will return that match. Based on my own testing with using separate mapping files, this usually is the most recently added mapping (I don't know how this works with creating the stubs programmatically, but my guess is that the most recently added stub would be matched and returned).
To avoid this sort of ambiguity, there are a few strategies you can employ, but my personal favorite is to use the priority field along with specific and general mapping.
{
"priority": 1,
"request": {
"url": "/test",
"queryParameters": {
"search_term": {
"equalTo": "WireMock"
}
}
},
"response": {
"status": 201
}
}
{
"priority": 10,
"request": {
"url": "/test",
"queryParameters": {
"search_term": {
"matches": "*"
}
}
},
"response": {
"status": 204
}
}
More information about priority can be found here.
I'd also challenge that you shouldn't have two specific mappings that would both be matched -- the matcher should differ enough to separate the two. If you do need two identical matches, in order to simulate data changing or some other workflow, you can use scenarios to achieve this.

Related

Reducing metrics dimensions with a MetricFilter

We're currently implementing a Spring Boot service with Kafka stream and are currenty looking into the automatically generated metrics so we can establish proper monitoring.
We've found that the data (as exposed by the actuator endpoint) is split into too many dimensions for our needs; we'd be fine with metrics "by topic" for now, but there are also dimensions like "kafka.version", "partitions" etc.
What we did was to try and add a MeterFilter bean like this:
#Bean
public MeterFilter meterFilter() {
return MeterFilter.ignoreTags("spring.id", "kafka.version", "client.id", "partition");
}
This question states "this will ignore all meters with this tag."
That doesn't seem entirely the case - we see output like
(endpoint .../actuator/metrics/kafka.consumer.fetch.manager.records.lag)
{
"name": "kafka.consumer.fetch.manager.records.lag",
"description": "The latest lag of the partition",
"measurements": [
{
"statistic": "VALUE",
"value": 0.0
}
],
"availableTags": [
{
"tag": "topic",
"values": [
"our_internal_app-KSTREAM-TOTABLE-STATE-STORE-0000000002-changelog"
]
}
]
}
This remains the only metric shown at this endpoint.
Does this metric really not originally contain the tags "kafka.version" and "partition"? If we remove the filter, that topic appears along with several more (including internal ones) and with the dimensions we tried to remove.
We were expecting to either not see any metric ("ignore all meters with this tag") or all topics, which is how we read the MeterFilter.ignoreTags() javadoc: "Suppress tags with given tag keys." (suppress tags, not metrics containing them).
What are we misunderstanding?

How to compare number string in filter operator?

data: [
{
"name": "mark",
"age": "20"
},
{
"name": "john",
"age": "10"
}
]
in this case, how to get age greater than 10?
sample code:
JsonPath.read(json, "$.data[?(#.age > 10)]");
This can be done using Jayway's JsonPath library.
First, the JSON you showed is not good for processing, the wrapping { } are missing.
Second, Jayway's comparison operator works if you test against the number as a string (It's a bit weird but the library does the required casting internally that way).
So, with this JSON:
{
"data":[
{
"name":"mark",
"age":"20"
},
{
"name":"john",
"age":"10"
}
]
}
And this filter:
$.data[?(#.age > '10')]
You get the expected result [{"name" : "mark", "age" : "20"}]. You can test it online here.
Update
As pointed out by Parveen Verma, the suggested filter will not work if the range filter requires an implicit type conversion.
Jayway seems to only support implicit conversions when using the equality operators, e.g. $.data[?(#.age == 10)] (this works despite the type differences).
There is an unmerged pull request that adds this behavior; since the code is somewhat behind the current version it may require some work to integrate it but if you really need this functionality it can be done.

Is is possible to reduce two separate query to only one in Elastic Search?

I have ElasticSearch data offers with the following structure:
{
{
"id": "123",
"tariffId": "15477",
"tariffFamilyId": "555",
"characteristics": "xxx"
},
{
"id": "124",
"tariffId": "15478",
"tariffFamilyId": "777",
"characteristics": "yyy"
},
{
"id": "351",
"tariffId": "25271",
"tariffFamilyId": "555",
"characteristics": "zzz"
}
}
I need to find all offers with tariffFamilyId of a certain tariffId. As an initial argument, I know only tariffId and do not know tariffFamilyId (I need to detect it). Normally it means the two separate requests to Elastic Search should be made:
first request - find tariffFamilyId by tariffId.
second request - find offers with that tariffFamilyId.
For example for tariffId=15477, we get tariffFamilyId=555. So for this family, there will be two offers with id 123 and 351.
The question - is it possible to somehow make only one request to Elastic search, not two?
P.S. This is for Java implementation.

ES JAVA API not able to updateByQuery when adding sort by an existing field

I want to avoid reindexing all documents after a field mapping being changed from (excerpt from the template file):
"subject": {
"type": "string"
},
to
"subject": {
"type": "string",
"fields": {
"sort": {
"type": "string",
"analyzer": "ducet_sort_subject"
},
"sortConversation": {
"type": "string",
"analyzer": "ducet_sort_subject_conversation"
}
}
},
the java code latest version is the following:
PutMappingResponse putMappingResponse = client.admin().indices().preparePutMapping(indexName)
.setSource("{\"properties\": {}}").setType("email").execute().actionGet();
BulkIndexByScrollResponse bulkIndexByScrollResponse = INSTANCE.newRequestBuilder(client).source(indexName).get();
Please note that there is no unmappedType default, so if the mapping is not found, I'm expecting to see some error, (as it does without those lines).
Instead I get the results back also for unindexed documents, but the order is random.
I have also tried to add the mapping manually in the setSource, but result didn't change.
In the documentation I read two statements that seem to be contrasting:
"The simplest usage of _update_by_query just performs an update on every document in the index without changing the source. This is useful to pick up a new property or some other online mapping change."
and
"Templates are only applied at index creation time. Changing a template will have no impact on existing indices. When using the create index API, the settings/mappings defined as part of the create index call will take precedence over any matching settings/mappings defined in the template."
is it even possible to do what I want without reindexing?

Wiremock Stand alone - How to manipulate response with request data

I was trying to implement mocking of POST REST call using Wiremock Standalone server. I am faced with a challenge like this, suppose the post body contains an "name" field and its value, the same value should be returned in the response of that POST call. My json file looks like this:
{
"priority": 1,
"request": {
"method": "POST",
"urlPath": "/primeSlots",
"bodyPatterns" : [ {
"matchesJsonPath" : "{ \"things\": [ { \"name\": \"794363\" }]
}"
} ]
},
"response": {
"status": 200,
"body": "{{$.things.name.value}}",
"transformers": ["response-template"]
}
}
so, I need to get the value , that is 794363,but using above approach not able to get it in the post response body.
I tried this too:
{
"request": {
"method": "POST",
"urlPath": "/transform",
"bodyPatterns": [
{
"matchesJsonPath" : "$.things[?(#.name =~ /[0-9]+/i)]"
}
]
},
"response": {
"status": 200,
"body": "{\"responseName\": \"
{{request.body.things.name.value}}\"}",
"headers": {
"Content-Type": "application/json"
},
"transformers": ["body-transformer"]
}
}
So my question is, even if i use a regEx, which matches with any number that comes in the request, how to give back the same number in the response using Wiremock standalone json file?
Thanks.
Today I was in the same situation like you and found a solution which I would like to share with you:
Create own class that extends ResponseDefinitionTransformer
Add Handlebar functionality in your own transformer class ( see https://github.com/jknack/handlebars.java how to do it )
(Optional) Append your own/other helpers e.g.
Arrays.stream(StringHelpers.values()).forEach(helper -> this.handlebars.registerHelper(helper.name(), helper));
Export your transformer customization as a separate JAR file
Create a start batch script to start up your WireMock standalone with your own transformer extension e.g. java -cp "-cp ".\lib\wiremock-standalone-2.5.1.jar;.\lib\customTransformer.jar" com.github.tomakehurst.wiremock.standalone.WireMockServerRunner --extensions "your.name.CustomTransformer" (for linux use : instead of ; as classpath separator)
In case you have multiple transformers, just define all those using , (comma) as separator in the --extensions arg.
Unfortunately WireMock's response templating transformer doesn't currently break out the request body into a Map as would be necessary for what you're trying to do. The request body is just a single string.
The simplest way for you to enable this would probably be to write a Handlebars helper that implements JSONPath or some other mechanism for querying a JSON document, then registering this with the templating transformer when you initialise WireMock.
At some point I'll write handlebars helpers to do this kind of thing for XML and JSON, but that won't be for a while.

Categories

Resources