All the containers will be launched in order using docker compose. Check the file docker-compose.yaml to see the definition of the containers and their launch process. Here are the commands to launch the system and to turn it down:
docker-compose up
docker-compose down
Note: if you change something in the code you should rebuild the images using the --build
flag
In this step we are going to setup GitHub Actions in order to have CI in our system. The idea is that, every time we create a new release, build the system (restapi and webapp), run the tests, and if everything is ok, build the docker images and upload them to Github packages. Then we can deploy the application using these images.
The workflow for this is in lomap_en2b.yml. In this file you can see that there are two jobs, one for the restapi, one for the webapp. Jobs are executed in paralel so this will speed up our build.
So, the first to jobs in this file build the webapp and the restapi (in parallel). If everything goes well, check the e2e tests (later in this document) and if these acceptance tests pass ok, create the docker images and deploy them.
Integration tests is maybe the most difficult part to integrate in our system. We have to test the system as a whole. The idea here is to deploy the system and make the tests using jest-puppeteer (browser automatization) and jest-cucumber (user stories). We will also be using expect-puppeteer to make easier the test writing. All the structure needed is under the webapp/e2e
directory. These tests can be run locally using npm run test:e2e
and they will be run also in GitHub Actions, just after the unitary tests.
In this project the E2E testing user stories are defined using Cucumber. Cucumber uses a language called Gherkin to define the user stories. You can find the example in the features
directory. Then, the actual tests are in the folder steps
. We are going to configure jest to execute only the tests of this directory (check the jest.config.ts
file).
The E2E tests have two extra difficulties. The first one, we need a browser to perform the tests as if the user was using the application. For this matter, we use jest-peppeteer
that will launch a Chromium instance for running the tests. The browser is started in the beforeAll
function. Note that the browser is launched in a headless mode. This is neccesary for the tests to run in the CI environment. If you want to debug the tests you can always turn this feature off. The second problem is that we need to run the restapi and the webapp at the same time to be able to run the tests. For achieving this, we are going to use the package start-server-and-test
. This package, allows us to launch multiple servers and then run the tests. No need for any configuration. We can configure it straight in the package.json
file:
"test:e2e": "start-server-and-test 'npm --prefix ../restapi start' http://localhost:5000/api/users/list prod 3000 'cd e2e && jest'"
The package accepts pairs of parameters (launch a server and an URL to check if it is running. It also accepts npm commands (for instance prod, for the webapp, that will run npm run prod
). The last parameter of the task will be launching jest to run the E2E tests.
This part will be carried out using Gatling. Gatling will simulate load in our system making petitions to the webapp.
In order to use Gatling for doing the load tests in our application we need to download it. Basically, the program has two parts, a recorder to capture the actions that we want to test and a program to run this actions and get the results. Gatling will take care of capture all the response times in our requests and presenting them in quite useful graphics for its posterior analysis.
Once we have downloaded Gatling we need to start the recorder. This works as a proxy that intercepts all the actions that we make in our browser. That means that we have to configure our browser to use a proxy. We have to follow this steps:
- Configure the recorder in HTTP proxy mode.
- Configure the HTTPs mode to Certificate Authority.
- Generate a CA certificate and key. For this, press the Generate CA button. You will have to choose a folder to generate the certificates. Two pem files will be generated.
- Configure Firefox to use this CA certificate (Preferences>Certificates, import the generated certificate).
- Configure Firefox to use a proxy (Preferences>Network configuration). The proxy will be localhost:8000.
- Configure Firefox so it uses this proxy even if the call is to a local address. In order to do this, we need to set the property
network.proxy.allow_hijacking_localhost
totrue
inabout:config
.
Once we have the recorder configured, and the application running (in Heroku for instance), we can start recording our first test. We must specify a package and class name. This is just for test organization. Package will be a folder and Class name the name of the test. In my case I have used GetUsersList
without package name. After pressing start the recorder will start capturing our actions in the browser. So here you should perform all the the actions that you want to record. In my case, I opened the main website and added one user. Once we stop recording the simulation will be stored under the user-files/simulations
directory, written in Scala language. I have copied the generated file under webapp/loadtestexample
just in case you want to see how a test file in gatling looks like. Note that this simulation included a post petition to the restapi. Post data is stored under a different directory in the gattling installation directory (user-files/resources
).
We can modify our load test for instance to inject 20 users at the same time:
setUp(scn.inject(constantUsersPerSec(3).during(15))).protocols(httpProtocol)
changing it in the scala file. Check here to see more options about generating load. In order to execute the test we have to execute:
gatling.sh -s GetUsersList
In the console, we will get an overview of the results and in the results directory we will have the full report in web format.
It is important to note that we could also dockerize this load tests using this image. It is just a matter of telling the docker file where your gatling configuration and scala files are and the image will do the rest.