Mock as a Service with Wiremock and Kubernetes

Load testing micro-services or frontends with dependencies is a pain when it come to make comparisons of your tests results. In my experience in digital retailers, I’ve often lost dozens of hours of load tests because a third party goes crazy during the test. As well it needs every time a wide analysis to confirm that the spotted response time degradation came effectively from the dependency and not from your tested application. One way to get rid of this problem is to work with mock services

What is mocking ?

From Wikipedia, the free encyclopedia

In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways, most often as part of a software testing initiative.

In load testing, creating a mock is simulating a third party responses to avoid calling them directly.

Why would I do that ?

  • In your performance scenario, if you’re calling paid API like maps and you want to avoid to pay for the tests.
  • The third party is another team environment or the production
  • Reducing the variation between tests.
  • You want to control your latency (and avoid making calls through the internet to the third party)
  • Limiting your “out” bandwidth because you’re on a cloud provider
  • Fixing the response time of a third party to avoid your test to fail because of it

The more common way to use a mock is in order to isolate the component you are load testing, so you can compare accurately your different load tests avoiding painful analysis to know if it’s your app or your third party that cause slow response times

What should a mock be able to do ?

The mock need to answer requests with a pre-defined response that allow the calling application to run properly without errors. In the best case, the response can be dynamic and the response times settable. In this way, you can mimic the response time of the production one or if not in prod yet, getting it from Service Level Agreement with your partner to set a realistic response time.

At the era of micro-services, mocks are widely used to get JSON response from the clients to mimic other micro-services behavior.

How to set up the mock ?

Wiremock is a Java based tool used as endpoint to answer pre-defined responses to matching requests. It’s a wonderful tool for chaos engineering and performance testing.

Clone this repository on your machine :

git clone git@github.com:Rbillon59/wiremock-loadtest.git

The first step is to define the URL matching and the response in a json file : An example is available in the repository

{
"request": {
"method": "GET",
"url": "/static"
},
"response": {
"status": 200,
"fixedDelayMilliseconds": 1000,
"jsonBody": {
"data": [{
"type": "product",
"id": "1",
"attributes": {
"productName": "Raspberry PI",
"productDescription": "Best product ever",
"price": 42,
"stock": 500
}
}]
}
}
}

This will match the /static request and answer the pre-defined jsonBody with a 1s fixed delay

Then launch the docker container with your newly configured stub :

At the root of the repository, launch :

docker run --rm -p 8080:8080 -v ${PWD}/samples/stubs:/home/wiremock/mappings rbillon59/wiremock-loadtest

And you can test with a simple curl (and jq to beautify a bit) :

$ curl localhost:8080/static | jq

Ok it works, let’s go further !

Mock As A Service

In the repository you’ve both a docker-compose file and a Kubernetes deployment.

The docker-compose file allow you to quickly bring up a set of Wiremock containers behind a nginx reverse proxy. So you can easily handle thousands of requests. The problem with docker-compose is it’s only working on a single host. If you want a distributed deployment across multiple machines you need to switch to Kubernetes.

You can launch the Kubernetes deployment with :

kubectl apply -f -R k8s/

The Kubernetes service type Load Balancer will ensure the exposition of the Wiremock service and the load balancing across the pods. The HorizontalPodAutoscaler will scale automagically the number of Wiremock pods across the cluster if the CPU consumption increase over a threshold and scale down if lower than the threshold. In that way, you will be able to deploy Wiremock just beside your tested application

Let’s check if all is ok:

kubectl get pods

Load testing the mock

Ok so we have deployed a mock service inside a distributed environment, but if the mock cannot handle the sent load, it’s useless, so lets stress it a bit

We will use Vegeta, a dumb but powerful load testing tool. Really useful for it’s really quick start for low complexity projects.

This test is done in the worst possible conditions. On a local k3s cluster, with the tested application and the load injector on the exact same machine. This means that the results are worse than it should be in reality.

We need to know our wiremock’s loadbalancer endpoint :

kubectl get services

Note the wiremock-svc External IP and Port

Let’s try a simple curl to see if all is ok :

All right ! Let’s try to make it burn !

docker run --rm --network=host -i peterevans/vegeta sh -c "echo 'GET http://192.168.1.13:8080/static' | vegeta attack -rate=5000 -duration=60s | tee results.bin | vegeta report"

Report :

Requests      [total, rate, throughput]         299672, 4990.33, 4908.49
Duration [total, attack, wait] 1m1s, 1m0s, 1.001s
Latencies [min, mean, 50, 90, 95, 99, max] 1s, 1.044s, 1.016s, 1.11s, 1.143s, 1.347s, 2.683s
Bytes In [total, mean] 43752112, 146.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:299672

So, we made 5000 requests per seconds during 60 seconds against a single instance of Wiremock for a total of 299.672 requests, and the pod gets up to 23,13% CPU usage (last spike)

It not even reached the auto scaling cap of 30% CPU usage before triggering another pod spawn !

Conclusion

Wiremock combined with Kubernetes offer a really good starter point to provide Mock As A Service in your application’s eco-system. It’s fast, resilient and reliable. We covered here a tiny possibility of the offered Wiremock’s features, the static json response is far from the only. You can work with dynamic responses, templating, proxyfication and of course working with TLS if wanted. Take a look at http://wiremock.org/docs/ to learn more.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store