automacao-core-carga-back 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/k6.cjs ADDED
@@ -0,0 +1,403 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var http = require('k6/http');
6
+ var k6 = require('k6');
7
+ var metrics = require('k6/metrics');
8
+ var sql = require('k6/x/sql');
9
+ var driver = require('k6/x/sql/driver/postgres');
10
+
11
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
+
13
+ var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
14
+ var sql__default = /*#__PURE__*/_interopDefaultLegacy(sql);
15
+ var driver__default = /*#__PURE__*/_interopDefaultLegacy(driver);
16
+
17
+ const LOGIN_URL = 'https://platform-homologx.senior.com.br/t/senior.com.br/bridge/1.0/rest/platform/authentication/actions/login';
18
+ const DURACAOLOGIN_TREND = new metrics.Trend('tempo_resposta_login');
19
+
20
+ /**
21
+ * Utilitários de autenticação k6 para a plataforma Senior.
22
+ * Funções para login e montagem de headers Bearer.
23
+ */
24
+ class K6AuthUtils {
25
+ /**
26
+ * Monta o objeto de headers com Authorization Bearer para uso nas requisições.
27
+ * @param {string} tokenId - Access token retornado pelo login
28
+ * @returns {Object} Objeto de headers com Content-Type e Authorization
29
+ * @example
30
+ * const params = K6AuthUtils.paramsHeader(token);
31
+ * http.get(url, params);
32
+ */
33
+ static paramsHeader(tokenId) {
34
+ return {
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ 'Authorization': `Bearer ${tokenId}`
38
+ }
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Realiza o login na plataforma Senior e retorna o access_token.
44
+ * Registra a duração da chamada na trend `tempo_resposta_login`.
45
+ * @param {string} inputLogin - JSON stringificado com { "username": "...", "password": "..." }
46
+ * @returns {Promise<string>} access_token para uso nas requisições autenticadas
47
+ * @example
48
+ * import { K6AuthUtils } from 'automacao-core-carga-back/k6';
49
+ *
50
+ * // Credenciais vêm do seu repositório de teste, nunca deste core.
51
+ * // k6 run -e K6_USERNAME=... -e K6_PASSWORD=... test.js
52
+ * export async function setup() {
53
+ * return await K6AuthUtils.login(JSON.stringify({
54
+ * username: __ENV.K6_USERNAME,
55
+ * password: __ENV.K6_PASSWORD,
56
+ * }));
57
+ * }
58
+ */
59
+ static async login(inputLogin) {
60
+ const headers = {
61
+ headers: {
62
+ 'Content-Type': 'application/json'
63
+ }
64
+ };
65
+ const loginRes = http__default["default"].post(LOGIN_URL, inputLogin, headers, {
66
+ tags: {
67
+ login_tag: 'login'
68
+ }
69
+ });
70
+ k6.check(loginRes, {
71
+ 'Login status code 200': r => r.status === 200
72
+ }, {
73
+ login_tag: 'login'
74
+ });
75
+ DURACAOLOGIN_TREND.add(loginRes.timings.duration, {
76
+ login_tag: 'login'
77
+ });
78
+ const body = loginRes.json();
79
+ const bodyAccess = JSON.parse(body.jsonToken);
80
+ return bodyAccess.access_token;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Utilitários de banco de dados para testes k6.
86
+ * Encapsula abertura/fechamento de conexão Postgres e execução de queries,
87
+ * usando a extensão nativa `k6/x/sql`.
88
+ */
89
+ class K6DbUtils {
90
+ /**
91
+ * Abre uma conexão com o banco de dados Postgres.
92
+ * @param {string} connectionString - String de conexão no formato postgres://user:pass@host:port/db
93
+ * Monte a partir de variáveis de ambiente no seu repositório de teste; este
94
+ * core não guarda credenciais nem endpoints de banco.
95
+ * @returns {Object} Objeto de conexão para uso nos demais métodos
96
+ * @example
97
+ * import { K6DbUtils } from 'automacao-core-carga-back/k6';
98
+ *
99
+ * // k6 run -e DB_USER=... -e DB_PASSWORD=... -e DB_HOST=... -e DB_PORT=... -e DB_NAME=... test.js
100
+ * const CONEXAO = `postgres://${__ENV.DB_USER}:${__ENV.DB_PASSWORD}@${__ENV.DB_HOST}:${__ENV.DB_PORT}/${__ENV.DB_NAME}`;
101
+ *
102
+ * export function setup() {
103
+ * const db = K6DbUtils.abreConexao(CONEXAO);
104
+ * const resultado = K6DbUtils.pesquisa(db, 'SELECT id FROM schema.tabela LIMIT 1');
105
+ * K6DbUtils.fechaConexao(db);
106
+ * }
107
+ */
108
+ static abreConexao(connectionString) {
109
+ console.log('Iniciando conexão com o Postgres');
110
+ return sql__default["default"].open(driver__default["default"], connectionString);
111
+ }
112
+
113
+ /**
114
+ * Executa uma query SELECT no banco de dados.
115
+ * @param {Object} conexao - Conexão aberta via abreConexao
116
+ * @param {string} query - Comando SQL. Ex: 'SELECT vlrbpr FROM schema.tabela WHERE id = 1'
117
+ * @returns {Array} Resultado da query
118
+ */
119
+ static pesquisa(conexao, query) {
120
+ return conexao.query(query);
121
+ }
122
+
123
+ /**
124
+ * Converte um único valor retornado do banco de code ASCII para string.
125
+ * @param {Array} result - Resultado da query (retorno de pesquisa)
126
+ * @param {string} coluna - Nome da coluna. Ex: 'vlrbpr'
127
+ * @returns {string} Valor convertido para string
128
+ */
129
+ static converteDado(result, coluna) {
130
+ for (const row of result) {
131
+ return `${String.fromCharCode(...row[coluna])}`;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Converte um array de valores retornados do banco de code ASCII para strings.
137
+ * @param {Array} results - Resultado da query (retorno de pesquisa)
138
+ * @param {string} coluna - Nome da coluna. Ex: 'vlrbpr'
139
+ * @returns {string[]} Array de valores convertidos para string
140
+ */
141
+ static converteArrayDados(results, coluna) {
142
+ const formatado = [];
143
+ results.forEach((value, index) => {
144
+ for (let row = 1; row <= results.length; row++) {
145
+ formatado[index] = `${String.fromCharCode(...value[coluna])}`;
146
+ }
147
+ });
148
+ return formatado;
149
+ }
150
+
151
+ /**
152
+ * Fecha a conexão com o banco de dados.
153
+ * @param {Object} conexao - Conexão aberta via abreConexao
154
+ */
155
+ static fechaConexao(conexao) {
156
+ conexao.close();
157
+ console.log('Fechando conexão');
158
+ }
159
+
160
+ /**
161
+ * Executa um comando DML/DDL no banco (UPDATE, INSERT, DELETE, DROP, etc).
162
+ * @param {Object} conexao - Conexão aberta via abreConexao
163
+ * @param {string} comando - Comando SQL a ser executado
164
+ */
165
+ static executaComando(conexao, comando) {
166
+ conexao.exec(comando);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Utilitários de relatório para testes k6.
172
+ * Gera o resumo das métricas ao final do teste via handleSummary,
173
+ * produzindo um arquivo JSON que alimenta a skill de relatório de carga.
174
+ *
175
+ * @example
176
+ * import { K6ReportUtils } from 'automacao-core-carga-back/k6';
177
+ *
178
+ * export function handleSummary(data) {
179
+ * return K6ReportUtils.gerarSummary(data, { nome: 'calculaImpostos' });
180
+ * // gera: k6/imagensIA/calculaImpostos/k6calculaImpostos.json
181
+ * }
182
+ *
183
+ * Override por variáveis de ambiente:
184
+ * k6 run -e K6_JSON_DIR=imagensIA -e K6_JSON_FILE=k6meuTeste.json test.js
185
+ */
186
+ class K6ReportUtils {
187
+ /**
188
+ * @private
189
+ */
190
+ static _lerValores(data, metrica) {
191
+ if (data && data.metrics && data.metrics[metrica] && data.metrics[metrica].values) {
192
+ return data.metrics[metrica].values;
193
+ }
194
+ return {};
195
+ }
196
+
197
+ /**
198
+ * @private
199
+ */
200
+ static _arredonda(valor) {
201
+ return typeof valor === 'number' && isFinite(valor) ? Number(valor.toFixed(2)) : null;
202
+ }
203
+
204
+ /**
205
+ * @private
206
+ */
207
+ static _inteiro(valor) {
208
+ return typeof valor === 'number' && isFinite(valor) ? valor : null;
209
+ }
210
+
211
+ /**
212
+ * @private
213
+ */
214
+ static _montaLatencia(v) {
215
+ const b = {
216
+ unidade: 'ms',
217
+ avg: K6ReportUtils._arredonda(v.avg),
218
+ min: K6ReportUtils._arredonda(v.min),
219
+ med: K6ReportUtils._arredonda(v.med),
220
+ max: K6ReportUtils._arredonda(v.max)
221
+ };
222
+ b['p(90)'] = K6ReportUtils._arredonda(v['p(90)']);
223
+ b['p(95)'] = K6ReportUtils._arredonda(v['p(95)']);
224
+ return b;
225
+ }
226
+
227
+ /**
228
+ * @private
229
+ */
230
+ static _textoTerminal(r, caminho) {
231
+ const d = r.http_req_duration;
232
+ return ['', `── Resumo K6 ${r.teste ? '· ' + r.teste + ' ' : ''}──`, `duração: ${r.duracao.min} min (${r.duracao.ms} ms)`, `http_req_duration: avg=${d.avg}ms min=${d.min}ms med=${d.med}ms max=${d.max}ms p(95)=${d['p(95)']}ms`, `http_reqs: ${r.http_reqs.total} (${r.http_reqs.por_segundo}/s)`, `iterations: ${r.iterations.total}`, `taxa de erro: ${r.http_req_failed.taxa_erro_pct}%`, `JSON salvo em: ${caminho}`, ''].join('\n');
233
+ }
234
+
235
+ /**
236
+ * Gera o resumo do k6 em JSON e texto para o terminal.
237
+ * Deve ser retornado dentro da função nativa handleSummary do teste.
238
+ * @param {Object} data - Objeto de summary fornecido pelo k6 ao handleSummary
239
+ * @param {Object} [opcoes] - Opções de saída
240
+ * @param {string} [opcoes.nome] - Nome do teste (usado no nome do arquivo e no campo `teste` do JSON)
241
+ * @returns {Object} Mapa aceito pelo handleSummary: { [caminho]: jsonString, stdout: texto }
242
+ * @example
243
+ * export function handleSummary(data) {
244
+ * return K6ReportUtils.gerarSummary(data, { nome: 'baixaPagamento' });
245
+ * }
246
+ */
247
+ static gerarSummary(data, opcoes) {
248
+ const opts = opcoes || {};
249
+ const temEnv = typeof __ENV !== 'undefined' && __ENV;
250
+ const basedir = temEnv && __ENV.K6_JSON_DIR ? __ENV.K6_JSON_DIR : 'k6/imagensIA';
251
+ const dir = opts.nome ? `${basedir}/${opts.nome}` : basedir;
252
+ const nomeArquivo = temEnv && __ENV.K6_JSON_FILE ? __ENV.K6_JSON_FILE : opts.nome ? `k6${opts.nome}.json` : 'k6.json';
253
+ const caminho = `${dir}/${nomeArquivo}`;
254
+ const duracaoMs = data && data.state && typeof data.state.testRunDurationMs === 'number' ? data.state.testRunDurationMs : null;
255
+ const a = K6ReportUtils._arredonda;
256
+ const i = K6ReportUtils._inteiro;
257
+ const l = m => K6ReportUtils._lerValores(data, m);
258
+ const reqDuration = l('http_req_duration');
259
+ const reqWaiting = l('http_req_waiting');
260
+ const reqFailed = l('http_req_failed');
261
+ const httpReqs = l('http_reqs');
262
+ const iteracoes = l('iterations');
263
+ const checks = l('checks');
264
+ const vusMax = l('vus_max');
265
+ const resumo = {
266
+ gerado_em: new Date().toISOString(),
267
+ teste: opts.nome || null,
268
+ duracao: {
269
+ ms: a(duracaoMs),
270
+ min: duracaoMs !== null ? a(duracaoMs / 60000) : null
271
+ },
272
+ vus_max: i(vusMax.value),
273
+ http_req_duration: K6ReportUtils._montaLatencia(reqDuration),
274
+ http_req_waiting: K6ReportUtils._montaLatencia(reqWaiting),
275
+ http_req_failed: {
276
+ taxa_erro_pct: a((reqFailed.rate || 0) * 100),
277
+ sucessos: i(reqFailed.passes),
278
+ falhas: i(reqFailed.fails)
279
+ },
280
+ http_reqs: {
281
+ total: i(httpReqs.count),
282
+ por_segundo: a(httpReqs.rate)
283
+ },
284
+ iterations: {
285
+ total: i(iteracoes.count),
286
+ por_segundo: a(iteracoes.rate)
287
+ },
288
+ checks: {
289
+ taxa_sucesso_pct: typeof checks.rate === 'number' ? a(checks.rate * 100) : null,
290
+ passes: i(checks.passes),
291
+ falhas: i(checks.fails)
292
+ }
293
+ };
294
+ const saida = {};
295
+ saida[caminho] = JSON.stringify(resumo, null, 2);
296
+ saida.stdout = K6ReportUtils._textoTerminal(resumo, caminho);
297
+ return saida;
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Utilitários de manipulação de dados para testes k6.
303
+ * Helpers de array e cálculo usados transversalmente nos módulos.
304
+ */
305
+ class K6DataUtils {
306
+ /**
307
+ * Cria um array bidimensional a partir de um array plano.
308
+ * Útil para processar registros em lotes (ex: baixar títulos em grupos de 10).
309
+ * @param {Array} array - Array de entrada
310
+ * @param {number} tamanho - Quantidade de itens por subarray
311
+ * @returns {Array[]} Array de subarrays com `tamanho` itens cada
312
+ * @example
313
+ * import { K6DataUtils } from 'automacao-core-carga-back/k6';
314
+ *
315
+ * const titulos = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
316
+ * const lotes = K6DataUtils.criaSubArrays(titulos, 3);
317
+ * // [[1,2,3], [4,5,6], [7,8,9], [10]]
318
+ */
319
+ static criaSubArrays(array, tamanho) {
320
+ const subarrays = [];
321
+ for (let i = 0; i < array.length; i += tamanho) {
322
+ subarrays.push(array.slice(i, i + tamanho));
323
+ }
324
+ return subarrays;
325
+ }
326
+
327
+ /**
328
+ * Soma os valores de cada subarray de um array bidimensional.
329
+ * @param {Array[]} array - Array bidimensional com valores numéricos
330
+ * @returns {string[]} Array com a soma de cada subarray formatada em 2 casas decimais
331
+ * @example
332
+ * K6DataUtils.somaValores([[0, 1, 2, 3], [2, 3, 9, 8]]);
333
+ * // ['6.00', '22.00']
334
+ */
335
+ static somaValores(array) {
336
+ return array.map(sub => sub.reduce((total, valor) => total + valor, 0).toFixed(2));
337
+ }
338
+ }
339
+
340
+ const SEARCHNOTIFICATIONS_URL = 'https://platform-homologx.senior.com.br/t/senior.com.br/bridge/1.0/rest/platform/notifications/actions/searchNotifications';
341
+
342
+ /**
343
+ * Utilitários de notificações da plataforma Senior para testes k6.
344
+ * Funções para pesquisa e polling de notificações.
345
+ */
346
+ class K6NotificationsUtils {
347
+ /**
348
+ * Realiza POST no endpoint SearchNotifications.
349
+ * @param {Object|string} input - Payload da pesquisa (objeto ou JSON stringificado)
350
+ * @param {Object} params - Headers (retorno de K6AuthUtils.paramsHeader())
351
+ * @param {boolean} [fullResponse=false] - Se true, retorna o objeto Response completo;
352
+ * se false, retorna apenas o JSON da resposta
353
+ * @returns {Object|Response} Resposta da chamada
354
+ * @example
355
+ * import { K6NotificationsUtils, K6AuthUtils } from 'automacao-core-carga-back/k6';
356
+ *
357
+ * const params = K6AuthUtils.paramsHeader(token);
358
+ * const resultado = K6NotificationsUtils.pesquisar(input, params);
359
+ * console.log(resultado.listInformation.totalElements);
360
+ */
361
+ static pesquisar(input, params, fullResponse = false) {
362
+ const retorno = http__default["default"].post(SEARCHNOTIFICATIONS_URL, input, params);
363
+ if (retorno.status !== 200) {
364
+ console.log(`📥 Response: ${retorno.body}`);
365
+ }
366
+ k6.check(retorno, {
367
+ 'SearchNotifications status 200': rs => rs.status === 200
368
+ });
369
+ return fullResponse ? retorno : retorno.json();
370
+ }
371
+
372
+ /**
373
+ * Polling até que o total de notificações esperado seja atingido.
374
+ * Realiza até 100 tentativas com intervalo de 4 segundos entre cada.
375
+ * Falha o teste (fail) se a quantidade não for atingida.
376
+ * @param {Object|string} input - Payload da pesquisa
377
+ * @param {Object} params - Headers (retorno de K6AuthUtils.paramsHeader())
378
+ * @param {number} quantidadeEsperada - Total de notificações esperadas
379
+ * @returns {number} Total de notificações encontradas ao final
380
+ * @example
381
+ * const total = K6NotificationsUtils.aguardarTotal(input, params, 5);
382
+ * console.log(`Notificações recebidas: ${total}`);
383
+ */
384
+ static aguardarTotal(input, params, quantidadeEsperada) {
385
+ let quantidadeAtual = 0;
386
+ for (let tentativa = 0; tentativa < 100 && quantidadeAtual < quantidadeEsperada; tentativa++) {
387
+ const retorno = K6NotificationsUtils.pesquisar(input, params);
388
+ quantidadeAtual = retorno.listInformation.totalElements;
389
+ console.log(`Tentativa: ${tentativa} - Atual: ${quantidadeAtual} - Esperado: ${quantidadeEsperada}`);
390
+ k6.sleep(4);
391
+ if (tentativa === 99 && quantidadeAtual !== quantidadeEsperada) {
392
+ k6.fail('As notificações não foram geradas corretamente');
393
+ }
394
+ }
395
+ return quantidadeAtual;
396
+ }
397
+ }
398
+
399
+ exports.K6AuthUtils = K6AuthUtils;
400
+ exports.K6DataUtils = K6DataUtils;
401
+ exports.K6DbUtils = K6DbUtils;
402
+ exports.K6NotificationsUtils = K6NotificationsUtils;
403
+ exports.K6ReportUtils = K6ReportUtils;