Signature Matching
Most non-trivial applications rely on external systems like 3rd party APIs or databases to function. This is especially true for apps that utilize microservices architectures. Mocks can be generated by hand or automatically by Speedscale. Examples of services that could be mocked include the Google API, postgres or another team's HTTP REST endpoint.
How does it work?
Service mocks are generally made available over the network and are accessible to your app in a test environment or on the local desktop. If your service mocks are working properly, your service under test (SUT) will believe it is actually running in production because the mock is convincing. A realistic service mock must simulate the following components:
- data that is similar to production
- realistic response time (not too fast, not too slow)
- accurate response sequencing for non-idempotent requests
- continuously updated tokens like authentication, etc
How does it know which response to return?
Speedscale uses a special text string called a signature to differentiate between different requests. When the service under test (SUT) sends a request to the Speedscale, selective nuggets of information are extracted from the request and added to the signature. Typically this includes things like HTTP Query Parameters or MySQL SQL statements. Once this signature is generated, it is matched against the library of signatures generated from the previously recorded traffic. When the incoming signature matches a previously recorded one, the related response is returned.
The sequence of events goes like this:
- Traffic is recorded/imported to Speedscale
- You create a Snapshot containing traffic covering a specific timeframe and filter criteria.
- The Speedscale analyzer combines the traffic into a set of signature/response pairs. This can be viewed as a form of compression to make the service mock dataset more compact and dynamic.
- The Speedscale service mocking engine receives a message from the SUT and creates a signature.
- The request signature is compared against all known request signatures in the Snapshot.
- A response is returned if the signature is recognized or a 404 if it is unknown.
- If multiple requests have the same signature but different responses, Speedscale will cycle through the responses in order.
Fundamentally, the signature is a hash map of key=value pairs. The objective of adding transforms to the signature is to make it match with a particular response found in the response. The service mock engine will apply the transforms to the incoming request and based on those modifications it will attempt to find a match in the snapshot. So the purpose of this exercise is to modify miss or passthrough requests individually using transforms until they match an existing response in the snapshot.
Speedscale will automatically generate signatures for common protocols such as HTTP and Postgres. Modification of these signatures is possible and covered in this section. By adding new requests to your traffic snapshot you effectively add new service mock known responses. During environment replication, Speedscale will return the response matching what was recorded in the original environment.
You may notice an instance
field in the signature. This is used to differentiate between multiple requests that are identical. If you modify the instance, you cause the service mock to return this response the nth time this signature is received.
Take the following HTTP request as an example:
POST /foo-platform/pdt/foo/management HTTP/1.1
Content-Type: application/xml; charset=ISO-8859-1
<my request body>
This HTTP request would generate a signature similar to the following:
{
"http:host": "localhost",
"http:method": "POST",
"http:url": "/foo-platform/pdt/foo/management",
"http:requestBodyJSON": "G15IHJlcXVlc3QgYm9keT4=",
"instance": "1"
}
Signatures are essentially hash maps of key=value pairs.
What kind of dependencies can be automatically mocked?
Speedscale automatically mocks any technology on our supported technology page. We've created baselines that work in most situations but you can customize as described below.
What happens if my requests are non-idempotent (aka the response changes after each request)?
Speedscale automatically handles changing responses and is smart enough to deal with many common patterns without human intervention. Speedscale incorporates a learning model that mutates based on the protocol and specific API type being monitored. Even if Speedscale has never seen your API before there is a good probability of it being able to automatically mock your dependency without training.
What if my API or Database isn't mocked correctly out of the box?
The Speedscale model can be trained using the store_sig transform. This transform will add the specified data to the signature and use it to match uniqueness. This transform allows you to add new items to check before accepting a service mock request match.
What if Speedscale cannot automatically mock my dependency?
You can request new protocol support in the Speedscale community Slack. Otherwise, you will need to provide your own replica of the dependency. Typically this involves writing a custom mock server using a framework like Mockito or gomock. For databases this gets a lot more involved and will require database replication tools.
What are some of the downsides of service mocking?
Custom built service mocks tend to fall out of date quickly because the data or the API contract changes. For this reason we recommend Speedscale regenerate your mocks automatically every sprint (if possible).
For more information see our tutorial on mock APIs.