From 5f79badaf357b6a0cd5625edb5a6ef314c612d4c Mon Sep 17 00:00:00 2001 From: charlyautomatiza Date: Sun, 21 Jul 2024 22:02:56 -0300 Subject: [PATCH] feat: :sparkles: performance 360 - workshop k6 --- .github/workflows/k6-runner.yml | 13 ++ .gitignore | 2 + README.md | 165 ++++++++++++++++- data/users.csv | 101 +++++++++++ data/users.json | 304 ++++++++++++++++++++++++++++++++ src/01-shared-iterations.js | 21 +++ src/02-per-vu-iterations.js | 21 +++ src/03-constant-vus.js | 20 +++ src/04-ramping-vus.js | 23 +++ src/05-constant-arrival-rate.js | 24 +++ src/06-ramping-arrival-rate.js | 29 +++ src/07-externally-controlled.js | 16 ++ src/browser.js | 43 +++++ src/checks.js | 18 ++ src/csv.js | 51 ++++++ src/json.js | 51 ++++++ src/options.js | 12 ++ src/sample.js | 24 +++ src/script.js | 7 + src/stages.js | 16 ++ src/thresholds.js | 23 +++ 21 files changed, 983 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/k6-runner.yml create mode 100644 .gitignore create mode 100644 data/users.csv create mode 100644 data/users.json create mode 100644 src/01-shared-iterations.js create mode 100644 src/02-per-vu-iterations.js create mode 100644 src/03-constant-vus.js create mode 100644 src/04-ramping-vus.js create mode 100644 src/05-constant-arrival-rate.js create mode 100644 src/06-ramping-arrival-rate.js create mode 100644 src/07-externally-controlled.js create mode 100644 src/browser.js create mode 100644 src/checks.js create mode 100644 src/csv.js create mode 100644 src/json.js create mode 100644 src/options.js create mode 100644 src/sample.js create mode 100644 src/script.js create mode 100644 src/stages.js create mode 100644 src/thresholds.js diff --git a/.github/workflows/k6-runner.yml b/.github/workflows/k6-runner.yml new file mode 100644 index 0000000..1b026aa --- /dev/null +++ b/.github/workflows/k6-runner.yml @@ -0,0 +1,13 @@ +name: Main Workflow +on: [push] +jobs: + build: + name: Run k6 test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run k6 local test + uses: grafana/k6-action@v0.3.1 + with: + filename: ./src/thresholds.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2623dd6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.html +.vscode \ No newline at end of file diff --git a/README.md b/README.md index ce02ba6..11d1c5f 100644 --- a/README.md +++ b/README.md @@ -1 +1,164 @@ -# k6-performance-360 \ No newline at end of file +

+ Twitch + Discord + + + +

