Denne tutorial om performance testing med open source værktøjet JMeter, er den første i en serie af indlæg omkring brugbare værktøjer til open source udvikling. Materialet er udarbejdet af Andreas Kring, der introducerede JMeter ved en af Magentas udviklerdage. Her gav Andreas en workshop om sit arbejde med værktøjet til at teste ydeevnen for systemer baseret på frameworket Alfresco. Materialet er delt op i 3 øvelser, der når omkring mange af de fundamentale konfigurationsmuligheder for JMeter.
Installation af JMeter
Performance testing er en vigtig del af softwareudvikling og der findes en række værktøjer til dette. Heriblandt open source værktøjet JMeter, der kræver Java 8+ så installér først Java, hvis du ikke allerede har denne installeret (på Ubuntu 18.04 LTS køres eksempelvis):
$ sudo apt install openjdk-11-jdk
Derefter kan JMeter hentes på https://jmeter.apache.org/download_jmeter.cgi. Hent .tgz
filen og udpak denne – derefter burde JMeter være klar til kørsel fra mappen bin/jmeter
.
For at få en lidt højere tidsopløsning på de grafer, som JMeter genererer, skal vi lige skrue lidt på en enkelt konfiguration. I filen bin/reportgenerator.properties
ændres nedenstående property til 5000 i stedet for 60000:
jmeter.reportgenerator.overall_granularity=5000
Installering af Docker
Nedenstående applikationer kører i Docker, så hvis du ikke allerede har Docker installeret, så gør dette vha. instruktionerne her.
Øvelse 1 – oprettelse af JMeter testplan
Dette er en JMeter “Hello world” øvelse, hvor vi skal lave en Test Plan indeholdende en Thread Group, som indeholder en Simple Controller, der indeholder et enkelt Request.
Formålet er at undersøge to funktionelt identiske REST services, hvor den ene er udviklet i Python, mens den anden er skrevet i Java. De to REST services startes op på følgende måde:
Python
En Flask-applikation, som kan deployes med Docker:
$ cd docker/flask
$ docker build -t flask-app .
$ docker run --name flask-app -p 5000:5000 flask-app
Der skulle nu køre en Flask app på port 5000. App’en returnerer det n’te Fibonacci-tal vha. en rekursiv funktion (valgt bevidst, da dette går langsomt for store værdier af n). Test, at app’en fungerer ved at kalde fx:
$ curl http://localhost:5000/fib?n=7
som vil returnere det 7. Fibonacci-tal.
Java
En Spring Boot applikation, som enten kan deployes direkte med Java eller også via en Docker container på samme måde som ovenfor. Deployment direkte med Java foretages således:
$ cd docker/spring-boot
$ java -jar target/performance-testing-workshop-0.0.1-SNAPSHOT.jar
Med Docker klares det ved:
$ cd docker/spring-boot
$ docker build -t spring-boot-app .
$ docker run --name spring-boot-app -p 8080:8080 spring-boot-app
App’en kan testes ved at kalde fx:
$ curl http://localhost:8080/fib?n=7
JMeter
Start JMeter og gør følgende:
- Tilføj en Thread Group til testplanen.
- Tilføj en Simple Controller til trådgruppen.
- Tilføj et HTTP Request til controlleren og udfyld felterne efter behov.
- Tilføj et View Results Tree til trådgruppen.
- Klik på View Results Tree til højre og kør testplanen (vha. den grønne play-knap).
- Verificér, at kaldet gik godt og at de forventede data blev returneret.
- Tilføj en Timer til requestet og vælg en passende “think time”.
- Tryk på Thread Group og øg antallet af brugere. Vælg også en passende Ramp-up periode.
- Sæt Loop-Count til uendelig og sæt en Duration på fx 200 s.
- Gem testplanen og kør denne fra kommandolinjen med
$ jmeter -n -t sti/til/testplan.jmx -l log.jtl
- Generér en testrapport med
$ jmeter -g log.jtl -o report
og kig på resultatet i en browser. - Undersøg, hvilken af de to REST applikationer, som performer bedst (definér selv passende parametre for at afgøre dette – inkl. værdien af n, som fodres ind i Fibonacci-funktionen).
Et eksempel på en testplan, som kan bruges sammenligning, kan findes i mappen jmeter/ex1.jmx.
Øvelse 2 – kald til et Alfresco-system
Opsætning af en testplan, som indeholder lidt flere elementer. Vi laver nogle kald mod et standard Alfresco-system (leveres i Docker). Testplanen skal indeholde følgende elementer:
- Et Config Element, som læser en række brugere fra en CSV-fil.
- En setUp Thread Group (der kun køres en enkelt gang), som opretter brugerne fra CSV-filen i Alfresco.
- En trådgruppe indeholdende requests, der:
- Uploader et dokument med et tilfældigt navn (for at filnavne ikke skal konflikte, når man brugere uploader filer samtidigt).
- Henter dokumentet igen.
- Sletter dokumentet.
Alfresco endpoints
Her følger en kort beskrivelse af de endpoints, vi får brug for at kalde i testplanen. Ved POST requestene er der i hvert tilfælde givet et eksempel på det JSON, der skal sendes.
Oprettelse af brugere
POST /alfresco/s/api/people
{
"userName": "username",
"firstName": "firstname",
"lastName": "lastname",
"email": "username@example.org",
"password": "secret"
}
Tilføje brugere til et Alfresco site
Brugerne skal tilføjes til et site i Alfresco. Vi anvender Alfrescos standard site, som
har site short name, som er swsdp
. For at tilføje en bruger til dette site kaldes:
POST /alfresco/s/api/sites/swsdp/memberships
{
"role": "SiteManager",
"person": {
"userName":"username"
}
}
Upload af dokument
Foretages vha. et multipart/form-data POST request til
POST /alfresco/s/api/upload
hvor e.g. følgende felter sendes med i formen:
siteid=swsdp
containerid=documentLibrary
filename=someFile.txt
filedata=(binary <- selve filen)
Hente et dokument
GET /alfresco/s/api/node/content/workspace/SpacesStore/${nodeRef}
hvor ${nodeRef}
er referencen til den Alfresco node, hvor filen er gemt.
Bemærk, at denne NodeRef
returneres i ovenstående kald, hvor filen blev uploadet.
Slette et dokument
DELETE /alfresco/api/-default-/public/alfresco/versions/1/nodes/${nodeRef}
hvor ${nodeRef}
på samme måde som før er referencen til den Alfresco node,
hvor filen er gemt.
Testplanen
Gør nedenstående for at konstruere JMeter testplanen.
CSV-filen med brugere
Hent CSV-filen med brugere her.
Oprettelse af setUp Thread Group
- Start Alfresco:
$ cd docker/alfresco $ docker-compose up
Alfresco lytter nu på port 8080 på localhost. - Lav en ny JMeter testplan og sæt flueben ved feltet
Run Thread Groups consecutively
. - Tilføj et HTTP Request Defaults element (findes under Config Elements) til testplanen, og sæt værdierne for
Server Name
ogPort Number
. - Tilføj en CSV Data Set Config (også et Config Element) og brug denne til at indlæse bruger og passwords fra CSV-filen (udfyld felterne
Filename
ogVariable Names
). - Tilføj et View Results Tree til testplanen (findes under Samplers).
- Opret en setUp Thread Group, som skal oprette brugerne i CSV-filen og sæt Loop Count feltet i denne til 50 (da der er 50 brugere i CSV-filen).
- Tilføj en Simple Controller til ovenstående trådgruppe (findes under Logic Controllers).
- Tilføj en HTTP Authorization Manager til controlleren og udfyld felterne
Base URL=http://localhost:8080
),Username=admin
ogPassword=admin
. - Tilføj en HTTP Header Manager til controlleren og tilføj headeren
Content-Type: application/json
til denne. - Tilføj et HTTP Request til controlleren, som opretter en bruger via informationer i CSV-filen.
- Tilføj et HTTP Request til controlleren, som tilføjer brugeren til
swsdp
sitet i Alfresco.
Verificér, at testplanen fungerer indtil videre før vi går videre performance testing med JMeter af Alfresco.
Oprettelse af load test trådgruppen
- Tilføj en ny trådgruppe til testplanen (passende konfigrationsværdier for denne udfyldes senere, når vi har verificeret, at det hele fungerer som det skal).
- Tilføj en Simple Controller til trådgruppen.
- Tilføj en HTTP Authorization Manager til controlleren (på samme måde som før, men brug i stedet brugerne fra CSV-filen til at autentificere med denne gang i stedet for admin-brugeren.
- Tilføj et HTTP request til at uploade et dokument til Alfrescos
swsdp
site, idet følg. skal huskes:- Sæt flueben ved feltet Use multipart/form-data
- Under Parameters sættes felterne
siteid
,containerid
ogfilename
. Et tilfældigt filnavn kan genereres med JMeter funktionen${__RandomString(20,abcdefghijklmnopqrstuvxyz,randomFilename)}.doc
, som genererer en tilfældig streng, der er 20 karakterer lang (valgt fra listen af de anførte bogstaver). Værdien af strengen gemmes efterfølgende i JMeter variablenrandomFilename
, som vi kan referere til senere.
- Tilføj til requestet en Regular Expression Extractor (findes under Post Processors) og tilføj et regex, som ekstraherer NodeRef’en fra responset på requestet. Vælg et passende variablenavn, hvor den udtrukne værdi kan gemmes.
- Tilføj en Gaussian Random Timer (findes under Timers) til requestet og sæt en passende “think time”.
- Tilføj et HTTP Request til controlleren, som henter det netop uploadede dokument vha. variablen fra upload requestst.
- Tilføj et HTTP Request til controlleren, som sletter det uploadede dokument igen.
- Tilføj også passende timere til de to sidste requests.
Test af trådgruppen
Test, at kaldene i trådgruppen, fungerer (du kan evt. deaktivere setUp trådgruppen om nødvendigt).
Performance test Alfresco
Vælg passende parametre for selve “load” trådgruppen. Kør herefter en række test for at finde ud af, hvor mange samtidige brugere Alfresco kan klare i henhold til ovenstående testplan. Overvej, om der er elementer i setuppet, som kan forstyrre målingerne.
Øvelse 3 – test af request til website
Vi skal i denne øvelse kigge på JMeters mulighed for at optage requests (recording). Lad os prøve at optage de kald, som JMeter foretager, når den kontakter forsiden på https://www.magenta.dk.
Proceduren er beskrevet i JMeters officielle dokumentation her: https://jmeter.apache.org/usermanual/jmeter_proxy_step_by_step.html.
Prøv at følge trinene i guiden og se, om du kan få det til at fungere.
Bemærk: erfaringen, i forhold til performance testing med open source værktøjet JMeter, har vist at der er problemer med at få JMeter proxy’en til at fungere i Chrome, så det anbefales at bruge Firefox i denne øvelse.