Using EMS to build tests with dynamic info

This tutorial aims to show the basic concepts and principles of the Elastest Monitoring Service, and its intended use. You can check the documentation of this service following this link.

In this example, we will use Elastest to assess that a webserver — the System under Test — is able to serve multiple clients, and uses as much bandwitdh as possible when doing so.

In particular, our TJob will start one download of a large file at the beginning of the test, and after some time, it will start a second one. The test passes if the bandwidth consumption with two downloads in parallel roughly doubles the bandwidth consumption with only one download going on.

The ElasTest infrastructure provides us with the means to extract data from the server running the test automatically. We use this feature to collect the network activity, which we will analyse in the EMS.

This example is shipped along with ElasTest within the project Building assertions with monitoring data (EMS Example in older versions), but we are going to explain how to create it.

The System under Test

Our SuT is nginx, a well-known webserver. The configuration of the System under Test in elastest is as follows:

  • SuT Name: nginx
  • Select Deployed by Elastest
  • Select With Docker Compose
  • Docker Compose:

    version: '3'
            image: nginx
                - /bin/bash
                - "-c"
                - "dd if=/dev/random of=/usr/share/nginx/html/sparse bs=1024 count=1 seek=5242880000;nginx;sleep infinity"
                - "80"
  • Main Service: nginx-service

  • Wait for http port: 80

The SuT configuration should look like this:

We use Docker Compose to make nginx serve a large file called sparse on the root path of the webserver, which will listen for incoming connections at port 80.

The TJob

The TJob exercising the SuT is an HTTP client written in Go, whose source coude can be found here. First, the TJob uses the Elastest Monitoring Service API to deploy one Stamper and one Monitoring Machine. The stamping rules at the file stampers.txt are the following:

when e.strcmp(type,"net") do #NetData
when e.path(message) do #TJobMsg

when e.tag(#testresult) do #websocket 
when e.tag(#lowavg) do #websocket 
when e.tag(#highavg) do #websocket 

We use the stampers to assign a tag to the input and output events according to their content. When an input event has a string field called type whose value is net, then it is #NetData. When an input event has a field called message, then it is a #TJobMsg. The output events tagged as #testresult, #lowavg and #highavg are output to the websocket, over which The TJob will be listening for events.

The Monitoring Machine at the file sessiondef.txt is the following:

pred isnet := e.tag(#NetData) /\ e.strmatch(containerName, "nginx")

stream bool lowstarted := e.strmatch(message, "STARTING FIRST DOWNLOAD")
stream bool lowended := e.strmatch(message, "STARTING SECOND DOWNLOAD")
stream bool highstarted := e.strmatch(message, "STARTING SECOND DOWNLOAD")
stream bool highended:= e.strmatch(message, "FINISHIN SECOND DOWNLOAD")
stream bool tjobfinished := e.strmatch(message, "FINISHING TEST")

stream num outBandwidth := if isnet then e.getnum(net.txBytes_ps)

stream bool low_is_running := Once lowstarted /\ ~Once lowended
stream bool high_is_running := Once highstarted /\ ~Once highended

stream num avgbwlow := avg(outBandwidth within low_is_running)
stream num avgbwhigh := avg(outBandwidth within high_is_running)

stream bool testcorrect := Once low_is_running /\ Once high_is_running /\ avgbwhigh * 0.8 > avgbwlow

trigger tjobfinished do emit avgbwlow on #lowavg
trigger tjobfinished do emit avgbwhigh on #highavg
trigger tjobfinished do emit testcorrect on #testresult

In this Monitoring Machine,

  • The predicate isnet filters the events containing information about the net.
  • The boolean streams lowstarted/ended indicate when the period of only one download starts and ends.
  • The boolean streams highstarted/ended indicate when the period of two downloads in parallel starts and ends.
  • The boolean stream tjobfinised indicates that the test is over.
  • The numeric stream outBandwidth extracts the bandwidth usage from a specific field in the event.
  • The boolean stream low_is_running indicates that only one download is being performed.
  • The boolean stream high_is_running indicates that two downloads are being performed in parallel.
  • The numeric stream avgbwlow calculates the average bandwidth when there is only one download.
  • The numeric stream avgbwhigh calculates the average bandwidth when there are two downloads in parallel.
  • The boolean stream testcorrect assesses that (a) there was a low bandwidth period, (b) there was a high bandwidth period, and (c), the average bandwidth during two parallel downloads is greater than (almost) the double of the bandwidth consumed by a single download.
  • Finally, the trigger clause emits the result of testcorrect over the channel #testresult when the TJob is over.

After the initialization phase, the TJob connects to the Elastest Monitoring Service websocket endpoint and proceeds to perform the downloads, printing a message beteween the different stages. This can be seen in the main TJob routine:

go DownloadFile(fileUrl)
time.Sleep(60 * time.Second)
go DownloadFile(fileUrl)
time.Sleep(60 * time.Second)
time.Sleep(5 * time.Second)
fmt.Println("FINISHING TEST")

Then, the TJob checks the value of the event received over the channel #testresult and exits with a success or fail code accordingly. The code of the Go program is designed to stress the System under Test, while all the numeric computation and property assessment is carried out in the Monitoring Service.

We have generated a Docker image for the TJob, and published at imdeasoftware/e2etjob:1.2. The configuration for the TJob at ElasTest is as follows:

  • TJob name: Double bandwidth
  • Current SuT: Select nginx
  • Environment Docker Image: imdeasoftware/e2etjob:1.2
  • Commands:

    cd /go;./tjob
  • Test Support Services: Check EMS

The TJob configuration should look like this:

And, of course, we have to make sure that the EMS checkbox is checked:

After some minutes, we should see that the test passes, which means that nginx behaves as expected: