prix-r9 1.0.3 → 2.0.0

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) QA Team
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,233 +1,223 @@
1
- # Prix-R9 — Pruebas de Estrés HTTP
2
-
3
- Herramienta CLI ligera para pruebas de carga y rendimiento de APIs REST. Permite realizar envíos concurrentes de alto volumen simulando usuarios simultáneos con escalado progresivo (**Ramp-Up**) e inyección de **variables dinámicas** para evitar colisiones de datos en bases de datos.
4
-
5
- ---
6
-
7
- ## Instalación
8
-
9
- ```bash
10
- npm install -g prix-r9
11
- ```
12
-
13
- ---
14
-
15
- ## Cómo Empezar
16
-
17
- ```bash
18
- prix-r9 --config mi-config.json
19
- ```
20
-
21
- Toda la configuración (URL, cabeceras, métodos y tiempos) reside dentro del archivo JSON que le pases como parámetro. Esto te permite guardar un historial de todos los servicios estresados.
22
-
23
- ---
24
-
25
- ## Importador Automático desde cURL
26
-
27
- No tienes que escribir el archivo JSON a mano. Si tienes una petición que ya funciona en **Postman, Swagger o en tu Navegador**, simplemente cópiala como formato `cURL` y la herramienta creará el JSON por ti.
28
-
29
- ```bash
30
- # 1. Guarda tu comando cURL en un archivo de texto
31
- # (Click derecho en Network tab del navegador → Copy as cURL)
32
-
33
- # 2. Convierte a config JSON
34
- prix-r9-curl -i mi-curl.txt -o casos/mi-endpoint.json
35
-
36
- # 3. Lanza la prueba
37
- prix-r9 --config casos/mi-endpoint.json
38
- ```
39
-
40
- **¿Qué hace?**
41
- - Extrae la URL y el Método HTTP automáticamente.
42
- - Extrae todas las cabeceras (Tokens, ApiKeys).
43
- - Detecta si es un envío JSON regular (`--data`) o un envío de Archivo pesado (`--form`). Si es archivo, automáticamente separa la ruta física local (`file` / `filekey`) y construye el `body` con los campos extra.
44
- - Le inyecta un **Ramp-Up predeterminado** (5 a 50 req/s en 5 segundos), listo para que lo afines.
45
-
46
- ---
47
-
48
- ## Organización por Casos de Prueba (Recomendado)
49
-
50
- Para no perder la configuración de un WebService que probaste y que podrías volver a ocupar en meses, guarda los archivos JSON divididos por carpetas:
51
-
52
- ```text
53
- mi-proyecto/
54
- └── casos/
55
- ├── modulo-usuarios/
56
- │ └── crear-usuario.json
57
- ├── modulo-reportes/
58
- │ └── generar-reporte.json
59
- └── modulo-archivos/
60
- └── upload-csv.json
61
- ```
62
-
63
- > **IMPORTANTE:** Tú y tu equipo deciden cómo nombrar las carpetas. Pueden ser por Producto, Módulo, Ambiente de QA o Sprint.
64
-
65
- ---
66
-
67
- ## Motor de Carga (Rate & Ramp-Up)
68
-
69
- La herramienta permite moldear cómo las peticiones van entrando a tu API a través del tiempo usando cuatro valores clave:
70
-
71
- * **`startRate`** (Ej: `5`): Peticiones por segundo al inicio de la prueba.
72
- * **`targetRate`** (Ej: `50`): Máximo de peticiones por segundo al que se quiere llegar.
73
- * **`rampUpTime`** (Ej: `5`): Segundos que toma escalar de `startRate` a `targetRate`.
74
- * **`duration`** (Ej: `10`): Duración total de la prueba en segundos.
75
-
76
- ### Fórmula de cálculo por segundo
77
-
78
- ```
79
- Si s < rampUpTime:
80
- rate(s) = PISO( startRate + (targetRate - startRate) * (s / rampUpTime) )
81
-
82
- Si s >= rampUpTime:
83
- rate(s) = targetRate
84
- ```
85
-
86
- **Ejemplo con `startRate: 3, targetRate: 5, rampUpTime: 10, duration: 15`:**
87
-
88
- | Segundo (s) | Fracción = s ÷ 10 | Incremento = (5-3) × fracción | rate = 3 + incremento | Redondeado |
89
- |:-----------:|:-----------------:|:-----------------------------:|:---------------------:|:----------:|
90
- | 1 | 0.1 | 0.2 | 3.2 | **3** |
91
- | 2 | 0.2 | 0.4 | 3.4 | **3** |
92
- | 3 | 0.3 | 0.6 | 3.6 | **3** |
93
- | 4 | 0.4 | 0.8 | 3.8 | **3** |
94
- | 5 | 0.5 | 1.0 | 4.0 | **4** |
95
- | 6 | 0.6 | 1.2 | 4.2 | **4** |
96
- | 7 | 0.7 | 1.4 | 4.4 | **4** |
97
- | 8 | 0.8 | 1.6 | 4.6 | **4** |
98
- | 9 | 0.9 | 1.8 | 4.8 | **4** |
99
- | 10 | 1.0 | 2.0 | 5.0 | **5** |
100
- | 11 – 15 | — | tope alcanzado | 5 pet/s × 5 seg | **25** |
101
- | **TOTAL** | | | | **62** |
102
-
103
- ---
104
-
105
- ## Variables Dinámicas `{{ }}`
106
-
107
- Para evitar colisiones por restricciones `UNIQUE` en base de datos, puedes usar variables dinámicas en el `body` y `headers`:
108
-
109
- - **`{{uuid}}`**: Cadena alfanumérica única (ej: `123e4567-e89b-12d3...`).
110
- - **`{{timestamp}}`**: Tiempo actual en milisegundos (ej: `1702939129124`).
111
- - **`{{random_number}}`**: Número aleatorio del 0 al 9999.
112
-
113
- ---
114
-
115
- ## Ejemplo 1: Carga JSON
116
-
117
- ```json
118
- {
119
- "url": "https://api.tuempresa.com/v1/usuarios",
120
- "method": "POST",
121
- "startRate": 5,
122
- "targetRate": 50,
123
- "rampUpTime": 5,
124
- "duration": 10,
125
- "headers": {
126
- "Authorization": "Bearer tu_token",
127
- "X-Request-ID": "{{uuid}}"
128
- },
129
- "body": {
130
- "id_unico": "{{uuid}}",
131
- "correo_usuario": "prueba_{{timestamp}}@empresa.com",
132
- "edad": "{{random_number}}"
133
- }
134
- }
135
- ```
136
-
137
- ---
138
-
139
- ## Ejemplo 2: Subida de Archivos (Multipart)
140
-
141
- ```json
142
- {
143
- "url": "https://api.tuempresa.com/v1/upload-foto",
144
- "method": "POST",
145
- "startRate": 2,
146
- "targetRate": 10,
147
- "rampUpTime": 2,
148
- "duration": 5,
149
- "headers": {
150
- "Authorization": "Bearer tu_token"
151
- },
152
- "file": "./foto-pesada.jpg",
153
- "filekey": "foto",
154
- "body": {
155
- "TypeFile": "1",
156
- "ReasonProcess": "Carga desde V{{random_number}}"
157
- }
158
- }
159
- ```
160
-
161
- - **`file`:** Ruta del archivo a adjuntar en cada petición.
162
- - **`filekey`:** Nombre del campo que espera el backend (el `name` del `<input type="file">`).
163
- - **`body`:** Campos extra que acompañan al archivo en el `FormData`.
164
-
165
- ---
166
-
167
- ## Métricas Generadas
168
-
169
- Al terminar la prueba se imprime un resumen y se guarda en `reporte.txt`:
170
-
171
- ```text
172
- ===========================================
173
- RESUMEN DE LA PRUEBA
174
- ===========================================
175
- Peticiones Totales : 410
176
- Conexiones Máximas : 50
177
- Rendimiento / Rate : 23.50 Req/s
178
-
179
- DESGLOSE DE RESULTADOS:
180
- Exitosas (2xx) : 410
181
- Errores Cliente (4xx): 0
182
- Errores Server (5xx): 0
183
-
184
- TIEMPOS DE RESPUESTA (Latencia en ms):
185
- Mínimo : 60.88 ms
186
- Máximo : 165.25 ms
187
- Promedio: 75.93 ms
188
- P95 : 88.99 ms
189
-
190
- CÓDIGOS DE ESTADO HTTP:
191
- [200] -> 410 veces
192
- ===========================================
193
- ```
194
-
195
- > **P95**: El 95% de las peticiones tardó igual o menos que ese tiempo.
196
- > **Rendimiento**: Throughput real (Req/s) que el servidor procesó durante toda la prueba.
197
-
198
- ---
199
-
200
- ## Template para Informe con IA
201
-
202
- El paquete incluye el archivo `promptInforme.txt`, un template profesional para generar informes técnicos de rendimiento usando cualquier IA (ChatGPT, Claude, etc.).
203
-
204
- **Cómo usarlo:**
205
- 1. Corre uno o varios escenarios de estrés con `prix-r9`
206
- 2. Copia el contenido de cada `reporte.txt` generado
207
- 3. Abre `promptInforme.txt` y pega los reportes en las secciones marcadas
208
- 4. Envía el prompt completo a tu IA preferida
209
-
210
- El informe generado incluirá: resumen ejecutivo, tabla comparativa, análisis por escenario, diagnóstico del servidor, recomendaciones y semáforo de salud del sistema.
211
-
212
- El archivo se encuentra en:
213
- ```
214
- node_modules/prix-r9/promptInforme.txt
215
- ```
216
-
217
- ---
218
-
219
- ## Referencia Rápida
220
-
221
- ```bash
222
- # Instalar globalmente
223
- npm install -g prix-r9
224
-
225
- # Convertir cURL a config JSON
226
- prix-r9-curl -i mi-curl.txt -o casos/endpoint.json
227
-
228
- # Ejecutar prueba de estrés
229
- prix-r9 --config casos/endpoint.json
230
-
231
- # Ver versión
232
- prix-r9 --version
233
- ```
1
+ # Prix-R9
2
+
3
+ CLI para pruebas de carga HTTP/REST con ramp-up, multipart y escenarios encadenados por steps.
4
+
5
+ ## Caracteristicas
6
+
7
+ - Ejecuta pruebas de carga con `rate` fijo o `startRate -> targetRate`.
8
+ - Soporta requests JSON y multipart con archivo.
9
+ - Permite escenarios encadenados dentro de una misma iteracion usando `steps`.
10
+ - Extrae valores del response JSON y los reutiliza en los siguientes steps.
11
+ - Mantiene compatibilidad con el formato legacy de un solo request.
12
+ - Genera `reporte.txt` con metricas generales del escenario y metricas por step.
13
+
14
+ ## Instalacion
15
+
16
+ ```bash
17
+ npm install -g prix-r9
18
+ ```
19
+
20
+ ## Comandos
21
+
22
+ ```bash
23
+ prix-r9 --config mi-config.json
24
+ prix-r9 --prompt
25
+ prix-r9-curl -i mi-curl.txt -o casos/mi-endpoint.json
26
+ ```
27
+
28
+ ## Flujo recomendado desde cURL
29
+
30
+ 1. Exporta cada request funcional como `cURL` desde browser, Postman o Swagger.
31
+ 2. Convierte cada cURL a un JSON base:
32
+ ```bash
33
+ prix-r9-curl -i curl-upload.txt -o upload.json
34
+ prix-r9-curl -i curl-execute.txt -o execute.json
35
+ ```
36
+ 3. Toma esos JSON generados y unelos manualmente dentro de `steps`.
37
+ 4. En el step 1 agrega `extract` con la ruta exacta del valor devuelto.
38
+ 5. En el step 2 reemplaza el valor fijo por un placeholder `{{variableExtraida}}`.
39
+ 6. Ejecuta el escenario encadenado con `prix-r9 --config escenario.json`.
40
+
41
+ El importador `prix-r9-curl` sigue generando configuraciones legacy de un solo request. Eso es intencional: sirven como bloque base para construir escenarios multi-step.
42
+
43
+ ## Variables dinamicas
44
+
45
+ Se pueden usar en `url`, `headers`, `body`, `file` y `filekey`.
46
+
47
+ - `{{uuid}}`
48
+ - `{{timestamp}}`
49
+ - `{{random_number}}`
50
+
51
+ ## Formato legacy de un request
52
+
53
+ Este formato sigue funcionando sin cambios:
54
+
55
+ ```json
56
+ {
57
+ "url": "https://api.tuempresa.com/v1/usuarios",
58
+ "method": "POST",
59
+ "startRate": 5,
60
+ "targetRate": 50,
61
+ "rampUpTime": 5,
62
+ "duration": 10,
63
+ "headers": {
64
+ "Authorization": "Bearer tu_token",
65
+ "X-Request-ID": "{{uuid}}"
66
+ },
67
+ "body": {
68
+ "id_unico": "{{uuid}}",
69
+ "correo_usuario": "prueba_{{timestamp}}@empresa.com"
70
+ }
71
+ }
72
+ ```
73
+
74
+ Internamente se normaliza como un escenario de un solo step.
75
+
76
+ ## Formato recomendado para escenarios encadenados
77
+
78
+ La forma mas simple es usar `steps` con el mismo formato que genera `prix-r9-curl`, sin obligarte a anidar `request`.
79
+
80
+ ```json
81
+ {
82
+ "name": "Carga encadenada confirmacion de pago",
83
+ "startRate": 2,
84
+ "targetRate": 5,
85
+ "rampUpTime": 5,
86
+ "duration": 10,
87
+ "steps": [
88
+ {
89
+ "name": "uploadProcess",
90
+ "url": "https://qa.miapi.com/mdl03/api/blob/uploadProcess",
91
+ "method": "post",
92
+ "headers": {
93
+ "Accept": "application/json, text/plain, */*",
94
+ "Authorization": "Bearer tu_token"
95
+ },
96
+ "file": "./Plantillas/PlantillaMovimientoManual.csv",
97
+ "filekey": "File",
98
+ "body": {
99
+ "TypeFile": "1",
100
+ "ReasonProcess": "Carga MovimientoManualV2",
101
+ "CreatedBy": "Alek Rutherford",
102
+ "TypeProcessId": "2efff14a-94cf-4928-a6a9-ad210b487205"
103
+ },
104
+ "extract": {
105
+ "uploadFileProcessId": "$.uploadFileProcessId"
106
+ }
107
+ },
108
+ {
109
+ "name": "executeLoadProcess",
110
+ "url": "https://qa.miapi.com/mdl03/api/AZ/ExecuteLoadProcess",
111
+ "method": "post",
112
+ "headers": {
113
+ "Accept": "application/json, text/plain, */*",
114
+ "Content-Type": "application/json",
115
+ "apiKey": "tu_api_key"
116
+ },
117
+ "body": {
118
+ "UploadFileProcessId": "{{uploadFileProcessId}}",
119
+ "AprovalStatus": 1,
120
+ "ApprovedBy": "Alek Rutherford"
121
+ }
122
+ }
123
+ ]
124
+ }
125
+ ```
126
+
127
+ Tambien se acepta la forma anidada con `request`, pero la forma directa suele ser mas facil de mantener cuando vienes desde cURL.
128
+
129
+ ## Reglas de ejecucion
130
+
131
+ - Cada iteracion crea su propio contexto.
132
+ - `variables` define valores iniciales opcionales por iteracion.
133
+ - `extract` guarda valores del response JSON para los steps siguientes.
134
+ - Si un step falla por HTTP, red o extraccion, la iteracion termina y los steps restantes quedan omitidos por cascade.
135
+ - En escenarios multi-step, el rate representa iteraciones por segundo.
136
+
137
+ ## Extraccion de valores
138
+
139
+ `extract` acepta un mapa `nombreVariable -> ruta`.
140
+
141
+ ```json
142
+ {
143
+ "extract": {
144
+ "uploadFileProcessId": "$.uploadFileProcessId",
145
+ "primerDetalle": "$.data[0].id"
146
+ }
147
+ }
148
+ ```
149
+
150
+ Rutas soportadas:
151
+
152
+ - `$.propiedad`
153
+ - `$.objeto.hijo`
154
+ - `$.items[0].id`
155
+ - `$['propiedad-rara']`
156
+
157
+ Las rutas son case-sensitive. Si el response trae `uploadFileProcessId`, entonces `$.UploadFileProcessId` va a fallar.
158
+
159
+ ## Multipart
160
+
161
+ Para multipart:
162
+
163
+ - define `file` con la ruta del archivo
164
+ - define `filekey` exactamente como lo espera el backend
165
+ - manda los campos extra en `body`
166
+ - no copies manualmente `Content-Type: multipart/form-data; boundary=...`; el CLI lo genera solo
167
+
168
+ Ejemplo:
169
+
170
+ ```json
171
+ {
172
+ "url": "https://api/upload",
173
+ "method": "post",
174
+ "headers": {
175
+ "Authorization": "Bearer tu_token"
176
+ },
177
+ "file": "./foto.jpg",
178
+ "filekey": "File",
179
+ "body": {
180
+ "TypeFile": "1",
181
+ "ReasonProcess": "Carga {{timestamp}}"
182
+ }
183
+ }
184
+ ```
185
+
186
+ ## Metricas generadas
187
+
188
+ Al finalizar, el CLI imprime un resumen y guarda `reporte.txt` con:
189
+
190
+ - iteraciones totales, exitosas y fallidas
191
+ - requests ejecutados
192
+ - throughput real en `iter/s` y `req/s`
193
+ - latencia por iteracion
194
+ - latencia agregada por request
195
+ - metricas por step: ejecutado, exitoso, errores, omitido por cascade, latencia y codigos de estado
196
+
197
+ ## Prompt de informe
198
+
199
+ ```bash
200
+ prix-r9 --prompt
201
+ ```
202
+
203
+ Copia `promptInforme.txt` al directorio actual. El template ya esta orientado a analizar escenarios multi-step y distinguir entre metricas por iteracion y metricas por step.
204
+
205
+ ## Publicacion en npm
206
+
207
+ Antes de publicar:
208
+
209
+ ```bash
210
+ npm run check
211
+ npm run pack:dry-run
212
+ ```
213
+
214
+ Si todo sale bien:
215
+
216
+ ```bash
217
+ npm login
218
+ npm publish --access public
219
+ ```
220
+
221
+ ## Version actual
222
+
223
+ `2.0.0`
package/import-curl.js CHANGED
@@ -5,8 +5,8 @@ const { program } = require('commander');
5
5
  const { toJsonString } = require('curlconverter');