+ +# Pruebas de Performance con K6 + +Este repositorio contiene scripts de pruebas de rendimiento desarrollados con K6 y una GitHub Actions para la ejecución continua de las pruebas en CI/CD. + +## Contenido + +- [Requisitos](#requisitos) +- [Instalación](#instalación) +- [Ejecución de Pruebas](#ejecución-de-pruebas) +- [GitHub Actions](#github-actions) +- [Licencia](#licencia) + +## Requisitos + +Antes de ejecutar las pruebas, asegúrate de tener [K6](https://grafana.com/docs/k6/latest/) instalado en tu sistema. +Sigue las instrucciones en la [documentación oficial](https://grafana.com/docs/k6/latest/set-up/install-k6/). + +## Instalación + +1. Clone este repositorio en su máquina local: + +```bash +git clone https://github.com/charlyautomatiza/k6-performance-360.git +``` + +2. Navega hasta el directorio del proyecto: + +```bash +cd k6-performance-360 +``` + +## Ejecución de Pruebas + +Para realizar una ejecución local: + +```bash +k6 run ./src/script.js +``` + +Para usar K6 WebDashboard: + +```bash +K6_WEB_DASHBOARD=true k6 run ./src/script.js +``` + +Para guardar el reporte como un archivo HTML, podemos ejecutar el siguiente comando + +```bash +K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=html-report.html k6 run ./src/script.js +``` + +Para ejecutar un test de browser, podemos ejecutar el siguiente comando: + +```bash +K6_BROWSER_HEADLESS=true k6 run ./src/browser.js +``` + +Observe que la variable de ambiente `K6_BROWSER_HEADLESS` debe ser definida como `true` para ser ejecutada en herramientas de integración contínua. Para ejecución y depuración en local, es útil usar la variable con el valor definido como `false` para ejecutar el browser en primer plano. + +```bash +K6_BROWSER_HEADLESS=false k6 run ./src/browser.js +``` + +### Ejecución externa + +Para probar los ejemplos de ejecución externa deberás tener instalado un cliente http como por ejemplo [Postman](https://www.postman.com/) o [Insomnia](https://insomnia.rest/). + +**Importante**: todos los `cURLs` utilizados pueden ejecutarse desde la línea de comandos o también pueden importarse desde tu cliente de preferencia. + +#### Validar el estado de una ejecución + +Puedes utilizar una request de tipo GET mediante la API de K6 + +```powershell +curl --request GET \ + --url http://localhost:6565/v1/status \ + --header 'Content-Type: application/json' +``` + +#### Pausar una ejecución + +Puedes utilizar una request de tipo PATCH a la API de K6, similar a la siguiente + +```powershell +curl --request PATCH \ + --url http://localhost:6565/v1/status \ + --header 'Content-Type: application/json' \ + --data '{ + "data": { + "attributes": { + "paused": true + }, + "id": "default", + "type": "status" + } + }' +``` + +Se destaca lo siguiente del paso anterior: + +- `paused: true` -> pausa la ejecución. + +#### Reanudar y escalar una ejecución + +Puedes utilizar una request de tipo PATCH a la API de K6, similar a la siguiente + +```powershell +curl --request PATCH \ + --url http://localhost:6565/v1/status \ + --header 'Content-Type: application/json' \ + --data '{ + "data": { + "attributes": { + "paused": false, + "vus": 40 + }, + "id": "default", + "type": "status" + } +}' +``` + +Se destaca lo siguiente del paso anterior: + +- `paused: false` -> Reanuda la ejecución. +- `vus: 40` -> tiene que ser un valor mayor a la cantidad de VUs actual y menor o igual a la cantidad máxima de VUs definida en el script. + +#### Recomendaciones + +Este tipo de ejecución es una opción para simular carga distribuida desde múltiples generadores de , la API de K6 no proporcionará versatilidad para gestionar este tipo de ejecución desde una máquina host. + +Para el caso de que se cuente con infra propia puede ser una opción a ser considerada en combinación, por ejemplo, con el uso e implementación de herramientas como [NGROK](https://ngrok.com/) + +## GitHub Actions + +Este repositorio incluye una GitHub Actions configurada para ejecutar pruebas continuamente en el branch principal. La acción está definida en el archivo [k6-runner.yml](.github/workflows/k6-runner.yml). + +## Extensiones VSCode recomendadas + +- [Conventional Commits for VSCode](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits) + +- [GitHub Pull Requests](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github) + +- [Codeium: AI Coding](https://marketplace.visualstudio.com/items?itemName=Codeium.codeium) + +- [SonarLint](https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode) + +- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + +- [Thunder Client](https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client) + +- [Postman](https://marketplace.visualstudio.com/items?itemName=Postman.postman-for-vscode) + +## Licencia + +Este proyecto está bajo la licencia Creative Commons CC0 1.0 Universal. diff --git a/data/users.csv b/data/users.csv new file mode 100644 index 0000000..0fc994c --- /dev/null +++ b/data/users.csv @@ -0,0 +1,101 @@ +username +jlidington0 +ashapcott1 +acharnock2 +zbeggin3 +bvivyan4 +pportugal5 +ltoft6 +jfochs7 +eshilliday8 +mstandishbrooks9 +jgotobeda +dcreaseb +ggrahamec +dbarkerd +egartenfelde +srobusf +rtodarog +khatrickh +lgetheni +rheamsj +eblasiakk +slanglandl +sdeardsm +ulabatn +nosanneo +frufflip +jluneyq +tmarchellor +egees +jwalakt +khardimanu +ballingtonv +nbunfordw +ghinkensenx +bmclaey +falansz +sdenziloe10 +sgiuron11 +klarver12 +bskellorne13 +schilde14 +bpanton15 +hbrownlea16 +ageist17 +tjahndel18 +rseabon19 +kclifford1a +rlarkings1b +afenty1c +gtrythall1d +hcristofalo1e +btenwick1f +cwiggans1g +keasby1h +gcubbino1i +rbartul1j +dseverwright1k +ojeans1l +jlagne1m +jrichardes1n +zpaolinelli1o +jgavin1p +dthresher1q +dsaiz1r +falmack1s +mhedau1t +bsawart1u +cczadla1v +dtullis1w +ksemon1x +rvannikov1y +imapston1z +bmacturlough20 +egillani21 +acoffee22 +cvial23 +semmot24 +mbuffy25 +bwarmington26 +sbonsul27 +aodocherty28 +ababar29 +ipasmore2a +tkolodziej2b +cdaintree2c +cbeyne2d +tmatiebe2e +elearmouth2f +apaye2g +mbrunstan2h +fthomassen2i +kcoltman2j +tharkin2k +nlutton2l +lburker2m +lwarby2n +wcoats2o +zrooper2p +vblaker2q +aduguid2r \ No newline at end of file diff --git a/data/users.json b/data/users.json new file mode 100644 index 0000000..9223f3e --- /dev/null +++ b/data/users.json @@ -0,0 +1,304 @@ +{ + "users": [ + { + "username": "jlidington0" + }, + { + "username": "ashapcott1" + }, + { + "username": "acharnock2" + }, + { + "username": "zbeggin3" + }, + { + "username": "bvivyan4" + }, + { + "username": "pportugal5" + }, + { + "username": "ltoft6" + }, + { + "username": "jfochs7" + }, + { + "username": "eshilliday8" + }, + { + "username": "mstandishbrooks9" + }, + { + "username": "jgotobeda" + }, + { + "username": "dcreaseb" + }, + { + "username": "ggrahamec" + }, + { + "username": "dbarkerd" + }, + { + "username": "egartenfelde" + }, + { + "username": "srobusf" + }, + { + "username": "rtodarog" + }, + { + "username": "khatrickh" + }, + { + "username": "lgetheni" + }, + { + "username": "rheamsj" + }, + { + "username": "eblasiakk" + }, + { + "username": "slanglandl" + }, + { + "username": "sdeardsm" + }, + { + "username": "ulabatn" + }, + { + "username": "nosanneo" + }, + { + "username": "frufflip" + }, + { + "username": "jluneyq" + }, + { + "username": "tmarchellor" + }, + { + "username": "egees" + }, + { + "username": "jwalakt" + }, + { + "username": "khardimanu" + }, + { + "username": "ballingtonv" + }, + { + "username": "nbunfordw" + }, + { + "username": "ghinkensenx" + }, + { + "username": "bmclaey" + }, + { + "username": "falansz" + }, + { + "username": "sdenziloe10" + }, + { + "username": "sgiuron11" + }, + { + "username": "klarver12" + }, + { + "username": "bskellorne13" + }, + { + "username": "schilde14" + }, + { + "username": "bpanton15" + }, + { + "username": "hbrownlea16" + }, + { + "username": "ageist17" + }, + { + "username": "tjahndel18" + }, + { + "username": "rseabon19" + }, + { + "username": "kclifford1a" + }, + { + "username": "rlarkings1b" + }, + { + "username": "afenty1c" + }, + { + "username": "gtrythall1d" + }, + { + "username": "hcristofalo1e" + }, + { + "username": "btenwick1f" + }, + { + "username": "cwiggans1g" + }, + { + "username": "keasby1h" + }, + { + "username": "gcubbino1i" + }, + { + "username": "rbartul1j" + }, + { + "username": "dseverwright1k" + }, + { + "username": "ojeans1l" + }, + { + "username": "jlagne1m" + }, + { + "username": "jrichardes1n" + }, + { + "username": "zpaolinelli1o" + }, + { + "username": "jgavin1p" + }, + { + "username": "dthresher1q" + }, + { + "username": "dsaiz1r" + }, + { + "username": "falmack1s" + }, + { + "username": "mhedau1t" + }, + { + "username": "bsawart1u" + }, + { + "username": "cczadla1v" + }, + { + "username": "dtullis1w" + }, + { + "username": "ksemon1x" + }, + { + "username": "rvannikov1y" + }, + { + "username": "imapston1z" + }, + { + "username": "bmacturlough20" + }, + { + "username": "egillani21" + }, + { + "username": "acoffee22" + }, + { + "username": "cvial23" + }, + { + "username": "semmot24" + }, + { + "username": "mbuffy25" + }, + { + "username": "bwarmington26" + }, + { + "username": "sbonsul27" + }, + { + "username": "aodocherty28" + }, + { + "username": "ababar29" + }, + { + "username": "ipasmore2a" + }, + { + "username": "tkolodziej2b" + }, + { + "username": "cdaintree2c" + }, + { + "username": "cbeyne2d" + }, + { + "username": "tmatiebe2e" + }, + { + "username": "elearmouth2f" + }, + { + "username": "apaye2g" + }, + { + "username": "mbrunstan2h" + }, + { + "username": "fthomassen2i" + }, + { + "username": "kcoltman2j" + }, + { + "username": "tharkin2k" + }, + { + "username": "nlutton2l" + }, + { + "username": "lburker2m" + }, + { + "username": "lwarby2n" + }, + { + "username": "wcoats2o" + }, + { + "username": "zrooper2p" + }, + { + "username": "vblaker2q" + }, + { + "username": "aduguid2r" + } + ] +} \ No newline at end of file diff --git a/src/01-shared-iterations.js b/src/01-shared-iterations.js new file mode 100644 index 0000000..da6c4f1 --- /dev/null +++ b/src/01-shared-iterations.js @@ -0,0 +1,21 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'shared-iterations', + vus: 10, + iterations: 450, // ejemplo ok: 300 + maxDuration: '30s', // ejemplo ok: '45s' + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); + // El tiempo total de iteración + // es el tiempo de espera + el tiempo para finalizar la request + // Inyectamos una espera de 500ms + sleep(0.5); +} diff --git a/src/02-per-vu-iterations.js b/src/02-per-vu-iterations.js new file mode 100644 index 0000000..61298d1 --- /dev/null +++ b/src/02-per-vu-iterations.js @@ -0,0 +1,21 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'per-vu-iterations', + vus: 10, + iterations: 20, + maxDuration: '40s', + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); + // El tiempo total de iteración + // es el tiempo de espera + el tiempo para finalizar la request + // Inyectamos una espera de 500ms + sleep(0.5); +} diff --git a/src/03-constant-vus.js b/src/03-constant-vus.js new file mode 100644 index 0000000..d01eb45 --- /dev/null +++ b/src/03-constant-vus.js @@ -0,0 +1,20 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'constant-vus', + vus: 10, + duration: '30s', + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); + // El tiempo total de iteración + // es el tiempo de espera + el tiempo para finalizar la request + // Inyectamos una espera de 500ms + sleep(0.5); +} diff --git a/src/04-ramping-vus.js b/src/04-ramping-vus.js new file mode 100644 index 0000000..8dafee4 --- /dev/null +++ b/src/04-ramping-vus.js @@ -0,0 +1,23 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'ramping-vus', + startvus: 10, + stages: [ + { duration: '30s', target: 10 }, + { duration: '30s', target: 0 }, + ], + gracefulRampDown: '1s', + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); + // Añadimos sleep con mayor duración que el gracefulRampDown + // para que las iteraciones sean más largas que el rampdown + sleep(5); +} diff --git a/src/05-constant-arrival-rate.js b/src/05-constant-arrival-rate.js new file mode 100644 index 0000000..0b4fa95 --- /dev/null +++ b/src/05-constant-arrival-rate.js @@ -0,0 +1,24 @@ +import http from 'k6/http'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'constant-arrival-rate', + // Duración de la prueba + duration: '30s', + // ¿Cuántas iteraciones por timeUnit + rate: 30, + // Start `rate` iterations per second + timeUnit: '1s', + // VUs pre-establecidos antes de comenzar la prueba + preAllocatedVUs: 5, + // Máximo de 50 VUs para sostener la definida + // tasa de llegada constante. + maxVUs: 50, + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); +} diff --git a/src/06-ramping-arrival-rate.js b/src/06-ramping-arrival-rate.js new file mode 100644 index 0000000..fe6d34e --- /dev/null +++ b/src/06-ramping-arrival-rate.js @@ -0,0 +1,29 @@ +import http from 'k6/http'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'ramping-arrival-rate', + // Inicio iteraciones por `timeUnit` + startRate: 100, + // Inicia `startRate` iteraciones por minuto + timeUnit: '1m', + // Asignación previa de las VU necesarias. + preAllocatedVUs: 60, + stages: [ + // Iniciar 100 iteraciones por `timeUnit` durante el primer minuto. + { target: 100, duration: '1m' }, + // Aumenta linealmente hasta iniciar 300 iteraciones por + // `timeUnit` durante los siguientes dos minutos. + { target: 300, duration: '2m' }, + // Disminuye linealmente hasta iniciar 30 iteraciones + // por `timeUnit` en el último minuto. + { target: 30, duration: '1m' }, + ], + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); +} diff --git a/src/07-externally-controlled.js b/src/07-externally-controlled.js new file mode 100644 index 0000000..355092d --- /dev/null +++ b/src/07-externally-controlled.js @@ -0,0 +1,16 @@ +import http from 'k6/http'; + +export const options = { + scenarios: { + crocodiles: { + executor: 'externally-controlled', + vus: 10, + maxVUs: 50, + duration: '10m', + }, + }, +}; + +export default function () { + http.get('https://test-api.k6.io/public/crocodiles'); +} diff --git a/src/browser.js b/src/browser.js new file mode 100644 index 0000000..cf0a735 --- /dev/null +++ b/src/browser.js @@ -0,0 +1,43 @@ +// Para tener un browser en primer plano -> K6_BROWSER_HEADLESS=false +import { browser } from 'k6/browser'; +import { check } from 'k6'; + +export const options = { + scenarios: { + ui: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, + thresholds: { + checks: ['rate>0.9'], // The rate of successful checks should be higher than 90% + } +} + +export default async function () { + const context = await browser.newContext(); + const page = await context.newPage(); + + try { + await page.goto('https://test.k6.io/my_messages.php'); + + await page.locator('input[name="login"]').type('admin'); + await page.locator('input[name="password"]').type('123'); + + await Promise.all([ + page.waitForNavigation(), + page.locator('input[type="submit"]').click(), + ]); + + const header = await page.locator("h2").textContent(); + check(header, { + header: (h) => h == "Welcome, admin!", + }); + } finally { + await page.close(); + } +} diff --git a/src/checks.js b/src/checks.js new file mode 100644 index 0000000..fe44064 --- /dev/null +++ b/src/checks.js @@ -0,0 +1,18 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +export const options = { + stages: [ + { duration: '10s', target: 5 }, + { duration: '15s', target: 10 }, + { duration: '10s', target: 0 } + ], +} + +export default function () { + const res = http.get('https://test.k6.io'); + check(res, { + "response code was 200": (res) => res.status == 200, + }); + sleep(1); +} diff --git a/src/csv.js b/src/csv.js new file mode 100644 index 0000000..5fe3600 --- /dev/null +++ b/src/csv.js @@ -0,0 +1,51 @@ +import http from 'k6/http'; +import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js'; +import { SharedArray } from 'k6/data'; +import { expect, describe } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +/* + El trabajo pesado (abrir y procesar archivos grandes por ejemplo) + debe hacerse aquí. + De esta manera sólo ocurrirá una vez y el resultado será compartido + entre todas las VUs, ahorrando tiempo y memoria. +*/ + +const data = new SharedArray('users data', function (){ + return papaparse.parse(open('../data/users.csv'), { header: true }).data; +}); + +export const options = { + stages: [ + { duration: '10s', target: 1 }, + { duration: '10s', target: 20 }, + { duration: '30s', target: 20 }, + { duration: '10s', target: 1 } + ], + thresholds: { + // Errores http tienen que se menor al 1% + http_req_failed: ['rate<0.01'], + // 95% de las peticiones http tienen que responder en menos de 200ms + http_req_duration: ['p(95)<200'] + } +}; + +export default function(){ + describe('API Cocodrilos', () => { + describe('obtener lista de cocodrilos', ()=> { + const response = http.get('https://test-api.k6.io/public/crocodiles'); + + expect(response.status, 'status code').to.equal(200); + expect(response).to.have.validJsonBody(); + expect(response.json().length, 'cantidad de cocodrilos').to.be.above(0); + }); + + describe('post ejemplo', () => { + let username = data[Math.floor(Math.random() * data.length)].username; + const response = http.post('https://httpbin.test.k6.io/post', username); + + expect(response.status, 'status code').to.equal(200); + expect(response).to.have.validJsonBody(); + expect(response.json().data, 'valid username').to.be.equal(username); + }) + }); +} diff --git a/src/json.js b/src/json.js new file mode 100644 index 0000000..78b5d20 --- /dev/null +++ b/src/json.js @@ -0,0 +1,51 @@ +import http from 'k6/http'; +import { expect, describe } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; +import { SharedArray } from 'k6/data'; + +/* + El trabajo pesado (abrir y procesar archivos grandes por ejemplo) + debe hacerse aquí. + De esta manera sólo ocurrirá una vez y el resultado será compartido + entre todas las VUs, ahorrando tiempo y memoria. +*/ + +const data = new SharedArray('input data', function (){ + return JSON.parse(open('../data/users.json')).users; +}); + +export const options = { + stages: [ + { duration: '10s', target: 1 }, + { duration: '10s', target: 20 }, + { duration: '30s', target: 20 }, + { duration: '10s', target: 1 } + ], + thresholds: { + // Errores http tienen que se menor al 1% + http_req_failed: ['rate<0.01'], + // 95% de las peticiones http tienen que responder en menos de 200ms + http_req_duration: ['p(95)<200'] + } +}; + +export default function(){ + describe('API Cocodrilos', () => { + describe('obtener lista de cocodrilos', ()=> { + const response = http.get('https://test-api.k6.io/public/crocodiles'); + + expect(response.status, 'status code').to.equal(200); + expect(response).to.have.validJsonBody(); + expect(response.json().length, 'cantidad de cocodrilos').to.be.above(0); + }); + + describe('post ejemplo', () => { + let username = data[Math.floor(Math.random() * data.length)].username; + + const response = http.post('https://httpbin.test.k6.io/post', username); + + expect(response.status, 'status code').to.equal(200); + expect(response).to.have.validJsonBody(); + expect(response.json().data, 'valid username').to.be.equal(username); + }) + }); +} diff --git a/src/options.js b/src/options.js new file mode 100644 index 0000000..54ab0c2 --- /dev/null +++ b/src/options.js @@ -0,0 +1,12 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + vus: 25, + duration: '50s', +}; + +export default function () { + http.get('https://test.k6.io'); + sleep(1); +} diff --git a/src/sample.js b/src/sample.js new file mode 100644 index 0000000..4b775c3 --- /dev/null +++ b/src/sample.js @@ -0,0 +1,24 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + discardresponsebodies: true, + scenarios: { + contacts: { + executor: 'ramping-vus', + startvus: 10, + stages: [ + { duration: '30s', target: 10 }, + { duration: '30s', target: 0 }, + ], + gracefulRampDown: '1s', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); + // Añadimos sleep con mayor duración que el gracefulRampDown + // para que las iteraciones sean más largas que el rampdown + sleep(5); +} diff --git a/src/script.js b/src/script.js new file mode 100644 index 0000000..f0baf70 --- /dev/null +++ b/src/script.js @@ -0,0 +1,7 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export default function () { + http.get('https://test.k6.io'); + sleep(1); +} diff --git a/src/stages.js b/src/stages.js new file mode 100644 index 0000000..0af4c2d --- /dev/null +++ b/src/stages.js @@ -0,0 +1,16 @@ +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + stages: [ + { duration: '10s', target: 10 }, + { duration: '15s', target: 10 }, + { duration: '10s', target: 30 }, + { duration: '10s', target: 0 } + ] +} + +export default function () { + http.get('https://test.k6.io'); + sleep(1); +} diff --git a/src/thresholds.js b/src/thresholds.js new file mode 100644 index 0000000..97d2565 --- /dev/null +++ b/src/thresholds.js @@ -0,0 +1,23 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +export const options = { + stages: [ + { duration: '10s', target: 5 }, + { duration: '15s', target: 10 }, + { duration: '10s', target: 0 } + ], + thresholds: { + http_req_failed: ['rate<0.01'], // http errors should be less than 1% + http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms + checks: ['rate>0.9'] // The rate of successful checks should be higher than 90% + } +} + +export default function () { + const res = http.get('https://test.k6.io'); + check(res, { + "response code was 200": (res) => res.status == 200, + }); + sleep(1); +}