Enviando notificações com xk6 notification ✉
Tags: k6, testing, performance, go
Published: 2024-04-17 00:18:50

Em ambientes de integração contínua, a comunicação e notificação efetiva dos resultados dos testes de software é de suma importância.

As notificações podem ser tanto o envio de um e-mail para canal quando uma mensagem de comunicação em um chat, ou mesmo, eventos de callback realizados via webhook.

Nesse artigo veremos como podemos utilizar o modulo xk6-notification para o disparo de notificações do resultado dos testes de performance com k6.

## Pré-requisitos📑
- K6 instalado
- xk6 configurado

## Conhecendo o xk6-notification📚

O modulo [xk6-notification](https://github.com/grafana/xk6-notification) oferece uma solução versátil para o envio de notificações via webhook, permitindo integração com uma variedade de serviços de notificação de sua escolha.

O modulo foi construido utilizando a biblioteca [shoutrrr](https://containrrr.dev/shoutrrr/v0.8/), uma lib GoLang utilizada para envio de notificações.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9s8fbxuwungquym3flfh.png)


## Instalando o xk6-notification👩‍💻
Antes de iniciar a instalação do modulo xk6-notification, é importante destacar que a configuração do xk6 deve ter sido realizada. [No artigo utilizando modulo do xk6 com k6](https://dev.to/marlo2222/utilizando-modulos-do-xk6-com-k6-4nk1) abordamos com mais detalhes essa configuração.

Com o xk6 configurado, realize o build do binário do xk6-notification utilizando o seguinte comando:

```
xk6 build --with github.com/dgzlopes/xk6-notification@latest
```


## Configurando nosso script🪛
O script abaixo executa um teste de carga na API de listagem de crocodilos do K6 por 10 segundos, empregando 5(VUs) nesse periodo. É definido um limite para o número de requisições com falha, esperando um resultado inferior a 5% do total de requisições realizadas.

```
import http from 'k6/http';
import { check } from 'k6';

export const options = {
    vus: 5,
    duration: '10s',
    thresholds: {
        http_req_failed: ['rate < 0.05'],
    }
}

export default function(){
    const BASE_URL = 'https://test-api.k6.io/public/crocodiles/';

    const res = http.get(BASE_URL);

    check(res, {
        'status code 200': (r) => r.status === 200
    });
}
```

O primeiro ajuste necessário em nosso script é na fase de inicialização, onde devemos adicionar o módulo xk6-notification. Adicionar a seguinte linha ao seu script:

```
import notification from 'k6/x/notification';
```
Após a importação do modulo, vamos incluir uma função `handleSummary` na fase de desmontagem. Nessa etapa realizaremos o envio de notificação com os resultados do teste assim que ele for concluído:

```
export function teardown(data) {
  notification.send('url', 'message');
}
```

> Observe que estamos utilizando o módulo `notification`, mais precisamente a função `send`, para o envio de mensagens. Dois argumentos são necessarios: url de destino e messagem a ser enviada.

No campo da URL, é necessário fornecer o endereço do webhook do serviço selecionado. Neste exemplo, utilizaremos um webhook para enviar mensagens para um canal no Telegram. A estrutura do webhook será a seguinte:

```
const url = `telegram://${__ENV.TOKEN}@telegram?channels=${__ENV.CANAL}`
```

> A URL do webhook precisa receber dois argumentos definidos como variaveis de ambiente. O primeiros deles é o TOKEN do seu bot criado no telegram,  o segundo, o CANAL onde a mensagem deve ser enviada.

> Caso opte por utilizar outro serviços de notificação, segue a documentação para o envio de mensagems utilizando webhook das plataformas [slack](https://api.slack.com/messaging/webhooks) e [teams](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet).

Para o conteúdo da nossa mensagem, podemos incluir todas as métricas obtidas durante o teste, as quais estão disponíveis no argumento data da função handleSummary. 

Portanto, vamos estabelecer uma função auxiliar para formatar a mensagem destinada a nossa notificação. A função terá o seguinte escopo:

```
export function format_message(data) {
    let checks = data.metrics.checks.values.fails == 0 ? '✅' : '❌';
    let thresholds = data.metrics.http_req_failed.thresholds['rate < 0.05'].ok ? '✅' : '❌';

    return `Resultado de execução do teste: 
    - Quantidade de VUs: ${data.metrics.vus.values['value']}
    - Duração total(ms): ${data.state.testRunDurationMs}
    - Iteraçoes(RPS): ${data.metrics.iterations.values['count']}
    
Req Durations(ms):
    - min: ${data.metrics.http_req_duration.values.min},
    - med: ${data.metrics.http_req_duration.values.med},
    - max: ${data.metrics.http_req_duration.values.max},
    - p(90): ${data.metrics.http_req_duration.values['p(90)']},
    - p(95): ${data.metrics.http_req_duration.values['p(95)']}
    
Checks:
    - status code 200: ${checks}
    
Thresholds: 
    - http_req_failed < 5%: ${thresholds}`
}
```

> Essa função tem como objetivo principal montar uma mensagem com algumas informações relevantes sobre o teste, além de realizar verificações nos resultados dos thresholds e checks que foram definidos.

Assim, podemos fazer as modificações necessárias na nossa função de notificação, ajustando-a para utilizar a URL que definimos para nosso webhook e a mensagem correspondente. Após todos os ajustes, o script final ficará da seguinte forma:

```
import http from 'k6/http';
import { check } from 'k6';
import notification from 'k6/x/notification';

const url = `telegram://${__ENV.TOKEN}@telegram?channels=${__ENV.CANAL}`;

export const options = {
    vus: 15,
    duration: '10s',
    thresholds: {
        http_req_failed: ['rate < 0.05'],
    }
}

export default function () {
    const BASE_URL = 'https://test-api.k6.io/public/crocodiles/';

    const res = http.get(BASE_URL);

    check(res, {
        'status code 200': (r) => r.status === 200
    });
}

export function handleSummary(data) {
    notification.send(url, format_message(data));
}

export function format_message(data) {
    let checks = data.metrics.checks.values.fails > 0 ? '✅' : '❌';
    let thresholds = data.metrics.http_req_failed.thresholds['rate < 0.05'].ok ? '✅' : '❌';

    return `Resultado de execução do teste: 
    - Quantidade de VUs: ${data.metrics.vus.values['value']}
    - Duração total(ms): ${data.state.testRunDurationMs}
    - Iteraçoes(RPS): ${data.metrics.iterations.values['count']}
    
Req Durations(ms):
    - min: ${data.metrics.http_req_duration.values.min},
    - med: ${data.metrics.http_req_duration.values.med},
    - max: ${data.metrics.http_req_duration.values.max},
    - p(90): ${data.metrics.http_req_duration.values['p(90)']},
    - p(95): ${data.metrics.http_req_duration.values['p(95)']}
    
Checks:
    - status code 200: ${checks}
    
Thresholds: 
    - http_req_failed < 5%: ${thresholds}`
}
```
 
## Executando nosso teste🚀
Antes de iniciarmos nossos testes, é crucial destacar um ponto que frequentemente gera dúvidas entre os usuários dos módulos do xk6.

Quando utilizamos o xk6 para instalar um módulo desenvolvido pela comunidade, o que obtemos é uma versão personalizada (binário) do K6 que está presente em sua máquina, além do próprio módulo que foi construído.

Se executarmos o comando `dir`, podemos observar que uma versão personalizada do K6 está disponível. Portanto, é essencial realizar a execução dos testes utilizando esta versão personalizada.

```
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        14/04/2024     16:59       37777920 k6.exe
-a----        15/04/2024     20:58           1581 script.js
```

> Comando realizado utilizando o prompt do windows.

Esclarecido esse ponto, podemos realizar a execução do nosso script utilizando o seguinte comando:

```
.\k6.exe run -e TOKEN=seu_token -e CANAL=seu_canal script.js
```
Como resultado de saida teremos:

```
          /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: script.js
     output: -

  scenarios: (100.00%) 1 scenario, 1 max VUs, 31s max duration (incl. graceful stop):
           * default: 1 looping VUs for 1s (gracefulStop: 30s)


running (01.6s), 0/1 VUs, 2 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  1s
```
A mensagem que sera enviada ao canal especificado terá a seguinte estrutura: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5umjnea5sbqupnkul7m0.png)


## Conclusão❤️
Como podemos observar, a utilização do módulo xk6 notification simplifica o processo de envio de notificações sobre os resultados dos seus testes.

No exemplo deste artigo, exploramos uma mensagem contendo apenas algumas informações do resultado do teste, acessíveis através do objeto `data`. 

Inúmeras melhorias podem ser implementadas, como a parametrização de environments em sua ferramenta de integração contínua, ou até mesmo a utilização de outros serviços, como o Slack, que oferece recursos avançados de customização de mensagens e envio via webhook.

Agradecimentos ao [Daniel González Lopes
](https://github.com/dgzlopes), pelo modulo, ajudem a manter esse projeto com uma ⭐.

Gostou do conteúdo e quer saber mais sobre testes de performance com K6? Então não deixe de conferir meu curso na Udemy:

- [Teste de performance com K6](https://www.udemy.com/course/teste-de-performance-com-k6/?referralCode=95CCD8BC9F22A2A96BDA) ✨