6
6
 
7
7
  program
8
- .version('1.0.0')
9
- .description('Herramienta de importación de cURL a config.json para Pruebas de Estrés')
8
+ .version('2.0.0')
9
+ .description('Importador de cURL a config JSON base para pruebas de carga')
10
10
  .requiredOption('-i, --input <path>', 'Archivo de texto (.txt) que contiene el comando cURL crudo')
11
11
  .requiredOption('-o, --output <path>', 'Ruta de destino para el config JSON de la prueba (ej: casos/az/nuevo-endpoint.json)')
12
12
  .parse(process.argv);
@@ -105,11 +105,12 @@ try {
105
105
  fs.writeFileSync(destPath, JSON.stringify(outputConfig, null, 2), 'utf8');
106
106
 
107
107
  console.log(`✅ ¡Éxito!`);
108
- console.log(`Tu comando cURL ha sido convertido a una configuración de carga.`);
109
- console.log(`Archivo generado: ${destPath}`);
108
+ console.log(`Tu comando cURL ha sido convertido a una configuracion base de carga.`);
109
+ console.log(`Archivo base generado: ${destPath}`);
110
110
  console.log(`\nPuedes ejecutar la prueba ahora usando:`);
111
111
  console.log(`prix-r9 --config ${outputPath}`);
112
112
 
113
113
  } catch (err) {
114
114
  console.error(`💥 Error al procesar el cURL:`, err.message);
115
115
  }
116
+