Testing microservices¶
Imagine you have a Metrics for IOT, with microservice architecture:
Metrics And Events
Metrics ---> Receiver ---> Kafka --------> Saver ------> Postres
|| /\ ||
Metrics || || || Metrics
|| || Events || and Events
\/ || \/
Processor <-------> Redis Assessor -------------> Events
Warning -------------> Sensor Statistics
counters
Metrics service collect metrics from devices and sends to the Receiver.
Receiver aggregates metrics and sends them to Kafka.
Processor reads metrics from Kafka, process them and puts generated events back to Kafka.
It also uses Redis for warning counters storage.
Saver microservice saves all metrics and generated events to Postgres.
Finally Assessor takes events and statistics from Postgres and renders it to user or external services.
How to test?¶
Each input request pass through the 9 services. Error can be in any of them. And full coverage of one service with unit
or functional tests won’t help you, because bug can be everywhere. In deploy configuration, wrong protocol in microservices
communication, etc…
Catcher will help you:
---
include:
- file: metrics_check.yaml
as: metrics_check
variables:
metric1: '{{ RANDOM_INT }}'
device_id: '{{ RANDOM_STR }}'
metric2: 5000 # this value will generate warning
steps:
- http: # send data to the Metrics service
actions:
- post:
url: '{{ metrics_url }}/metric'
body: {device_id: '{{ device_id }}', value: '{{ metric1 }}'}
- post:
url: '{{ metrics_url }}/metric'
body: {device_id: '{{ device_id }}', value: '{{ metric2 }}'}
- kafka: # check Receiver put aggregate metric in kafka
consume:
server: '{{ kafka }}'
topic: 'metrics'
where:
equals: {the: '{{ MESSAGE.device_id }}', is: '{{ device_id }}'}
register: {value: '{{ OUTPUT.value }}'}
- check: # check metric's value was properly aggregated
equals: {the: '{{ value }}', is: '{{ metric1 + metric2 }}'}
- wait: {seconds: 0.5}
- kafka: # check event for metric2 was generated
consume:
server: '{{ kafka }}'
topic: 'events'
where:
and:
- equals: {the: '{{ MESSAGE.device_id }}', is: '{{ device_id }}'}
- equals: {the: '{{ MESSAGE.value }}', is: '{{ metric2 }}'}
- postgres: # check Saver put 2 metrics in Postgres
sql: 'select value from metrics where device_id == {{ device_id }}'
register: {metrics: '{{ OUTPUT.value }}'}
- run: metrics_check
- postgres: # check Saver put event in Postgres
sql: 'select count(*) from events where device_id = {{ device_id }} and value = {{ metric2 }}'
register: {event: '{{ OUTPUT.count }}'}
- check: '{{ event == 1 }}'
- http: # request statistics from Assessor
actions:
- get:
url: '{{ assessor_url }}/statistics?device_id={{ device_id }}'
register: {measurements: '{{ OUTPUT.measurements }}'}
- get:
url: '{{ assessor_url }}/events?device_id={{ device_id }}'
register: {events: '{{ OUTPUT.events }}'}
- run: # check proper statistics
include: metrics_check
variables: {metrics: '{{ measurements }}'}
- check:
contains: {the: '{{ metric2 }}', in: '{{ events }}'}
metrics_check.yaml:
---
steps:
- check:
and:
- equals: '{{ metrics|length == 2 }}'
- contains: {the: '{{ metric1 }}', in: '{{ metrics }}'}
- contains: {the: '{{ metric2 }}', in: '{{ metrics }}'}
With this Catcher test scenario you can always be sure, that every component of your system is working properly.