From 6bf413c4ce9892efa6d02f89c6dffe699c85fe57 Mon Sep 17 00:00:00 2001 From: erik Date: Mon, 13 Jul 2026 17:45:39 -0500 Subject: [PATCH] feat: Add comprehensive testing plan for IPSExtractor, including unit, integration, E2E, stress, and resilience tests. Introduce LaTeX documentation structure with sections for architecture, test strategy, and execution guidelines. Enhance README with setup instructions and k6 stress testing scripts. --- docs/plan_pruebas/README.md | 45 ++++ docs/plan_pruebas/diagrams/arquitectura.tex | 36 +++ docs/plan_pruebas/diagrams/flujo_bot.tex | 31 +++ docs/plan_pruebas/latexmkrc | 4 + docs/plan_pruebas/main.aux | 209 ++++++++++++++++++ docs/plan_pruebas/main.out | 73 ++++++ docs/plan_pruebas/main.tex | 80 +++++++ docs/plan_pruebas/main.toc | 74 +++++++ docs/plan_pruebas/preamble.tex | 110 +++++++++ docs/plan_pruebas/scripts/README.md | 49 ++++ docs/plan_pruebas/scripts/k6_bot_events.js | 66 ++++++ .../plan_pruebas/scripts/k6_bot_heartbeats.js | 67 ++++++ docs/plan_pruebas/scripts/k6_count_batches.js | 63 ++++++ .../plan_pruebas/scripts/k6_gateway_health.js | 60 +++++ .../plan_pruebas/sections/01_introduccion.tex | 55 +++++ .../plan_pruebas/sections/02_arquitectura.tex | 56 +++++ docs/plan_pruebas/sections/03_estrategia.tex | 63 ++++++ docs/plan_pruebas/sections/04_unitarias.tex | 75 +++++++ docs/plan_pruebas/sections/05_integracion.tex | 60 +++++ docs/plan_pruebas/sections/06_e2e.tex | 54 +++++ docs/plan_pruebas/sections/07_estres.tex | 90 ++++++++ docs/plan_pruebas/sections/08_resiliencia.tex | 33 +++ .../sections/09_datos_entornos.tex | 117 ++++++++++ .../sections/10_herramientas_ci.tex | 47 ++++ .../sections/11_cronograma_aceptacion.tex | 45 ++++ 25 files changed, 1662 insertions(+) create mode 100644 docs/plan_pruebas/README.md create mode 100644 docs/plan_pruebas/diagrams/arquitectura.tex create mode 100644 docs/plan_pruebas/diagrams/flujo_bot.tex create mode 100644 docs/plan_pruebas/latexmkrc create mode 100644 docs/plan_pruebas/main.aux create mode 100644 docs/plan_pruebas/main.out create mode 100644 docs/plan_pruebas/main.tex create mode 100644 docs/plan_pruebas/main.toc create mode 100644 docs/plan_pruebas/preamble.tex create mode 100644 docs/plan_pruebas/scripts/README.md create mode 100644 docs/plan_pruebas/scripts/k6_bot_events.js create mode 100644 docs/plan_pruebas/scripts/k6_bot_heartbeats.js create mode 100644 docs/plan_pruebas/scripts/k6_count_batches.js create mode 100644 docs/plan_pruebas/scripts/k6_gateway_health.js create mode 100644 docs/plan_pruebas/sections/01_introduccion.tex create mode 100644 docs/plan_pruebas/sections/02_arquitectura.tex create mode 100644 docs/plan_pruebas/sections/03_estrategia.tex create mode 100644 docs/plan_pruebas/sections/04_unitarias.tex create mode 100644 docs/plan_pruebas/sections/05_integracion.tex create mode 100644 docs/plan_pruebas/sections/06_e2e.tex create mode 100644 docs/plan_pruebas/sections/07_estres.tex create mode 100644 docs/plan_pruebas/sections/08_resiliencia.tex create mode 100644 docs/plan_pruebas/sections/09_datos_entornos.tex create mode 100644 docs/plan_pruebas/sections/10_herramientas_ci.tex create mode 100644 docs/plan_pruebas/sections/11_cronograma_aceptacion.tex diff --git a/docs/plan_pruebas/README.md b/docs/plan_pruebas/README.md new file mode 100644 index 0000000..314ff2e --- /dev/null +++ b/docs/plan_pruebas/README.md @@ -0,0 +1,45 @@ +# Plan de pruebas IPSExtractor (LaTeX) + +Documento profesional de pruebas unitarias, integración, E2E, estrés y resiliencia. + +## Requisitos + +- [TeX Live](https://www.tug.org/texlive/) o MiKTeX +- `pdflatex` (incluido en MiKTeX/TeX Live) +- Opcional: `latexmk` (requiere Perl en MiKTeX) +- Paquetes: `booktabs`, `longtable`, `hyperref`, `fancyhdr`, `geometry`, `babel`, `listings`, `tikz`, `xcolor`, `enumitem`, `siunitx`, `titlesec` + +## Compilación + +**Recomendado en Windows (MiKTeX sin Perl):** + +```powershell +cd docs\plan_pruebas +pdflatex -interaction=nonstopmode -file-line-error main.tex +pdflatex -interaction=nonstopmode -file-line-error main.tex +Copy-Item main.pdf PlanPruebas_IPSExtractor.pdf -Force +``` + +**Con latexmk** (si Perl está instalado): + +```powershell +latexmk -pdf main.tex +``` + +Artefactos: `main.pdf` y `PlanPruebas_IPSExtractor.pdf`. + +## Scripts de estrés (k6) + +Ver [`scripts/README.md`](scripts/README.md). Requiere [k6](https://k6.io/) y el stack levantado en `http://127.0.0.1:8189`. + +## Estructura + +``` +docs/plan_pruebas/ + main.tex + preamble.tex + latexmkrc + sections/ # capítulos del plan + diagrams/ # TikZ + scripts/ # k6 de referencia +``` diff --git a/docs/plan_pruebas/diagrams/arquitectura.tex b/docs/plan_pruebas/diagrams/arquitectura.tex new file mode 100644 index 0000000..6d9f6db --- /dev/null +++ b/docs/plan_pruebas/diagrams/arquitectura.tex @@ -0,0 +1,36 @@ +\begin{figure}[ht] +\centering +\begin{tikzpicture}[ + font=\small, + box/.style={draw=ipsblue, rounded corners=2pt, align=center, inner sep=4pt, minimum height=0.85cm, minimum width=2.4cm}, + ext/.style={draw=ipsgrey, dashed, rounded corners=2pt, align=center, inner sep=4pt, minimum height=0.85cm}, + arr/.style={-{Latex}, thick, ipsblue} +] + \node[box, fill=codebg] (desk) {Desktop\\Electron}; + \node[box, fill=codebg, right=1.8cm of desk] (gw) {api\_gateway\\:8189}; + \node[box, below=1.1cm of gw] (ext) {extraction\\:8001}; + \node[box, left=0.8cm of ext] (clean) {cleaning\\:8002}; + \node[box, right=0.8cm of ext] (count) {count-api\\:8080}; + \node[box, below=1.1cm of ext] (bot) {bot-descarga\\:8200}; + \node[box, below left=1.0cm and 0.2cm of bot] (pg) {PostgreSQL}; + \node[box, below right=1.0cm and 0.2cm of bot] (redis) {Redis}; + \node[ext, left=1.6cm of desk] (agent) {Agent PC\\Selenium}; + \node[ext, below=2.6cm of agent] (minio) {MinIO/S3}; + \node[ext, below=0.9cm of minio] (img) {Imaging}; + + \draw[arr] (desk) -- (gw); + \draw[arr] (gw) -- (ext); + \draw[arr] (gw) -- (clean); + \draw[arr] (gw) -- (count); + \draw[arr] (gw) -- (bot); + \draw[arr] (bot) -- (pg); + \draw[arr] (ext) -- (pg); + \draw[arr] (ext) -- (redis); + \draw[arr] (agent) |- (gw); + \draw[arr] (agent) -- (minio); + \draw[arr] (bot) -| (minio); + \draw[arr] (agent) -- (img); +\end{tikzpicture} +\caption{Arquitectura IPSExtractor bajo prueba.} +\label{fig:arquitectura} +\end{figure} diff --git a/docs/plan_pruebas/diagrams/flujo_bot.tex b/docs/plan_pruebas/diagrams/flujo_bot.tex new file mode 100644 index 0000000..107174c --- /dev/null +++ b/docs/plan_pruebas/diagrams/flujo_bot.tex @@ -0,0 +1,31 @@ +\begin{figure}[ht] +\centering +\begin{tikzpicture}[ + font=\footnotesize, + actor/.style={draw=ipsblue, rounded corners=2pt, align=center, minimum width=1.7cm, minimum height=0.7cm, fill=codebg}, + msg/.style={-{Latex}, thick}, + note/.style={align=left, font=\scriptsize\color{ipsgrey}} +] + \node[actor] (d) {Desktop}; + \node[actor, right=1.5cm of d] (g) {Gateway}; + \node[actor, right=1.5cm of g] (a) {API bot}; + \node[actor, right=1.5cm of a] (w) {Agent}; + \node[actor, right=1.5cm of w] (m) {MinIO}; + + \coordinate (top) at ($(d.south)+(0,-0.35)$); + \foreach \n in {d,g,a,w,m} { + \draw[ipsgrey!60] (\n.south) -- ++(0,-5.6); + } + + \draw[msg] ($(w.south)+(0,-0.5)$) -- node[above,font=\scriptsize]{register + heartbeat} ($(a.south)+(0,-0.5)$); + \draw[msg] ($(d.south)+(0,-1.3)$) -- node[above,font=\scriptsize]{POST /jobs (Excel)} ($(a.south)+(0,-1.3)$); + \draw[msg] ($(a.south)+(0,-2.0)$) -- node[above,font=\scriptsize]{PutObject Excel} ($(m.south)+(0,-2.0)$); + \draw[msg] ($(w.south)+(0,-2.7)$) -- node[above,font=\scriptsize]{claim\_pending} ($(a.south)+(0,-2.7)$); + \draw[msg] ($(w.south)+(0,-3.4)$) -- node[above,font=\scriptsize]{GET Excel / Put PDFs} ($(m.south)+(0,-3.4)$); + \draw[msg] ($(w.south)+(0,-4.1)$) -- node[above,font=\scriptsize]{POST events} ($(a.south)+(0,-4.1)$); + \draw[msg] ($(w.south)+(0,-4.8)$) -- node[above,font=\scriptsize]{PATCH completed} ($(a.south)+(0,-4.8)$); + \draw[msg] ($(d.south)+(0,-5.4)$) -- node[above,font=\scriptsize]{poll job + files} ($(a.south)+(0,-5.4)$); +\end{tikzpicture} +\caption{Secuencia del flujo bot de descarga.} +\label{fig:flujo-bot} +\end{figure} diff --git a/docs/plan_pruebas/latexmkrc b/docs/plan_pruebas/latexmkrc new file mode 100644 index 0000000..cee9185 --- /dev/null +++ b/docs/plan_pruebas/latexmkrc @@ -0,0 +1,4 @@ +$pdf_mode = 1; +$interaction = 'nonstopmode'; +$pdflatex = 'pdflatex -interaction=nonstopmode -file-line-error %O %S'; +$clean_ext = 'synctex.gz nav snm vrb bbl blg run.xml'; diff --git a/docs/plan_pruebas/main.aux b/docs/plan_pruebas/main.aux new file mode 100644 index 0000000..9184434 --- /dev/null +++ b/docs/plan_pruebas/main.aux @@ -0,0 +1,209 @@ +\relax +\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo } +\@nameuse{bbl@beforestart} +\catcode `"\active +\catcode `<\active +\catcode `>\active +\@nameuse{es@quoting} +\providecommand\hyper@newdestlabel[2]{} +\providecommand\HyField@AuxAddToFields[1]{} +\providecommand\HyField@AuxAddToCoFields[2]{} +\babel@aux{spanish}{} +\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introducci\'on}{6}{chapter.1}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:intro}{{1}{6}{Introducci\'on}{chapter.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {1.1}Objetivo}{6}{section.1.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {1.2}Alcance}{6}{section.1.2}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Dentro de alcance}{6}{subsection.1.2.1}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Fuera de alcance de esta versi\'on documental}{6}{subsection.1.2.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {1.3}Estado actual del repositorio}{6}{section.1.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {1.4}Referencias del sistema}{6}{section.1.4}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {1.1}{\ignorespaces Cobertura existente y gaps.}}{7}{table.1.1}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {2}Arquitectura bajo prueba}{8}{chapter.2}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:arquitectura}{{2}{8}{Arquitectura bajo prueba}{chapter.2}{}} +\@writefile{toc}{\contentsline {section}{\numberline {2.1}Vista de componentes}{8}{section.2.1}\protected@file@percent } +\@writefile{lof}{\contentsline {figure}{\numberline {2.1}{\ignorespaces Arquitectura IPSExtractor bajo prueba.}}{8}{figure.2.1}\protected@file@percent } +\newlabel{fig:arquitectura}{{2.1}{8}{Arquitectura IPSExtractor bajo prueba}{figure.2.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {2.2}Inventario de componentes}{8}{section.2.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {2.3}Flujo cr\'itico: bot de descarga}{8}{section.2.3}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {2.1}{\ignorespaces Componentes del sistema bajo prueba.}}{9}{table.2.1}\protected@file@percent } +\@writefile{lof}{\contentsline {figure}{\numberline {2.2}{\ignorespaces Secuencia del flujo bot de descarga.}}{9}{figure.2.2}\protected@file@percent } +\newlabel{fig:flujo-bot}{{2.2}{9}{Secuencia del flujo bot de descarga}{figure.2.2}{}} +\@writefile{lol}{\contentsline {lstlisting}{\numberline {2.1}Prefijos MinIO del bot}{9}{lstlisting.2.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {2.4}Otros flujos de negocio}{9}{section.2.4}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {3}Estrategia de pruebas}{10}{chapter.3}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:estrategia}{{3}{10}{Estrategia de pruebas}{chapter.3}{}} +\@writefile{toc}{\contentsline {section}{\numberline {3.1}Pir\'amide}{10}{section.3.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {3.1}{\ignorespaces Pir\'amide de pruebas IPSExtractor.}}{10}{table.3.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {3.2}Convenci\'on de identificadores}{10}{section.3.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {3.3}Entornos}{10}{section.3.3}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {3.2}{\ignorespaces TC = Testcontainers; LS = LocalStack.}}{11}{table.3.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {3.4}Mocks vs sistemas reales}{11}{section.3.4}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {3.5}Principios}{11}{section.3.5}\protected@file@percent } +\gdef \LT@i {\LT@entry + {2}{74.28644pt}\LT@entry + {1}{131.50148pt}\LT@entry + {1}{162.49014pt}} +\gdef \LT@ii {\LT@entry + {1}{79.97733pt}\LT@entry + {1}{125.81102pt}\LT@entry + {1}{162.49014pt}} +\@writefile{toc}{\contentsline {chapter}{\numberline {4}Pruebas unitarias}{12}{chapter.4}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:unitarias}{{4}{12}{Pruebas unitarias}{chapter.4}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4.1}Gateway}{12}{section.4.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {4.1}{Unitarias gateway.}}{12}{table.4.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {4.2}Bot-descarga API (\texttt {JobStore})}{12}{section.4.2}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {4.2}{Unitarias bot-descarga API.}}{12}{table.4.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {4.3}Agent bot (PC)}{12}{section.4.3}\protected@file@percent } +\gdef \LT@iii {\LT@entry + {1}{79.97733pt}\LT@entry + {1}{125.81102pt}\LT@entry + {1}{162.49014pt}} +\gdef \LT@iv {\LT@entry + {1}{79.97733pt}\LT@entry + {1}{131.50148pt}\LT@entry + {1}{156.79968pt}} +\@writefile{lot}{\contentsline {table}{\numberline {4.3}{Unitarias agent.}}{13}{table.4.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {4.4}Extraction / Cleaning / Count / Desktop}{13}{section.4.4}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {4.4}{Unitarias resto de servicios.}}{13}{table.4.4}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {4.5}Comandos de ejecuci\'on}{13}{section.4.5}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {4.1}Suite unitaria r\'apida}{13}{lstlisting.4.1}\protected@file@percent } +\gdef \LT@v {\LT@entry + {1}{74.28644pt}\LT@entry + {1}{131.50148pt}\LT@entry + {1}{162.49014pt}} +\gdef \LT@vi {\LT@entry + {1}{79.97733pt}\LT@entry + {1}{140.0374pt}\LT@entry + {1}{148.26378pt}} +\@writefile{toc}{\contentsline {chapter}{\numberline {5}Pruebas de integraci\'on}{14}{chapter.5}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:integracion}{{5}{14}{Pruebas de integraci\'on}{chapter.5}{}} +\@writefile{toc}{\contentsline {section}{\numberline {5.1}Stack de integraci\'on}{14}{section.5.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {5.2}Gateway}{14}{section.5.2}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {5.1}{Integraci\'on gateway.}}{14}{table.5.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {5.3}Bot-descarga}{14}{section.5.3}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {5.2}{Integraci\'on bot-descarga.}}{14}{table.5.2}\protected@file@percent } +\gdef \LT@vii {\LT@entry + {1}{79.97733pt}\LT@entry + {1}{140.0374pt}\LT@entry + {1}{148.26378pt}} +\@writefile{toc}{\contentsline {section}{\numberline {5.4}Extraction / Cleaning / Count}{15}{section.5.4}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {5.3}{Integraci\'on extraction, cleaning, count y BD.}}{15}{table.5.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {5.5}Smoke m\'inimo post-compose}{15}{section.5.5}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {5.1}Smoke health}{15}{lstlisting.5.1}\protected@file@percent } +\gdef \LT@viii {\LT@entry + {1}{57.21504pt}\LT@entry + {1}{91.6678pt}\LT@entry + {1}{154.26378pt}\LT@entry + {1}{91.35826pt}} +\@writefile{toc}{\contentsline {chapter}{\numberline {6}Pruebas end-to-end}{16}{chapter.6}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:e2e}{{6}{16}{Pruebas end-to-end}{chapter.6}{}} +\@writefile{toc}{\contentsline {section}{\numberline {6.1}Matriz de flujos de negocio}{16}{section.6.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {6.1}{Casos E2E cr\'iticos.}}{16}{table.6.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {6.2}Detalle E2E-05 (bot descarga)}{16}{section.6.2}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.1}Precondiciones}{16}{subsection.6.2.1}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.2}Pasos}{17}{subsection.6.2.2}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.3}Asserts}{17}{subsection.6.2.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {6.3}Desktop}{17}{section.6.3}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {7}Pruebas de estr\'es y carga}{18}{chapter.7}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:estres}{{7}{18}{Pruebas de estr\'es y carga}{chapter.7}{}} +\@writefile{toc}{\contentsline {section}{\numberline {7.1}Herramienta}{18}{section.7.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {7.2}Perfiles de carga}{18}{section.7.2}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {7.1}{\ignorespaces Cargas por perfil de entorno.}}{18}{table.7.1}\protected@file@percent } +\newlabel{tab:perfiles-carga}{{7.1}{18}{Cargas por perfil de entorno}{table.7.1}{}} +\@writefile{toc}{\contentsline {section}{\numberline {7.3}Escenarios (cat\'alogo completo)}{18}{section.7.3}\protected@file@percent } +\gdef \LT@ix {\LT@entry + {1}{74.28644pt}\LT@entry + {1}{103.04872pt}\LT@entry + {1}{111.58464pt}\LT@entry + {1}{97.04872pt}} +\@writefile{lot}{\contentsline {table}{\numberline {7.2}{Escenarios de estr\'es.}}{19}{table.7.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {7.4}Scripts k6 incluidos}{19}{section.7.4}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {7.3}{\ignorespaces Mapeo script $\leftrightarrow $ escenario.}}{19}{table.7.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {7.5}SLOs de aceptaci\'on}{19}{section.7.5}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {7.5.1}Perfil host-compartido-8gb (default)}{19}{subsection.7.5.1}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {7.5.2}Perfil laboratorio}{20}{subsection.7.5.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {7.6}Ejecuci\'on ejemplo}{20}{section.7.6}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {7.1}Estr\'es gateway en host compartido}{20}{lstlisting.7.1}\protected@file@percent } +\gdef \LT@x {\LT@entry + {1}{57.21504pt}\LT@entry + {1}{111.58464pt}\LT@entry + {1}{125.81102pt}\LT@entry + {1}{97.04872pt}} +\@writefile{toc}{\contentsline {chapter}{\numberline {8}Resiliencia y chaos}{21}{chapter.8}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:resiliencia}{{8}{21}{Resiliencia y chaos}{chapter.8}{}} +\@writefile{toc}{\contentsline {section}{\numberline {8.1}Objetivo}{21}{section.8.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {8.2}Casos}{21}{section.8.2}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {8.1}{Casos de resiliencia.}}{21}{table.8.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {8.3}Modos de fallo conocidos (bot)}{21}{section.8.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {8.4}Criterio global}{22}{section.8.4}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {9}Datos de prueba y entornos}{23}{chapter.9}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:datos}{{9}{23}{Datos de prueba y entornos}{chapter.9}{}} +\@writefile{toc}{\contentsline {section}{\numberline {9.1}Host donde se ejecutan las pruebas}{23}{section.9.1}\protected@file@percent } +\newlabel{sec:host-pruebas}{{9.1}{23}{Host donde se ejecutan las pruebas}{section.9.1}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.1}Hardware y sistema}{23}{subsection.9.1.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {9.1}{\ignorespaces Host de pruebas IPSExtractor (staging compartido).}}{23}{table.9.1}\protected@file@percent } +\newlabel{tab:host-pruebas}{{9.1}{23}{Host de pruebas IPSExtractor (staging compartido)}{table.9.1}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.2}Stack IPSExtractor observado (idle)}{23}{subsection.9.1.2}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {9.1}Smoke del gateway en el host}{23}{lstlisting.9.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {9.2}{\ignorespaces Huella de memoria IPSExtractor en idle.}}{24}{table.9.2}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.3}Carga concurrente del host (no IPS)}{24}{subsection.9.1.3}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.4}Requisitos previos a una campa\~na de estr\'es}{24}{subsection.9.1.4}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {9.2}Fixtures recomendadas}{24}{section.9.2}\protected@file@percent } +\gdef \LT@xi {\LT@entry + {1}{125.50148pt}\LT@entry + {1}{233.62204pt}} +\@writefile{toc}{\contentsline {section}{\numberline {9.3}Variables de entorno relevantes}{25}{section.9.3}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {9.3}{Variables cr\'iticas para pruebas.}}{25}{table.9.3}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {9.4}Seguridad en entornos de prueba}{25}{section.9.4}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {10}Herramientas profesionales y CI}{26}{chapter.10}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:herramientas}{{10}{26}{Herramientas profesionales y CI}{chapter.10}{}} +\@writefile{toc}{\contentsline {section}{\numberline {10.1}Stack de tooling}{26}{section.10.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {10.1}{\ignorespaces Herramientas profesionales adoptadas.}}{26}{table.10.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {10.2}Pipeline CI objetivo (no implementado en esta entrega)}{26}{section.10.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {10.3}Compilar este documento}{26}{section.10.3}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {10.1}latexmk}{26}{lstlisting.10.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {10.4}Prioridad de implementaci\'on de tests (ROI)}{27}{section.10.4}\protected@file@percent } +\gdef \LT@xii {\LT@entry + {1}{48.67912pt}\LT@entry + {1}{140.0374pt}\LT@entry + {1}{182.407pt}} +\@writefile{toc}{\contentsline {chapter}{\numberline {11}Cronograma y criterios de aceptaci\'on}{28}{chapter.11}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\newlabel{ch:cronograma}{{11}{28}{Cronograma y criterios de aceptaci\'on}{chapter.11}{}} +\@writefile{toc}{\contentsline {section}{\numberline {11.1}Fases sugeridas}{28}{section.11.1}\protected@file@percent } +\@writefile{lot}{\contentsline {table}{\numberline {11.1}{Hoja de ruta de calidad.}}{28}{table.11.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {11.2}Definition of Done por release}{28}{section.11.2}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {11.3}Plantilla de informe de ejecuci\'on}{28}{section.11.3}\protected@file@percent } +\@writefile{lol}{\contentsline {lstlisting}{\numberline {11.1}Campos m\'inimos del informe}{28}{lstlisting.11.1}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {11.4}Responsables (roles)}{29}{section.11.4}\protected@file@percent } +\@writefile{toc}{\contentsline {chapter}{\numberline {A}Glosario}{30}{appendix.Alph1}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\@writefile{toc}{\contentsline {chapter}{\numberline {B}Checklist de release}{31}{appendix.Alph2}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\@writefile{toc}{\contentsline {chapter}{\numberline {C}Mapa de rutas relevantes}{32}{appendix.Alph3}\protected@file@percent } +\@writefile{lof}{\addvspace {10\p@ }} +\@writefile{lot}{\addvspace {10\p@ }} +\gdef \@abspage@last{33} diff --git a/docs/plan_pruebas/main.out b/docs/plan_pruebas/main.out new file mode 100644 index 0000000..f07c198 --- /dev/null +++ b/docs/plan_pruebas/main.out @@ -0,0 +1,73 @@ +\BOOKMARK [0][-]{chapter.1}{\376\377\000I\000n\000t\000r\000o\000d\000u\000c\000c\000i\000\363\000n}{}% 1 +\BOOKMARK [1][-]{section.1.1}{\376\377\000O\000b\000j\000e\000t\000i\000v\000o}{chapter.1}% 2 +\BOOKMARK [1][-]{section.1.2}{\376\377\000A\000l\000c\000a\000n\000c\000e}{chapter.1}% 3 +\BOOKMARK [2][-]{subsection.1.2.1}{\376\377\000D\000e\000n\000t\000r\000o\000\040\000d\000e\000\040\000a\000l\000c\000a\000n\000c\000e}{section.1.2}% 4 +\BOOKMARK [2][-]{subsection.1.2.2}{\376\377\000F\000u\000e\000r\000a\000\040\000d\000e\000\040\000a\000l\000c\000a\000n\000c\000e\000\040\000d\000e\000\040\000e\000s\000t\000a\000\040\000v\000e\000r\000s\000i\000\363\000n\000\040\000d\000o\000c\000u\000m\000e\000n\000t\000a\000l}{section.1.2}% 5 +\BOOKMARK [1][-]{section.1.3}{\376\377\000E\000s\000t\000a\000d\000o\000\040\000a\000c\000t\000u\000a\000l\000\040\000d\000e\000l\000\040\000r\000e\000p\000o\000s\000i\000t\000o\000r\000i\000o}{chapter.1}% 6 +\BOOKMARK [1][-]{section.1.4}{\376\377\000R\000e\000f\000e\000r\000e\000n\000c\000i\000a\000s\000\040\000d\000e\000l\000\040\000s\000i\000s\000t\000e\000m\000a}{chapter.1}% 7 +\BOOKMARK [0][-]{chapter.2}{\376\377\000A\000r\000q\000u\000i\000t\000e\000c\000t\000u\000r\000a\000\040\000b\000a\000j\000o\000\040\000p\000r\000u\000e\000b\000a}{}% 8 +\BOOKMARK [1][-]{section.2.1}{\376\377\000V\000i\000s\000t\000a\000\040\000d\000e\000\040\000c\000o\000m\000p\000o\000n\000e\000n\000t\000e\000s}{chapter.2}% 9 +\BOOKMARK [1][-]{section.2.2}{\376\377\000I\000n\000v\000e\000n\000t\000a\000r\000i\000o\000\040\000d\000e\000\040\000c\000o\000m\000p\000o\000n\000e\000n\000t\000e\000s}{chapter.2}% 10 +\BOOKMARK [1][-]{section.2.3}{\376\377\000F\000l\000u\000j\000o\000\040\000c\000r\000\355\000t\000i\000c\000o\000:\000\040\000b\000o\000t\000\040\000d\000e\000\040\000d\000e\000s\000c\000a\000r\000g\000a}{chapter.2}% 11 +\BOOKMARK [1][-]{section.2.4}{\376\377\000O\000t\000r\000o\000s\000\040\000f\000l\000u\000j\000o\000s\000\040\000d\000e\000\040\000n\000e\000g\000o\000c\000i\000o}{chapter.2}% 12 +\BOOKMARK [0][-]{chapter.3}{\376\377\000E\000s\000t\000r\000a\000t\000e\000g\000i\000a\000\040\000d\000e\000\040\000p\000r\000u\000e\000b\000a\000s}{}% 13 +\BOOKMARK [1][-]{section.3.1}{\376\377\000P\000i\000r\000\341\000m\000i\000d\000e}{chapter.3}% 14 +\BOOKMARK [1][-]{section.3.2}{\376\377\000C\000o\000n\000v\000e\000n\000c\000i\000\363\000n\000\040\000d\000e\000\040\000i\000d\000e\000n\000t\000i\000f\000i\000c\000a\000d\000o\000r\000e\000s}{chapter.3}% 15 +\BOOKMARK [1][-]{section.3.3}{\376\377\000E\000n\000t\000o\000r\000n\000o\000s}{chapter.3}% 16 +\BOOKMARK [1][-]{section.3.4}{\376\377\000M\000o\000c\000k\000s\000\040\000v\000s\000\040\000s\000i\000s\000t\000e\000m\000a\000s\000\040\000r\000e\000a\000l\000e\000s}{chapter.3}% 17 +\BOOKMARK [1][-]{section.3.5}{\376\377\000P\000r\000i\000n\000c\000i\000p\000i\000o\000s}{chapter.3}% 18 +\BOOKMARK [0][-]{chapter.4}{\376\377\000P\000r\000u\000e\000b\000a\000s\000\040\000u\000n\000i\000t\000a\000r\000i\000a\000s}{}% 19 +\BOOKMARK [1][-]{section.4.1}{\376\377\000G\000a\000t\000e\000w\000a\000y}{chapter.4}% 20 +\BOOKMARK [1][-]{section.4.2}{\376\377\000B\000o\000t\000-\000d\000e\000s\000c\000a\000r\000g\000a\000\040\000A\000P\000I\000\040\000\050\000J\000o\000b\000S\000t\000o\000r\000e\000\051}{chapter.4}% 21 +\BOOKMARK [1][-]{section.4.3}{\376\377\000A\000g\000e\000n\000t\000\040\000b\000o\000t\000\040\000\050\000P\000C\000\051}{chapter.4}% 22 +\BOOKMARK [1][-]{section.4.4}{\376\377\000E\000x\000t\000r\000a\000c\000t\000i\000o\000n\000\040\000/\000\040\000C\000l\000e\000a\000n\000i\000n\000g\000\040\000/\000\040\000C\000o\000u\000n\000t\000\040\000/\000\040\000D\000e\000s\000k\000t\000o\000p}{chapter.4}% 23 +\BOOKMARK [1][-]{section.4.5}{\376\377\000C\000o\000m\000a\000n\000d\000o\000s\000\040\000d\000e\000\040\000e\000j\000e\000c\000u\000c\000i\000\363\000n}{chapter.4}% 24 +\BOOKMARK [0][-]{chapter.5}{\376\377\000P\000r\000u\000e\000b\000a\000s\000\040\000d\000e\000\040\000i\000n\000t\000e\000g\000r\000a\000c\000i\000\363\000n}{}% 25 +\BOOKMARK [1][-]{section.5.1}{\376\377\000S\000t\000a\000c\000k\000\040\000d\000e\000\040\000i\000n\000t\000e\000g\000r\000a\000c\000i\000\363\000n}{chapter.5}% 26 +\BOOKMARK [1][-]{section.5.2}{\376\377\000G\000a\000t\000e\000w\000a\000y}{chapter.5}% 27 +\BOOKMARK [1][-]{section.5.3}{\376\377\000B\000o\000t\000-\000d\000e\000s\000c\000a\000r\000g\000a}{chapter.5}% 28 +\BOOKMARK [1][-]{section.5.4}{\376\377\000E\000x\000t\000r\000a\000c\000t\000i\000o\000n\000\040\000/\000\040\000C\000l\000e\000a\000n\000i\000n\000g\000\040\000/\000\040\000C\000o\000u\000n\000t}{chapter.5}% 29 +\BOOKMARK [1][-]{section.5.5}{\376\377\000S\000m\000o\000k\000e\000\040\000m\000\355\000n\000i\000m\000o\000\040\000p\000o\000s\000t\000-\000c\000o\000m\000p\000o\000s\000e}{chapter.5}% 30 +\BOOKMARK [0][-]{chapter.6}{\376\377\000P\000r\000u\000e\000b\000a\000s\000\040\000e\000n\000d\000-\000t\000o\000-\000e\000n\000d}{}% 31 +\BOOKMARK [1][-]{section.6.1}{\376\377\000M\000a\000t\000r\000i\000z\000\040\000d\000e\000\040\000f\000l\000u\000j\000o\000s\000\040\000d\000e\000\040\000n\000e\000g\000o\000c\000i\000o}{chapter.6}% 32 +\BOOKMARK [1][-]{section.6.2}{\376\377\000D\000e\000t\000a\000l\000l\000e\000\040\000E\0002\000E\000-\0000\0005\000\040\000\050\000b\000o\000t\000\040\000d\000e\000s\000c\000a\000r\000g\000a\000\051}{chapter.6}% 33 +\BOOKMARK [2][-]{subsection.6.2.1}{\376\377\000P\000r\000e\000c\000o\000n\000d\000i\000c\000i\000o\000n\000e\000s}{section.6.2}% 34 +\BOOKMARK [2][-]{subsection.6.2.2}{\376\377\000P\000a\000s\000o\000s}{section.6.2}% 35 +\BOOKMARK [2][-]{subsection.6.2.3}{\376\377\000A\000s\000s\000e\000r\000t\000s}{section.6.2}% 36 +\BOOKMARK [1][-]{section.6.3}{\376\377\000D\000e\000s\000k\000t\000o\000p}{chapter.6}% 37 +\BOOKMARK [0][-]{chapter.7}{\376\377\000P\000r\000u\000e\000b\000a\000s\000\040\000d\000e\000\040\000e\000s\000t\000r\000\351\000s\000\040\000y\000\040\000c\000a\000r\000g\000a}{}% 38 +\BOOKMARK [1][-]{section.7.1}{\376\377\000H\000e\000r\000r\000a\000m\000i\000e\000n\000t\000a}{chapter.7}% 39 +\BOOKMARK [1][-]{section.7.2}{\376\377\000P\000e\000r\000f\000i\000l\000e\000s\000\040\000d\000e\000\040\000c\000a\000r\000g\000a}{chapter.7}% 40 +\BOOKMARK [1][-]{section.7.3}{\376\377\000E\000s\000c\000e\000n\000a\000r\000i\000o\000s\000\040\000\050\000c\000a\000t\000\341\000l\000o\000g\000o\000\040\000c\000o\000m\000p\000l\000e\000t\000o\000\051}{chapter.7}% 41 +\BOOKMARK [1][-]{section.7.4}{\376\377\000S\000c\000r\000i\000p\000t\000s\000\040\000k\0006\000\040\000i\000n\000c\000l\000u\000i\000d\000o\000s}{chapter.7}% 42 +\BOOKMARK [1][-]{section.7.5}{\376\377\000S\000L\000O\000s\000\040\000d\000e\000\040\000a\000c\000e\000p\000t\000a\000c\000i\000\363\000n}{chapter.7}% 43 +\BOOKMARK [2][-]{subsection.7.5.1}{\376\377\000P\000e\000r\000f\000i\000l\000\040\000h\000o\000s\000t\000-\000c\000o\000m\000p\000a\000r\000t\000i\000d\000o\000-\0008\000g\000b\000\040\000\050\000d\000e\000f\000a\000u\000l\000t\000\051}{section.7.5}% 44 +\BOOKMARK [2][-]{subsection.7.5.2}{\376\377\000P\000e\000r\000f\000i\000l\000\040\000l\000a\000b\000o\000r\000a\000t\000o\000r\000i\000o}{section.7.5}% 45 +\BOOKMARK [1][-]{section.7.6}{\376\377\000E\000j\000e\000c\000u\000c\000i\000\363\000n\000\040\000e\000j\000e\000m\000p\000l\000o}{chapter.7}% 46 +\BOOKMARK [0][-]{chapter.8}{\376\377\000R\000e\000s\000i\000l\000i\000e\000n\000c\000i\000a\000\040\000y\000\040\000c\000h\000a\000o\000s}{}% 47 +\BOOKMARK [1][-]{section.8.1}{\376\377\000O\000b\000j\000e\000t\000i\000v\000o}{chapter.8}% 48 +\BOOKMARK [1][-]{section.8.2}{\376\377\000C\000a\000s\000o\000s}{chapter.8}% 49 +\BOOKMARK [1][-]{section.8.3}{\376\377\000M\000o\000d\000o\000s\000\040\000d\000e\000\040\000f\000a\000l\000l\000o\000\040\000c\000o\000n\000o\000c\000i\000d\000o\000s\000\040\000\050\000b\000o\000t\000\051}{chapter.8}% 50 +\BOOKMARK [1][-]{section.8.4}{\376\377\000C\000r\000i\000t\000e\000r\000i\000o\000\040\000g\000l\000o\000b\000a\000l}{chapter.8}% 51 +\BOOKMARK [0][-]{chapter.9}{\376\377\000D\000a\000t\000o\000s\000\040\000d\000e\000\040\000p\000r\000u\000e\000b\000a\000\040\000y\000\040\000e\000n\000t\000o\000r\000n\000o\000s}{}% 52 +\BOOKMARK [1][-]{section.9.1}{\376\377\000H\000o\000s\000t\000\040\000d\000o\000n\000d\000e\000\040\000s\000e\000\040\000e\000j\000e\000c\000u\000t\000a\000n\000\040\000l\000a\000s\000\040\000p\000r\000u\000e\000b\000a\000s}{chapter.9}% 53 +\BOOKMARK [2][-]{subsection.9.1.1}{\376\377\000H\000a\000r\000d\000w\000a\000r\000e\000\040\000y\000\040\000s\000i\000s\000t\000e\000m\000a}{section.9.1}% 54 +\BOOKMARK [2][-]{subsection.9.1.2}{\376\377\000S\000t\000a\000c\000k\000\040\000I\000P\000S\000E\000x\000t\000r\000a\000c\000t\000o\000r\000\040\000o\000b\000s\000e\000r\000v\000a\000d\000o\000\040\000\050\000i\000d\000l\000e\000\051}{section.9.1}% 55 +\BOOKMARK [2][-]{subsection.9.1.3}{\376\377\000C\000a\000r\000g\000a\000\040\000c\000o\000n\000c\000u\000r\000r\000e\000n\000t\000e\000\040\000d\000e\000l\000\040\000h\000o\000s\000t\000\040\000\050\000n\000o\000\040\000I\000P\000S\000\051}{section.9.1}% 56 +\BOOKMARK [2][-]{subsection.9.1.4}{\376\377\000R\000e\000q\000u\000i\000s\000i\000t\000o\000s\000\040\000p\000r\000e\000v\000i\000o\000s\000\040\000a\000\040\000u\000n\000a\000\040\000c\000a\000m\000p\000a\000\361\000a\000\040\000d\000e\000\040\000e\000s\000t\000r\000\351\000s}{section.9.1}% 57 +\BOOKMARK [1][-]{section.9.2}{\376\377\000F\000i\000x\000t\000u\000r\000e\000s\000\040\000r\000e\000c\000o\000m\000e\000n\000d\000a\000d\000a\000s}{chapter.9}% 58 +\BOOKMARK [1][-]{section.9.3}{\376\377\000V\000a\000r\000i\000a\000b\000l\000e\000s\000\040\000d\000e\000\040\000e\000n\000t\000o\000r\000n\000o\000\040\000r\000e\000l\000e\000v\000a\000n\000t\000e\000s}{chapter.9}% 59 +\BOOKMARK [1][-]{section.9.4}{\376\377\000S\000e\000g\000u\000r\000i\000d\000a\000d\000\040\000e\000n\000\040\000e\000n\000t\000o\000r\000n\000o\000s\000\040\000d\000e\000\040\000p\000r\000u\000e\000b\000a}{chapter.9}% 60 +\BOOKMARK [0][-]{chapter.10}{\376\377\000H\000e\000r\000r\000a\000m\000i\000e\000n\000t\000a\000s\000\040\000p\000r\000o\000f\000e\000s\000i\000o\000n\000a\000l\000e\000s\000\040\000y\000\040\000C\000I}{}% 61 +\BOOKMARK [1][-]{section.10.1}{\376\377\000S\000t\000a\000c\000k\000\040\000d\000e\000\040\000t\000o\000o\000l\000i\000n\000g}{chapter.10}% 62 +\BOOKMARK [1][-]{section.10.2}{\376\377\000P\000i\000p\000e\000l\000i\000n\000e\000\040\000C\000I\000\040\000o\000b\000j\000e\000t\000i\000v\000o\000\040\000\050\000n\000o\000\040\000i\000m\000p\000l\000e\000m\000e\000n\000t\000a\000d\000o\000\040\000e\000n\000\040\000e\000s\000t\000a\000\040\000e\000n\000t\000r\000e\000g\000a\000\051}{chapter.10}% 63 +\BOOKMARK [1][-]{section.10.3}{\376\377\000C\000o\000m\000p\000i\000l\000a\000r\000\040\000e\000s\000t\000e\000\040\000d\000o\000c\000u\000m\000e\000n\000t\000o}{chapter.10}% 64 +\BOOKMARK [1][-]{section.10.4}{\376\377\000P\000r\000i\000o\000r\000i\000d\000a\000d\000\040\000d\000e\000\040\000i\000m\000p\000l\000e\000m\000e\000n\000t\000a\000c\000i\000\363\000n\000\040\000d\000e\000\040\000t\000e\000s\000t\000s\000\040\000\050\000R\000O\000I\000\051}{chapter.10}% 65 +\BOOKMARK [0][-]{chapter.11}{\376\377\000C\000r\000o\000n\000o\000g\000r\000a\000m\000a\000\040\000y\000\040\000c\000r\000i\000t\000e\000r\000i\000o\000s\000\040\000d\000e\000\040\000a\000c\000e\000p\000t\000a\000c\000i\000\363\000n}{}% 66 +\BOOKMARK [1][-]{section.11.1}{\376\377\000F\000a\000s\000e\000s\000\040\000s\000u\000g\000e\000r\000i\000d\000a\000s}{chapter.11}% 67 +\BOOKMARK [1][-]{section.11.2}{\376\377\000D\000e\000f\000i\000n\000i\000t\000i\000o\000n\000\040\000o\000f\000\040\000D\000o\000n\000e\000\040\000p\000o\000r\000\040\000r\000e\000l\000e\000a\000s\000e}{chapter.11}% 68 +\BOOKMARK [1][-]{section.11.3}{\376\377\000P\000l\000a\000n\000t\000i\000l\000l\000a\000\040\000d\000e\000\040\000i\000n\000f\000o\000r\000m\000e\000\040\000d\000e\000\040\000e\000j\000e\000c\000u\000c\000i\000\363\000n}{chapter.11}% 69 +\BOOKMARK [1][-]{section.11.4}{\376\377\000R\000e\000s\000p\000o\000n\000s\000a\000b\000l\000e\000s\000\040\000\050\000r\000o\000l\000e\000s\000\051}{chapter.11}% 70 +\BOOKMARK [0][-]{appendix.Alph1}{\376\377\000G\000l\000o\000s\000a\000r\000i\000o}{}% 71 +\BOOKMARK [0][-]{appendix.Alph2}{\376\377\000C\000h\000e\000c\000k\000l\000i\000s\000t\000\040\000d\000e\000\040\000r\000e\000l\000e\000a\000s\000e}{}% 72 +\BOOKMARK [0][-]{appendix.Alph3}{\376\377\000M\000a\000p\000a\000\040\000d\000e\000\040\000r\000u\000t\000a\000s\000\040\000r\000e\000l\000e\000v\000a\000n\000t\000e\000s}{}% 73 diff --git a/docs/plan_pruebas/main.tex b/docs/plan_pruebas/main.tex new file mode 100644 index 0000000..dc0ee16 --- /dev/null +++ b/docs/plan_pruebas/main.tex @@ -0,0 +1,80 @@ +\documentclass[11pt,a4paper,oneside]{report} + +\input{preamble} + +\begin{document} + +\makecover + +\chapter*{Control de cambios} +\begin{tabularx}{\textwidth}{@{}l l X@{}} +\toprule +\textbf{Versi\'on} & \textbf{Fecha} & \textbf{Descripci\'on} \\ +\midrule +1.0.0 & 13 jul 2026 & Versi\'on inicial del plan de pruebas y estr\'es. \\ +1.1.0 & 13 jul 2026 & Entorno real de ejecuci\'on (host Ubuntu compartido 8\,GiB) y perfiles de carga. \\ +\bottomrule +\end{tabularx} + +\chapter*{Resumen ejecutivo} +Este documento define la estrategia y la matriz de pruebas del monorepo \textbf{IPSExtractor}: API Gateway, extraction/workers ARQ, cleaning, count-api (Go), bot-descarga (API + agent Selenium), PostgreSQL, Redis, MinIO y la aplicaci\'on de escritorio. + +Hoy el repositorio cuenta principalmente con pruebas unitarias aisladas; no existe pipeline CI, ni suites de integraci\'on/E2E automatizadas. Este plan cierra ese gap con identificadores trazables (\texttt{UT-*}, \texttt{IT-*}, \texttt{E2E-*}, \texttt{ST-*}, \texttt{CH-*}), SLOs medibles y scripts \textbf{k6} de referencia en \texttt{docs/plan\_pruebas/scripts/}. + +\textbf{Importante:} las pruebas de integraci\'on, humo y estr\'es documentadas contra el stack vivo se ejecutan (o se ejecutar\'an) en el host descrito en la secci\'on~\ref{sec:host-pruebas} (laptop Ubuntu 24.04, 8\,GiB RAM, Docker compartido con MLflow, Airflow, n8n, etc.). Los resultados deben interpretarse en ese contexto: un OOM o p95 alto puede deberse a contenci\'on del host, no solo a IPSExtractor. + +\tableofcontents +\clearpage + +\input{sections/01_introduccion} +\input{sections/02_arquitectura} +\input{sections/03_estrategia} +\input{sections/04_unitarias} +\input{sections/05_integracion} +\input{sections/06_e2e} +\input{sections/07_estres} +\input{sections/08_resiliencia} +\input{sections/09_datos_entornos} +\input{sections/10_herramientas_ci} +\input{sections/11_cronograma_aceptacion} + +\appendix +\chapter{Glosario} +\begin{description}[style=nextline,leftmargin=2.2cm,labelwidth=2cm] + \item[ARQ] Cola as\'incrona de workers de extracci\'on sobre Redis. + \item[Claim] Operaci\'on at\'omica que asigna un job \texttt{pending} a un worker. + \item[Gateway] \texttt{api\_gateway}, \'unica puerta HTTP expuesta en el host (:8189). + \item[Imaging] Portal web automatizado por Selenium en el PC del bot. + \item[k6] Herramienta profesional de pruebas de carga (Grafana Labs). + \item[MinIO] Almacenamiento S3-compatible para Excel y PDFs del bot. + \item[SLO] Objetivo de nivel de servicio (latencia, error rate, etc.). +\end{description} + +\chapter{Checklist de release} +\begin{enumerate} + \item Unitarios verdes: bots, bot-descarga store, Vitest, \texttt{go test}. + \item Migraciones Alembic en BD limpia (0001--0004). + \item Smoke Compose: \texttt{GET /health/live} y \texttt{GET /health}. + \item E2E-01 a E2E-05 ejecutados en staging (E2E-05 con agent real si hay Imaging). + \item Al menos ST-GW-01, ST-BOT-01, ST-COUNT-01 y ST-EXT-01 con umbrales cumplidos. + \item Informe: p95, error rate, picos RAM, jobs fallidos, costos LLM. + \item \textbf{Entorno citado:} hostname, \texttt{free -h}, \texttt{docker stats}, perfil k6 (\texttt{shared8g}/\texttt{lab}). + \item Sin secretos hardcodeados en compose para entornos de prueba. +\end{enumerate} + +\chapter{Mapa de rutas relevantes} +\section*{Gateway (\texttt{:8189})} +\begin{itemize} + \item \texttt{GET /health/live}, \texttt{GET /health} + \item Proxy: \texttt{/tasks/*}, \texttt{/cleaning/*}, \texttt{/count/*}, \texttt{/bot-descarga/*} + \item Timeout JSON 30\,s; uploads (incl.\ \texttt{POST /bot-descarga/jobs}) 600\,s +\end{itemize} + +\section*{Bot-descarga API (\texttt{:8200}, v\'ia gateway)} +\begin{itemize} + \item Workers: \texttt{POST /workers/register}, \texttt{POST /workers/heartbeat} + \item Workers: \texttt{GET /workers}, \texttt{GET /workers/me/pending} + \item Jobs: \texttt{POST /jobs}, \texttt{GET/PATCH /jobs/\{id\}}, events, cancel, file, files MinIO +\end{itemize} + +\end{document} diff --git a/docs/plan_pruebas/main.toc b/docs/plan_pruebas/main.toc new file mode 100644 index 0000000..1642060 --- /dev/null +++ b/docs/plan_pruebas/main.toc @@ -0,0 +1,74 @@ +\babel@toc {spanish}{}\relax +\contentsline {chapter}{\numberline {1}Introducci\'on}{6}{chapter.1}% +\contentsline {section}{\numberline {1.1}Objetivo}{6}{section.1.1}% +\contentsline {section}{\numberline {1.2}Alcance}{6}{section.1.2}% +\contentsline {subsection}{\numberline {1.2.1}Dentro de alcance}{6}{subsection.1.2.1}% +\contentsline {subsection}{\numberline {1.2.2}Fuera de alcance de esta versi\'on documental}{6}{subsection.1.2.2}% +\contentsline {section}{\numberline {1.3}Estado actual del repositorio}{6}{section.1.3}% +\contentsline {section}{\numberline {1.4}Referencias del sistema}{6}{section.1.4}% +\contentsline {chapter}{\numberline {2}Arquitectura bajo prueba}{8}{chapter.2}% +\contentsline {section}{\numberline {2.1}Vista de componentes}{8}{section.2.1}% +\contentsline {section}{\numberline {2.2}Inventario de componentes}{8}{section.2.2}% +\contentsline {section}{\numberline {2.3}Flujo cr\'itico: bot de descarga}{8}{section.2.3}% +\contentsline {section}{\numberline {2.4}Otros flujos de negocio}{9}{section.2.4}% +\contentsline {chapter}{\numberline {3}Estrategia de pruebas}{10}{chapter.3}% +\contentsline {section}{\numberline {3.1}Pir\'amide}{10}{section.3.1}% +\contentsline {section}{\numberline {3.2}Convenci\'on de identificadores}{10}{section.3.2}% +\contentsline {section}{\numberline {3.3}Entornos}{10}{section.3.3}% +\contentsline {section}{\numberline {3.4}Mocks vs sistemas reales}{11}{section.3.4}% +\contentsline {section}{\numberline {3.5}Principios}{11}{section.3.5}% +\contentsline {chapter}{\numberline {4}Pruebas unitarias}{12}{chapter.4}% +\contentsline {section}{\numberline {4.1}Gateway}{12}{section.4.1}% +\contentsline {section}{\numberline {4.2}Bot-descarga API (\texttt {JobStore})}{12}{section.4.2}% +\contentsline {section}{\numberline {4.3}Agent bot (PC)}{12}{section.4.3}% +\contentsline {section}{\numberline {4.4}Extraction / Cleaning / Count / Desktop}{13}{section.4.4}% +\contentsline {section}{\numberline {4.5}Comandos de ejecuci\'on}{13}{section.4.5}% +\contentsline {chapter}{\numberline {5}Pruebas de integraci\'on}{14}{chapter.5}% +\contentsline {section}{\numberline {5.1}Stack de integraci\'on}{14}{section.5.1}% +\contentsline {section}{\numberline {5.2}Gateway}{14}{section.5.2}% +\contentsline {section}{\numberline {5.3}Bot-descarga}{14}{section.5.3}% +\contentsline {section}{\numberline {5.4}Extraction / Cleaning / Count}{15}{section.5.4}% +\contentsline {section}{\numberline {5.5}Smoke m\'inimo post-compose}{15}{section.5.5}% +\contentsline {chapter}{\numberline {6}Pruebas end-to-end}{16}{chapter.6}% +\contentsline {section}{\numberline {6.1}Matriz de flujos de negocio}{16}{section.6.1}% +\contentsline {section}{\numberline {6.2}Detalle E2E-05 (bot descarga)}{16}{section.6.2}% +\contentsline {subsection}{\numberline {6.2.1}Precondiciones}{16}{subsection.6.2.1}% +\contentsline {subsection}{\numberline {6.2.2}Pasos}{17}{subsection.6.2.2}% +\contentsline {subsection}{\numberline {6.2.3}Asserts}{17}{subsection.6.2.3}% +\contentsline {section}{\numberline {6.3}Desktop}{17}{section.6.3}% +\contentsline {chapter}{\numberline {7}Pruebas de estr\'es y carga}{18}{chapter.7}% +\contentsline {section}{\numberline {7.1}Herramienta}{18}{section.7.1}% +\contentsline {section}{\numberline {7.2}Perfiles de carga}{18}{section.7.2}% +\contentsline {section}{\numberline {7.3}Escenarios (cat\'alogo completo)}{18}{section.7.3}% +\contentsline {section}{\numberline {7.4}Scripts k6 incluidos}{19}{section.7.4}% +\contentsline {section}{\numberline {7.5}SLOs de aceptaci\'on}{19}{section.7.5}% +\contentsline {subsection}{\numberline {7.5.1}Perfil host-compartido-8gb (default)}{19}{subsection.7.5.1}% +\contentsline {subsection}{\numberline {7.5.2}Perfil laboratorio}{20}{subsection.7.5.2}% +\contentsline {section}{\numberline {7.6}Ejecuci\'on ejemplo}{20}{section.7.6}% +\contentsline {chapter}{\numberline {8}Resiliencia y chaos}{21}{chapter.8}% +\contentsline {section}{\numberline {8.1}Objetivo}{21}{section.8.1}% +\contentsline {section}{\numberline {8.2}Casos}{21}{section.8.2}% +\contentsline {section}{\numberline {8.3}Modos de fallo conocidos (bot)}{21}{section.8.3}% +\contentsline {section}{\numberline {8.4}Criterio global}{22}{section.8.4}% +\contentsline {chapter}{\numberline {9}Datos de prueba y entornos}{23}{chapter.9}% +\contentsline {section}{\numberline {9.1}Host donde se ejecutan las pruebas}{23}{section.9.1}% +\contentsline {subsection}{\numberline {9.1.1}Hardware y sistema}{23}{subsection.9.1.1}% +\contentsline {subsection}{\numberline {9.1.2}Stack IPSExtractor observado (idle)}{23}{subsection.9.1.2}% +\contentsline {subsection}{\numberline {9.1.3}Carga concurrente del host (no IPS)}{24}{subsection.9.1.3}% +\contentsline {subsection}{\numberline {9.1.4}Requisitos previos a una campa\~na de estr\'es}{24}{subsection.9.1.4}% +\contentsline {section}{\numberline {9.2}Fixtures recomendadas}{24}{section.9.2}% +\contentsline {section}{\numberline {9.3}Variables de entorno relevantes}{25}{section.9.3}% +\contentsline {section}{\numberline {9.4}Seguridad en entornos de prueba}{25}{section.9.4}% +\contentsline {chapter}{\numberline {10}Herramientas profesionales y CI}{26}{chapter.10}% +\contentsline {section}{\numberline {10.1}Stack de tooling}{26}{section.10.1}% +\contentsline {section}{\numberline {10.2}Pipeline CI objetivo (no implementado en esta entrega)}{26}{section.10.2}% +\contentsline {section}{\numberline {10.3}Compilar este documento}{26}{section.10.3}% +\contentsline {section}{\numberline {10.4}Prioridad de implementaci\'on de tests (ROI)}{27}{section.10.4}% +\contentsline {chapter}{\numberline {11}Cronograma y criterios de aceptaci\'on}{28}{chapter.11}% +\contentsline {section}{\numberline {11.1}Fases sugeridas}{28}{section.11.1}% +\contentsline {section}{\numberline {11.2}Definition of Done por release}{28}{section.11.2}% +\contentsline {section}{\numberline {11.3}Plantilla de informe de ejecuci\'on}{28}{section.11.3}% +\contentsline {section}{\numberline {11.4}Responsables (roles)}{29}{section.11.4}% +\contentsline {chapter}{\numberline {A}Glosario}{30}{appendix.Alph1}% +\contentsline {chapter}{\numberline {B}Checklist de release}{31}{appendix.Alph2}% +\contentsline {chapter}{\numberline {C}Mapa de rutas relevantes}{32}{appendix.Alph3}% diff --git a/docs/plan_pruebas/preamble.tex b/docs/plan_pruebas/preamble.tex new file mode 100644 index 0000000..6373380 --- /dev/null +++ b/docs/plan_pruebas/preamble.tex @@ -0,0 +1,110 @@ +% !TEX encoding = UTF-8 +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage[spanish,es-tabla]{babel} +\usepackage{lmodern} +\usepackage{microtype} + +\usepackage[ + a4paper, + margin=2.5cm, + headheight=14pt +]{geometry} + +\usepackage{setspace} +\onehalfspacing + +\usepackage{fancyhdr} +\pagestyle{fancy} +\fancyhf{} +\fancyhead[L]{\small IPSExtractor --- Plan de pruebas} +\fancyhead[R]{\small\thepage} +\fancyfoot[C]{\footnotesize Confidencial --- Uso interno} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\footrulewidth}{0.2pt} + +\usepackage{titlesec} +\titleformat{\chapter}[display] + {\normalfont\huge\bfseries}{\chaptertitlename\ \thechapter}{16pt}{\Huge} +\titleformat{\section}{\normalfont\Large\bfseries}{\thesection}{1em}{} +\titleformat{\subsection}{\normalfont\large\bfseries}{\thesubsection}{1em}{} + +\usepackage{booktabs} +\usepackage{longtable} +\usepackage{tabularx} +\usepackage{multirow} +\usepackage{array} +\usepackage{enumitem} +\setlist[itemize]{nosep,leftmargin=1.5em} +\setlist[enumerate]{nosep,leftmargin=1.5em} + +\usepackage{siunitx} +\usepackage{xcolor} +\definecolor{ipsblue}{HTML}{1B4F72} +\definecolor{ipsgrey}{HTML}{566573} +\definecolor{codebg}{HTML}{F4F6F7} +\definecolor{successgreen}{HTML}{1E8449} +\definecolor{warnorange}{HTML}{B9770E} + +\usepackage{listings} +\lstset{ + basicstyle=\ttfamily\small, + backgroundcolor=\color{codebg}, + frame=single, + framerule=0.3pt, + rulecolor=\color{ipsgrey}, + breaklines=true, + columns=fullflexible, + showstringspaces=false, + tabsize=2, + captionpos=b +} +\lstdefinelanguage{JavaScript}{ + keywords={function, const, let, var, return, if, else, for, while, export, import, default, true, false, null}, + sensitive=true, + morecomment=[l]//, + morecomment=[s]{/*}{*/}, + morestring=[b]", + morestring=[b]' +} + +\usepackage{tikz} +\usetikzlibrary{arrows.meta,positioning,fit,calc,shapes.geometric,shapes.multipart} + +\usepackage{graphicx} +\usepackage{hyperref} +\hypersetup{ + colorlinks=true, + linkcolor=ipsblue, + urlcolor=ipsblue, + citecolor=ipsblue, + pdftitle={Plan de pruebas IPSExtractor}, + pdfauthor={IPSExtractor QA}, + pdfsubject={Pruebas unitarias, integracion, E2E, estres y resiliencia} +} + +\newcommand{\docversion}{1.1.0} +\newcommand{\docdate}{13 de julio de 2026} +\newcommand{\statusbadge}[1]{\texttt{#1}} + +\newcommand{\makecover}{% + \begin{titlepage} + \centering + \vspace*{1.5cm} + {\color{ipsblue}\rule{\textwidth}{2pt}}\\[0.4cm] + {\Huge\bfseries IPSExtractor}\\[0.35cm] + {\Large\color{ipsgrey} Sistema de extracci\'on y an\'alisis de facturas m\'edicas}\\[0.4cm] + {\color{ipsblue}\rule{\textwidth}{2pt}}\\[1.8cm] + {\LARGE\bfseries Plan completo de pruebas}\\[0.3cm] + {\large Unitarias $\cdot$ Integraci\'on $\cdot$ E2E $\cdot$ Estr\'es $\cdot$ Resiliencia}\\[2.2cm] + \begin{tabular}{@{}ll@{}} + \textbf{Versi\'on} & \docversion \\ + \textbf{Fecha} & \docdate \\ + \textbf{Clasificaci\'on} & Uso interno \\ + \textbf{Herramientas} & pytest, Vitest, go test, k6, Docker Compose, latexmk \\ + \end{tabular} + \vfill + {\small Generado a partir de la arquitectura real del monorepo IPSExtractor.}\\[0.3cm] + {\color{ipsblue}\rule{0.5\textwidth}{0.6pt}} + \end{titlepage} +} diff --git a/docs/plan_pruebas/scripts/README.md b/docs/plan_pruebas/scripts/README.md new file mode 100644 index 0000000..8409815 --- /dev/null +++ b/docs/plan_pruebas/scripts/README.md @@ -0,0 +1,49 @@ +# Scripts k6 — Plan de estrés IPSExtractor + +Requieren [k6](https://k6.io/docs/get-started/installation/) y el stack en `http://127.0.0.1:8189`. + +## Entorno de referencia (obligatorio en informes) + +Las pruebas de carga del proyecto se calibran para el host: + +- **Hostname:** `ubuntu` (ASUS X441UAK) +- **SO:** Ubuntu 24.04.4 LTS +- **CPU / RAM:** i5-7200U, 8 GiB +- **Docker compartido** con MLflow (~1.8 GiB), Airflow, n8n, MinIO, etc. + +Antes de cada corrida, adjuntar al informe: + +```bash +hostnamectl | head -5 +free -h +docker stats --no-stream +curl -s -w '\ntime=%{time_total}s\n' http://127.0.0.1:8189/health/live +``` + +## Perfiles (`PROFILE`) + +| Valor | Cuándo | +|-------|--------| +| `shared8g` (default) | Host actual con otros contenedores | +| `lab` | Solo IPSExtractor, ≥3 GiB libres | + +## Variables + +| Variable | Default | Descripción | +|----------|---------|-------------| +| `BASE_URL` | `http://127.0.0.1:8189` | Gateway | +| `PROFILE` | `shared8g` | Perfil de carga | +| `BOT_API_TOKEN` | `dev-token-change-me` | Bearer bot | +| `DOWNLOAD_JOB_ID` | — | Obligatorio en events | +| `WORKER_PREFIX` | `load-w` | Prefijo heartbeats | +| `PDF_B64` | (PDF mínimo) | PDF para count | + +## Ejecución + +```bash +k6 run -e PROFILE=shared8g -e BASE_URL=http://127.0.0.1:8189 k6_gateway_health.js +k6 run -e PROFILE=shared8g -e BOT_API_TOKEN=dev-token-change-me k6_bot_heartbeats.js +k6 run -e PROFILE=shared8g -e DOWNLOAD_JOB_ID= k6_bot_events.js +# Solo si free -h muestra ≥3GiB disponibles: +k6 run -e PROFILE=shared8g k6_count_batches.js +``` diff --git a/docs/plan_pruebas/scripts/k6_bot_events.js b/docs/plan_pruebas/scripts/k6_bot_events.js new file mode 100644 index 0000000..eb48ba5 --- /dev/null +++ b/docs/plan_pruebas/scripts/k6_bot_events.js @@ -0,0 +1,66 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +/** + * ST-BOT-03 — Storm de eventos sobre un job existente. + * + * k6 run -e DOWNLOAD_JOB_ID= -e PROFILE=shared8g k6_bot_events.js + */ +const PROFILE = __ENV.PROFILE || 'shared8g'; +const BASE_URL = __ENV.BASE_URL || 'http://127.0.0.1:8189'; +const TOKEN = __ENV.BOT_API_TOKEN || 'dev-token-change-me'; +const JOB_ID = __ENV.DOWNLOAD_JOB_ID || ''; + +const profiles = { + shared8g: { + stages: [ + { duration: '15s', target: 5 }, + { duration: '45s', target: 12 }, + { duration: '15s', target: 0 }, + ], + }, + lab: { + stages: [ + { duration: '20s', target: 10 }, + { duration: '1m', target: 40 }, + { duration: '20s', target: 0 }, + ], + }, +}; + +const cfg = profiles[PROFILE] || profiles.shared8g; + +export const options = { + stages: cfg.stages, + thresholds: { + http_req_failed: ['rate<0.02'], + http_req_duration: ['p(95)<1000'], + }, + tags: { profile: PROFILE }, +}; + +export default function () { + if (!JOB_ID) { + throw new Error('Defina DOWNLOAD_JOB_ID con un job existente'); + } + const idx = __ITER + 1; + const payload = JSON.stringify({ + event_type: 'progress', + message: `k6 event ${idx}`, + index: idx, + total: 5000, + radicado: `R-${idx}`, + nit: '900123456', + metadata: { source: 'k6', profile: PROFILE }, + }); + const res = http.post(`${BASE_URL}/bot-descarga/jobs/${JOB_ID}/events`, payload, { + headers: { + Authorization: `Bearer ${TOKEN}`, + 'Content-Type': 'application/json', + }, + }); + check(res, { + 'event accepted': (r) => r.status === 200, + }); + sleep(PROFILE === 'shared8g' ? 0.15 : 0.05); +} diff --git a/docs/plan_pruebas/scripts/k6_bot_heartbeats.js b/docs/plan_pruebas/scripts/k6_bot_heartbeats.js new file mode 100644 index 0000000..2b29a16 --- /dev/null +++ b/docs/plan_pruebas/scripts/k6_bot_heartbeats.js @@ -0,0 +1,67 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +/** + * ST-BOT-01 — Heartbeats concurrentes de workers. + * + * k6 run -e BASE_URL=http://127.0.0.1:8189 -e BOT_API_TOKEN=dev-token-change-me \ + * -e PROFILE=shared8g k6_bot_heartbeats.js + */ +const PROFILE = __ENV.PROFILE || 'shared8g'; +const TOKEN = __ENV.BOT_API_TOKEN || 'dev-token-change-me'; +const PREFIX = __ENV.WORKER_PREFIX || 'load-w'; +const BASE_URL = __ENV.BASE_URL || 'http://127.0.0.1:8189'; + +const profiles = { + shared8g: { vus: 5, duration: '2m' }, + lab: { vus: 25, duration: '3m' }, +}; + +const cfg = profiles[PROFILE] || profiles.shared8g; + +export const options = { + scenarios: { + heartbeats: { + executor: 'constant-vus', + vus: cfg.vus, + duration: cfg.duration, + }, + }, + thresholds: { + http_req_duration: ['p(95)<800'], + checks: ['rate>0.95'], + }, + tags: { profile: PROFILE }, +}; + +function headers() { + return { + Authorization: `Bearer ${TOKEN}`, + 'Content-Type': 'application/json', + }; +} + +export function setup() { + for (let i = 0; i < cfg.vus; i++) { + const wid = `${PREFIX}-${i}`; + http.post( + `${BASE_URL}/bot-descarga/workers/register`, + JSON.stringify({ worker_id: wid, hostname: `k6-${i}`, max_concurrent: 1 }), + { headers: headers() }, + ); + } + return {}; +} + +export default function () { + const wid = `${PREFIX}-${__VU - 1}`; + const res = http.post( + `${BASE_URL}/bot-descarga/workers/heartbeat`, + JSON.stringify({ worker_id: wid }), + { headers: headers() }, + ); + check(res, { + 'heartbeat 200': (r) => r.status === 200, + }); + sleep(8); +} diff --git a/docs/plan_pruebas/scripts/k6_count_batches.js b/docs/plan_pruebas/scripts/k6_count_batches.js new file mode 100644 index 0000000..b9bac70 --- /dev/null +++ b/docs/plan_pruebas/scripts/k6_count_batches.js @@ -0,0 +1,63 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; +import encoding from 'k6/encoding'; + +/** + * ST-COUNT-01 — Lotes concurrentes hacia count-api vía gateway. + * En host compartido 8GiB: usar PROFILE=shared8g y liberar MLflow/Airflow antes. + * + * k6 run -e PROFILE=shared8g k6_count_batches.js + */ +const PROFILE = __ENV.PROFILE || 'shared8g'; +const BASE_URL = __ENV.BASE_URL || 'http://127.0.0.1:8189'; + +const profiles = { + shared8g: { + rate: 1, + duration: '1m', + preAllocatedVUs: 2, + maxVUs: 5, + }, + lab: { + rate: 5, + duration: '2m', + preAllocatedVUs: 10, + maxVUs: 20, + }, +}; + +const cfg = profiles[PROFILE] || profiles.shared8g; + +export const options = { + scenarios: { + batches: { + executor: 'constant-arrival-rate', + rate: cfg.rate, + timeUnit: '1s', + duration: cfg.duration, + preAllocatedVUs: cfg.preAllocatedVUs, + maxVUs: cfg.maxVUs, + }, + }, + thresholds: { + http_req_duration: ['p(95)<60000'], + checks: ['rate>0.85'], + }, + tags: { profile: PROFILE }, +}; + +const tinyPdf = encoding.b64decode( + 'JVBERi0xLjAKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPD4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCAzMDAgMTQ0XQo+PgplbmRvYmoKeHJlZgowIDQKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDA5IDAwMDAwIG4gCjAwMDAwMDAwNjMgMDAwMDAgbiAKMDAwMDAwMDEyNCAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDQKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjIwMQolJUVPRgo=', +); + +export default function () { + const bin = __ENV.PDF_B64 ? encoding.b64decode(__ENV.PDF_B64) : tinyPdf; + const data = { + file: http.file(bin, 'sample.pdf', 'application/pdf'), + }; + const res = http.post(`${BASE_URL}/count/v1/count`, data); + check(res, { + 'not 5xx': (r) => r.status < 500, + }); + sleep(0.1); +} diff --git a/docs/plan_pruebas/scripts/k6_gateway_health.js b/docs/plan_pruebas/scripts/k6_gateway_health.js new file mode 100644 index 0000000..ddabd67 --- /dev/null +++ b/docs/plan_pruebas/scripts/k6_gateway_health.js @@ -0,0 +1,60 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +/** + * ST-GW-01 — Gateway health liveness bajo carga. + * + * k6 run -e BASE_URL=http://127.0.0.1:8189 -e PROFILE=shared8g k6_gateway_health.js + * k6 run -e PROFILE=lab k6_gateway_health.js + * + * Perfiles: + * shared8g (default) — host Ubuntu 8GiB compartido (MLflow/Airflow/etc.) + * lab — Docker dedicado a IPS + */ +const PROFILE = __ENV.PROFILE || 'shared8g'; + +const profiles = { + shared8g: { + stages: [ + { duration: '20s', target: 5 }, + { duration: '40s', target: 15 }, + { duration: '40s', target: 25 }, + { duration: '20s', target: 0 }, + ], + thresholds: { + http_req_failed: ['rate<0.01'], + http_req_duration: ['p(95)<500'], + }, + }, + lab: { + stages: [ + { duration: '30s', target: 20 }, + { duration: '1m', target: 50 }, + { duration: '1m', target: 100 }, + { duration: '30s', target: 0 }, + ], + thresholds: { + http_req_failed: ['rate<0.001'], + http_req_duration: ['p(95)<300'], + }, + }, +}; + +const cfg = profiles[PROFILE] || profiles.shared8g; + +export const options = { + stages: cfg.stages, + thresholds: cfg.thresholds, + tags: { profile: PROFILE, host: 'ubuntu-shared-8g' }, +}; + +const BASE_URL = __ENV.BASE_URL || 'http://127.0.0.1:8189'; + +export default function () { + const res = http.get(`${BASE_URL}/health/live`); + check(res, { + 'status is 200': (r) => r.status === 200, + 'body ok': (r) => String(r.body).includes('ok'), + }); + sleep(0.2); +} diff --git a/docs/plan_pruebas/sections/01_introduccion.tex b/docs/plan_pruebas/sections/01_introduccion.tex new file mode 100644 index 0000000..45c26a3 --- /dev/null +++ b/docs/plan_pruebas/sections/01_introduccion.tex @@ -0,0 +1,55 @@ +\chapter{Introducci\'on} +\label{ch:intro} + +\section{Objetivo} +Definir un plan de pruebas \textbf{completo y ejecutable} para IPSExtractor que cubra: +\begin{itemize} + \item Correctitud funcional por servicio y por flujo de negocio. + \item Integraci\'on entre Gateway, microservicios, PostgreSQL, Redis y MinIO. + \item Validaci\'on end-to-end (Desktop $\rightarrow$ APIs $\rightarrow$ agent/bot). + \item Capacidad y l\'imites bajo carga (estr\'es) con criterios SLO. + \item Resiliencia ante fallos de dependencias (chaos controlado). +\end{itemize} + +\section{Alcance} +\subsection{Dentro de alcance} +\begin{itemize} + \item \texttt{api\_gateway}, \texttt{extraction} + workers ARQ, \texttt{cleaning}, \texttt{count-api}. + \item \texttt{bot-descarga} (API Docker) y agent PC (\texttt{bots/bot\_descarga}). + \item PostgreSQL 16, Redis 7, MinIO/S3, vol\'umenes \texttt{/data} e \texttt{ips\_queue}. + \item Desktop app (Electron/React) a nivel de contratos API y checklist E2E. +\end{itemize} + +\subsection{Fuera de alcance de esta versi\'on documental} +\begin{itemize} + \item Implementaci\'on inmediata de CI/CD o de nuevos tests FastAPI (se planifican, no se entregan aqu\'i). + \item Estr\'es contra producci\'on o Imaging real sin entorno de staging. + \item Pruebas de seguridad ofensivas (penetration testing). +\end{itemize} + +\section{Estado actual del repositorio} +\begin{table}[h] +\centering +\begin{tabular}{@{}llp{6.2cm}@{}} +\toprule +\textbf{\'Area} & \textbf{Tipo} & \textbf{Ubicaci\'on / notas} \\ +\midrule +Bot agent & Unit & \texttt{bots/bot\_descarga/tests/} \\ +Bot API store & Unit & \texttt{services/bot\_descarga/tests/test\_store.py} \\ +Desktop & Unit & Vitest en \texttt{services/desktop\_app} \\ +count-api & Unit & \texttt{go test} (features ML) \\ +Integraci\'on & --- & No existe \\ +E2E & --- & No existe \\ +CI & --- & No hay workflows \\ +\bottomrule +\end{tabular} +\caption{Cobertura existente y gaps.} +\end{table} + +\section{Referencias del sistema} +\begin{itemize} + \item \texttt{README.md} (ra\'iz): stack, puertos, arranque. + \item \texttt{docker-compose.yml}: orquestaci\'on de servicios. + \item \texttt{docs/MIGRACION\_MICROSERVICIOS.md}, \texttt{docs/database.dbml}. + \item READMEs por servicio bajo \texttt{services/*/} y \texttt{bots/bot\_descarga/}. +\end{itemize} diff --git a/docs/plan_pruebas/sections/02_arquitectura.tex b/docs/plan_pruebas/sections/02_arquitectura.tex new file mode 100644 index 0000000..8766bfe --- /dev/null +++ b/docs/plan_pruebas/sections/02_arquitectura.tex @@ -0,0 +1,56 @@ +\chapter{Arquitectura bajo prueba} +\label{ch:arquitectura} + +\section{Vista de componentes} +El host solo expone el Gateway en el puerto \textbf{8189}. El resto de APIs viven en la red Docker. El agent del bot corre en PCs externas y se comunica por HTTP + PutObject a MinIO. + +\input{diagrams/arquitectura} + +\section{Inventario de componentes} +\begin{table}[ht] +\centering +\begin{tabular}{@{}llp{5.8cm}@{}} +\toprule +\textbf{Componente} & \textbf{Puerto} & \textbf{Responsabilidad} \\ +\midrule +\texttt{api\_gateway} & Host 8189 & Proxy HTTP, health agregado, CORS \\ +\texttt{extraction} & 8001 & Jobs/tasks, LLM, ingest PDFs \\ +\texttt{worker} (ARQ) & --- & Procesamiento async v\'ia Redis \\ +\texttt{cleaning} & 8002 & Limpieza CSV / reglas \\ +\texttt{count-api} & 8080 & OCR + ONNX, stateless \\ +\texttt{bot-descarga} & 8200 & Control remoto de bots \\ +PostgreSQL 16 & 5432 & Persistencia compartida \\ +Redis 7 & 6379 & Cola ARQ + rate limiter \\ +Desktop & local & Cliente Electron/React \\ +Agent bot & local PC & Selenium + MinIO upload \\ +MinIO/S3 & externo & Excel y PDFs del bot \\ +\bottomrule +\end{tabular} +\caption{Componentes del sistema bajo prueba.} +\end{table} + +\section{Flujo cr\'itico: bot de descarga} +\input{diagrams/flujo_bot} + +Secuencia resumida: +\begin{enumerate} + \item Agent: \texttt{register} + loop \texttt{heartbeat} / \texttt{claim\_pending} ($\sim$8\,s). + \item Desktop: \texttt{POST /bot-descarga/jobs} (Excel, \texttt{worker\_id}, \texttt{job\_id}). + \item API: valida job padre y worker online; sube Excel a MinIO; estado \texttt{pending}. + \item Agent: claim $\rightarrow$ \texttt{RUNNING}; descarga Excel; Selenium/Imaging; PutObject PDFs. + \item Eventos \texttt{POST /events}; cierre \texttt{PATCH /jobs/\{id\}} (\texttt{completed}/\texttt{failed}). +\end{enumerate} + +Layout MinIO: +\begin{lstlisting}[language={},caption={Prefijos MinIO del bot}] +uploads/{download_job_id}/input.xlsx +downloads/{download_job_id}/{nit}/{radicado}.pdf +downloads/{download_job_id}/_manifest.json +\end{lstlisting} + +\section{Otros flujos de negocio} +\begin{description} + \item[Conteo] Desktop $\rightarrow$ \texttt{POST /count/v1/count} $\rightarrow$ \texttt{POST /count-jobs} $\rightarrow$ validaci\'on humana. + \item[Extracci\'on] \texttt{from-count} o ingest de PDFs $\rightarrow$ workers ARQ $\rightarrow$ filas en BD. + \item[Limpieza] Job cleaning desde \texttt{extraction\_batch\_id} o CSV upload. +\end{description} diff --git a/docs/plan_pruebas/sections/03_estrategia.tex b/docs/plan_pruebas/sections/03_estrategia.tex new file mode 100644 index 0000000..5701876 --- /dev/null +++ b/docs/plan_pruebas/sections/03_estrategia.tex @@ -0,0 +1,63 @@ +\chapter{Estrategia de pruebas} +\label{ch:estrategia} + +\section{Pir\'amide} +\begin{table}[h] +\centering +\begin{tabular}{@{}llp{4.5cm}l@{}} +\toprule +\textbf{Capa} & \textbf{Qu\'e valida} & \textbf{D\'onde} & \textbf{Frecuencia} \\ +\midrule +Unitaria & Dominio, parsers, auth, store & Local + CI & Cada PR \\ +Integraci\'on & HTTP + PG/Redis/MinIO & Compose test & PR / nightly \\ +Contrato & OpenAPI / rutas gateway & CI & Cada PR \\ +E2E & Flujos de negocio & Staging & Nightly / release \\ +Estr\'es & L\'imites y degradaci\'on & Staging aislado & Pre-release \\ +Chaos & Ca\'idas de dependencias & Staging & Mensual \\ +\bottomrule +\end{tabular} +\caption{Pir\'amide de pruebas IPSExtractor.} +\end{table} + +\section{Convenci\'on de identificadores} +\begin{itemize} + \item \texttt{UT--} --- unitarias + \item \texttt{IT--} --- integraci\'on + \item \texttt{E2E-} --- end-to-end de negocio + \item \texttt{ST--} --- estr\'es / carga + \item \texttt{CH-} --- chaos / resiliencia +\end{itemize} + +\section{Entornos} +\begin{description} + \item[local] Mocks de LLM, Imaging y MinIO (moto/LocalStack). + \item[ci] Unitarios + smoke Compose (\texttt{/health/live}). + \item[staging] Stack completo + MinIO staging + LLM con cuota; Imaging solo con VPN de prueba. + \item[stress] Igual que staging, sin usuarios reales; datos sint\'eticos. +\end{description} + +\section{Mocks vs sistemas reales} +\begin{table}[h] +\centering +\begin{tabular}{@{}lcccc@{}} +\toprule +\textbf{Dependencia} & \textbf{Unit/CI} & \textbf{Integr.} & \textbf{Estr\'es} & \textbf{E2E} \\ +\midrule +PostgreSQL & SQLite/TC & Real & Real & Real \\ +Redis & Mock/TC & Real & Real & Real \\ +MinIO & moto/LS & LocalStack & Staging & Staging \\ +LLM & Fake HTTP & Fake & Fake+1 real & Real \\ +Imaging & Mock & Mock & N/A & Real \\ +Chrome & Mock & Mock & N/A & Real \\ +\bottomrule +\end{tabular} +\caption{TC = Testcontainers; LS = LocalStack.} +\end{table} + +\section{Principios} +\begin{enumerate} + \item Un caso = un objetivo verificable (assert expl\'icito). + \item Datos de prueba versionados (fixtures), no datos de producci\'on. + \item Estr\'es solo en staging aislado; umbrales escritos antes de ejecutar. + \item Fallos externos (LLM/Imaging) se aislan con mocks en CI. +\end{enumerate} diff --git a/docs/plan_pruebas/sections/04_unitarias.tex b/docs/plan_pruebas/sections/04_unitarias.tex new file mode 100644 index 0000000..c2294db --- /dev/null +++ b/docs/plan_pruebas/sections/04_unitarias.tex @@ -0,0 +1,75 @@ +\chapter{Pruebas unitarias} +\label{ch:unitarias} + +\section{Gateway} +\begin{longtable}{@{}p{2.4cm}p{4.2cm}p{5.5cm}@{}} +\caption{Unitarias gateway.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +UT-GW-01 & Clasificaci\'on path upload vs JSON & Timeouts 600\,s vs 30\,s correctos \\ +UT-GW-02 & Health live sin upstream & Respuesta inmediata \texttt{ok} \\ +UT-GW-03 & Health agregado degradado & Si extraction/cleaning fallan $\rightarrow$ \texttt{degraded} \\ +\bottomrule +\end{longtable} + +\section{Bot-descarga API (\texttt{JobStore})} +Cobertura existente en \texttt{test\_store.py}; ampliar con: +\begin{longtable}{@{}p{2.6cm}p{4.0cm}p{5.5cm}@{}} +\caption{Unitarias bot-descarga API.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +UT-BOT-01 & Register + heartbeat & Worker online; offline tras $>$45\,s \\ +UT-BOT-02 & Claim at\'omico & Un solo worker obtiene el job \\ +UT-BOT-03 & Cancel pending & Estado \texttt{cancelled} inmediato \\ +UT-BOT-04 & Cancel running & \texttt{cancel\_requested=true} \\ +UT-BOT-05 & Auth Bearer & Token inv\'alido $\rightarrow$ 401 \\ +UT-BOT-06 & Keys MinIO & Prefijos uploads/downloads correctos \\ +\bottomrule +\end{longtable} + +\section{Agent bot (PC)} +Mantener y extender \texttt{bots/bot\_descarga/tests/}: +\begin{longtable}{@{}p{2.6cm}p{4.0cm}p{5.5cm}@{}} +\caption{Unitarias agent.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +UT-AGT-01 & Excel reader / NIT & Headers y limpieza correctos \\ +UT-AGT-02 & PDF validator & Rechaza firmas/pesos inv\'alidos \\ +UT-AGT-03 & Cancel mid-run & \texttt{should\_cancel} detiene loop \\ +UT-AGT-04 & Browser fatal DNS & \texttt{fatal\_error} en Imaging \\ +UT-AGT-05 & MinIO keys & Keys y modo an\'onimo \\ +UT-AGT-06 & RemoteApiClient (mock) & register/claim/events con HTTP fake \\ +\bottomrule +\end{longtable} + +\section{Extraction / Cleaning / Count / Desktop} +\begin{longtable}{@{}p{2.6cm}p{4.2cm}p{5.3cm}@{}} +\caption{Unitarias resto de servicios.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +UT-EXT-01 & Rate limiter LLM & Respeta RPM/TPM configurados \\ +UT-EXT-02 & Normalizer JSON & Salida can\'onica estable \\ +UT-CLN-01 & Reglas CSV & Numeric/text/special/dates \\ +UT-CLN-02 & Type inference & Tipos coherentes con fixtures \\ +UT-CNT-01 & Features ML & Vector de features esperado \\ +UT-CNT-02 & PDF oversized & Rechazo controlado \\ +UT-DES-01 & apiClient errores & Manejo de 4xx/5xx \\ +UT-DES-02 & Wizard downloads & Payload job correcto \\ +\bottomrule +\end{longtable} + +\section{Comandos de ejecuci\'on} +\begin{lstlisting}[language=bash,caption={Suite unitaria r\'apida}] +cd bots/bot_descarga && python -m pytest tests/ -q +cd services/bot_descarga && pytest -q +cd services/desktop_app && npm test +cd services/services-count-facturas-medicas-serving && go test ./... +\end{lstlisting} diff --git a/docs/plan_pruebas/sections/05_integracion.tex b/docs/plan_pruebas/sections/05_integracion.tex new file mode 100644 index 0000000..0817428 --- /dev/null +++ b/docs/plan_pruebas/sections/05_integracion.tex @@ -0,0 +1,60 @@ +\chapter{Pruebas de integraci\'on} +\label{ch:integracion} + +\section{Stack de integraci\'on} +Compose de prueba con PostgreSQL, Redis, LocalStack (MinIO), \texttt{bot-descarga}, \texttt{api\_gateway} y, seg\'un caso, extraction/cleaning/count-api. LLM siempre mockeado en CI. + +\section{Gateway} +\begin{longtable}{@{}p{2.4cm}p{4.2cm}p{5.5cm}@{}} +\caption{Integraci\'on gateway.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +IT-GW-01 & Proxy \texttt{/bot-descarga/health} & 200 desde host :8189 \\ +IT-GW-02 & Proxy \texttt{/tasks} & Llega a extraction \\ +IT-GW-03 & Upstream ca\'ido & 502/504 sin colgar el gateway \\ +IT-GW-04 & Upload path timeout & Rutas de upload usan 600\,s \\ +\bottomrule +\end{longtable} + +\section{Bot-descarga} +\begin{longtable}{@{}p{2.6cm}p{4.5cm}p{5.0cm}@{}} +\caption{Integraci\'on bot-descarga.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +IT-BOT-01 & Register $\rightarrow$ create $\rightarrow$ claim & Job RUNNING una sola vez \\ +IT-BOT-02 & Upload Excel a MinIO & Key \texttt{uploads/\{id\}/} presente \\ +IT-BOT-03 & Events + patch complete & Historial y status finales \\ +IT-BOT-04 & Worker offline create & HTTP 409 \\ +IT-BOT-05 & Parent job inexistente & HTTP 404 \\ +IT-BOT-06 & MinIO down en create & Job failed + HTTP 502 \\ +\bottomrule +\end{longtable} + +\section{Extraction / Cleaning / Count} +\begin{longtable}{@{}p{2.6cm}p{4.5cm}p{5.0cm}@{}} +\caption{Integraci\'on extraction, cleaning, count y BD.}\\ +\toprule +\textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ +\midrule +\endhead +IT-EXT-01 & Task $\rightarrow$ ARQ $\rightarrow$ rows & Filas en PG con LLM fake \\ +IT-EXT-02 & Redis ca\'ido & Fallback sync o error claro \\ +IT-EXT-03 & from-count lee \texttt{/data} & Paths v\'alidos montados \\ +IT-CLN-01 & Job desde batch\_id & \texttt{cleaned\_rows} persistidos \\ +IT-CLN-02 & CSV upload job & Preview + apply \\ +IT-CNT-01 & PDF fixture $\rightarrow$ JSON & Paridad con baseline \\ +IT-DB-01 & Migraciones 0001--0004 & BD limpia aplica sin error \\ +\bottomrule +\end{longtable} + +\section{Smoke m\'inimo post-compose} +\begin{lstlisting}[language=bash,caption={Smoke health}] +docker compose up --build -d +curl http://127.0.0.1:8189/health/live +curl http://127.0.0.1:8189/health +\end{lstlisting} +Nota Windows: usar \texttt{127.0.0.1}, no \texttt{localhost} (IPv6). diff --git a/docs/plan_pruebas/sections/06_e2e.tex b/docs/plan_pruebas/sections/06_e2e.tex new file mode 100644 index 0000000..28b03f0 --- /dev/null +++ b/docs/plan_pruebas/sections/06_e2e.tex @@ -0,0 +1,54 @@ +\chapter{Pruebas end-to-end} +\label{ch:e2e} + +\section{Matriz de flujos de negocio} +\begin{longtable}{@{}p{1.8cm}p{2.8cm}p{5.0cm}p{3.0cm}@{}} +\caption{Casos E2E cr\'iticos.}\\ +\toprule +\textbf{ID} & \textbf{Flujo} & \textbf{Pasos m\'inimos} & \textbf{\'Exito} \\ +\midrule +\endhead +E2E-01 & Conteo & Lotes PDF $\rightarrow$ \texttt{/count/v1/count} $\rightarrow$ \texttt{/count-jobs} $\rightarrow$ PATCH & Conteos editables \\ +E2E-02 & Extracci\'on from-count & Tras E2E-01 $\rightarrow$ task extraction $\rightarrow$ rows & Filas coherentes \\ +E2E-03 & Extracci\'on ingest & Upload PDFs $\rightarrow$ task $\rightarrow$ rows & Paridad con fixtures \\ +E2E-04 & Limpieza & Batch extraction $\rightarrow$ cleaning job & Reglas aplicadas \\ +E2E-05 & Bot feliz & Worker online $\rightarrow$ Excel $\rightarrow$ claim $\rightarrow$ PDFs MinIO $\rightarrow$ completed & Manifest + events \\ +E2E-06 & Bot cancel & Cancel pending y running & Estados correctos \\ +E2E-07 & Worker offline & Create job sin heartbeat & HTTP 409 \\ +E2E-08 & Pipeline largo & Descarga $\rightarrow$ extracci\'on PDFs & Sin corrupci\'on \\ +\bottomrule +\end{longtable} + +\section{Detalle E2E-05 (bot descarga)} +\subsection{Precondiciones} +\begin{itemize} + \item Stack Compose healthy; MinIO accesible; token \texttt{BOT\_API\_TOKEN} compartido. + \item Job Desktop padre existente en tabla \texttt{jobs}. + \item Agent registrado y con heartbeat $<$45\,s. + \item Excel fixture con $N$ radicados v\'alidos ($N\geq 3$ en smoke; $N\geq 50$ en regresi\'on). +\end{itemize} + +\subsection{Pasos} +\begin{enumerate} + \item Arrancar agent: \texttt{python -m bot\_descarga.worker.run --api-url http://127.0.0.1:8189/bot-descarga ...} + \item Desde Desktop o HTTP: crear job multipart con Excel. + \item Verificar claim y descarga de Excel. + \item (Staging Imaging) Completar descargas; en CI mock: simular eventos + PutObject. + \item Verificar \texttt{completed}, lista \texttt{/files} y \texttt{\_manifest.json}. +\end{enumerate} + +\subsection{Asserts} +\begin{itemize} + \item Un \'unico claim; status final \texttt{completed} o \texttt{failed} expl\'icito. + \item Eventos ordenados; \texttt{processed/total} coherentes. + \item Objetos MinIO bajo \texttt{downloads/\{id\}/}. +\end{itemize} + +\section{Desktop} +Checklist manual / automatizable: +\begin{itemize} + \item Wizard de descargas (2 pasos) y panel de resultados. + \item Polling de job ($\sim$3\,s) y workers ($\sim$5\,s). + \item Token en \texttt{localStorage} (\texttt{botApiToken}). +\end{itemize} +Gap conocido a resolver antes de E2E desktop completo: import de m\'odulo downloads ausente referenciado en \texttt{App.tsx}. diff --git a/docs/plan_pruebas/sections/07_estres.tex b/docs/plan_pruebas/sections/07_estres.tex new file mode 100644 index 0000000..64182d5 --- /dev/null +++ b/docs/plan_pruebas/sections/07_estres.tex @@ -0,0 +1,90 @@ +\chapter{Pruebas de estr\'es y carga} +\label{ch:estres} + +\section{Herramienta} +Se usa \textbf{k6} (Grafana Labs) contra \texttt{http://127.0.0.1:8189}. Scripts de referencia en \texttt{docs/plan\_pruebas/scripts/}. M\'etricas complementarias: \texttt{docker stats}, \texttt{pg\_stat\_activity}, Redis INFO, logs del gateway. + +\section{Perfiles de carga} +Por defecto, en el host de la secci\'on~\ref{sec:host-pruebas}, aplicar el perfil \textbf{host-compartido-8gb}. El perfil \textbf{laboratorio} solo aplica si el Docker Engine est\'a dedicado a IPS (sin MLflow/Airflow/n8n, $\geq$3\,GiB libres). + +\begin{table}[ht] +\centering +\begin{tabular}{@{}p{2.3cm}p{5.5cm}p{5.0cm}@{}} +\toprule +\textbf{ID} & \textbf{host-compartido-8gb} & \textbf{laboratorio} \\ +\midrule +ST-GW-01 & 5$\rightarrow$15$\rightarrow$25 VUs; p95 $<$500\,ms & 50--100 VUs; p95 $<$300\,ms \\ +ST-BOT-01 & 3--8 workers / 8\,s & 20--50 workers / 8\,s \\ +ST-BOT-03 & 5--15 VUs events & hasta 40 VUs / 5k events \\ +ST-COUNT-01 & 1 rps, max 3--5 VUs; evitar si RAM libre $<$3\,GiB & 5--20 lotes $\times$10 \\ +ST-EXT-01 & 20--50 tasks; 1 r\'eplica worker & 100--500 tasks; 2 r\'eplicas \\ +\bottomrule +\end{tabular} +\caption{Cargas por perfil de entorno.} +\label{tab:perfiles-carga} +\end{table} + +Con el zoo Docker actual (MLflow $\sim$1{,}86\,GiB + Airflow + n8n, etc.) \textbf{no} ejecutar ST-COUNT-01 ni ST-EXT agresivo sin liberar memoria primero. + +\section{Escenarios (cat\'alogo completo)} +\begin{longtable}{@{}p{2.4cm}p{3.2cm}p{3.5cm}p{3.2cm}@{}} +\caption{Escenarios de estr\'es.}\\ +\toprule +\textbf{ID} & \textbf{Objetivo} & \textbf{Carga (laboratorio)} & \textbf{Observar} \\ +\midrule +\endhead +ST-GW-01 & Gateway concurrente & 50--100 VUs \texttt{/health/live} & p95, 5xx \\ +ST-BOT-01 & Heartbeats masivos & 20--50 workers / 8\,s & PG, offline falsos \\ +ST-BOT-02 & Claim contention & 10 workers, cola jobs & Un claim/job \\ +ST-BOT-03 & Event storm & Hasta 5k events/job & Escritura PG \\ +ST-BOT-04 & Excel grande & 10--50\,MB upload & Timeout 600\,s \\ +ST-MINIO-01 & PutObject paralelo & N PCs & Errores S3 \\ +ST-COUNT-01 & OCR paralelo & 5--20 lotes $\times$10 & RAM, OOM \\ +ST-EXT-01 & Cola ARQ & 100--500 tasks (LLM mock) & Backlog \\ +ST-EXT-02 & LLM real & 20--50 PDFs & 429, costos \\ +ST-DES-01 & Polling desktop & 10 clientes poll & CPU gateway \\ +ST-DB-01 & PG saturaci\'on & Mezcla ST-BOT+EXT & Locks \\ +\bottomrule +\end{longtable} + +\section{Scripts k6 incluidos} +\begin{table}[h] +\centering +\begin{tabular}{@{}llp{4.8cm}@{}} +\toprule +\textbf{Archivo} & \textbf{ID} & \textbf{Target} \\ +\midrule +\texttt{k6\_gateway\_health.js} & ST-GW-01 & \texttt{GET /health/live} \\ +\texttt{k6\_bot\_heartbeats.js} & ST-BOT-01 & \texttt{POST .../workers/heartbeat} \\ +\texttt{k6\_bot\_events.js} & ST-BOT-03 & \texttt{POST .../jobs/\{id\}/events} \\ +\texttt{k6\_count\_batches.js} & ST-COUNT-01 & \texttt{POST /count/v1/count} \\ +\bottomrule +\end{tabular} +\caption{Mapeo script $\leftrightarrow$ escenario.} +\end{table} + +Los scripts aceptan \texttt{PROFILE=shared8g} (default recomendado en este host) o \texttt{PROFILE=lab}. + +\section{SLOs de aceptaci\'on} +\subsection{Perfil host-compartido-8gb (default)} +\begin{itemize} + \item Gateway \texttt{/health/live} p95 $<$\,\SI{500}{\milli\second}; error rate $<$\,1\,\%. + \item No usar el health \emph{agregado} (\texttt{/health}) como SLO de latencia (puede superar 10\,s en este host). + \item Heartbeat: 0 workers offline falsos con $\leq$8 workers y poll $\leq$8\,s. + \item Claim: 0 jobs con dos workers en \texttt{RUNNING}. + \item Count-api: sin OOM; detener la prueba si el host entra en swap sostenido. +\end{itemize} + +\subsection{Perfil laboratorio} +\begin{itemize} + \item Gateway p95 salud: $<$\,\SI{300}{\milli\second}; error rate $<$\,0,1\,\%. + \item Extracci\'on (LLM mock): backlog ARQ drenado con \texttt{WORKER\_REPLICAS=2}. + \item Count-api: sin OOM en carga acordada; PDFs oversized $\rightarrow$ 4xx. +\end{itemize} + +\section{Ejecuci\'on ejemplo} +\begin{lstlisting}[language=bash,caption={Estr\'es gateway en host compartido}] +cd docs/plan_pruebas/scripts +# Documentar entorno: free -h && docker stats --no-stream +k6 run -e BASE_URL=http://127.0.0.1:8189 -e PROFILE=shared8g k6_gateway_health.js +\end{lstlisting} diff --git a/docs/plan_pruebas/sections/08_resiliencia.tex b/docs/plan_pruebas/sections/08_resiliencia.tex new file mode 100644 index 0000000..a410639 --- /dev/null +++ b/docs/plan_pruebas/sections/08_resiliencia.tex @@ -0,0 +1,33 @@ +\chapter{Resiliencia y chaos} +\label{ch:resiliencia} + +\section{Objetivo} +Verificar degradaci\'on controlada y recuperaci\'on sin corrupci\'on de datos cuando fallan dependencias. + +\section{Casos} +\begin{longtable}{@{}p{1.8cm}p{3.5cm}p{4.0cm}p{3.2cm}@{}} +\caption{Casos de resiliencia.}\\ +\toprule +\textbf{ID} & \textbf{Fallo inyectado} & \textbf{Expectativa} & \textbf{Recuperaci\'on} \\ +\midrule +\endhead +CH-01 & Redis down mid-run & Extracci\'on async falla o fallback sync & Stack healthy al reiniciar Redis \\ +CH-02 & MinIO down mid-job & Create job 502 / PutObject warning & Job failed expl\'icito; BD consistente \\ +CH-03 & Agent crash mid-download & Job no queda zombie indefinido & Cancel o failed; sin doble claim \\ +CH-04 & Extraction container kill & Gateway health \texttt{degraded} & Tras restart, health ok \\ +CH-05 & Token inv\'alido masivo & 401 sin saturar workers & Logs claros \\ +CH-06 & Imaging DNS & Agent \texttt{fatal\_error} & Evento visible en Desktop \\ +\bottomrule +\end{longtable} + +\section{Modos de fallo conocidos (bot)} +\begin{itemize} + \item Worker offline al crear job $\rightarrow$ 409. + \item Excel vac\'io $\rightarrow$ 400. + \item Heartbeat $>$45\,s $\rightarrow$ worker \texttt{offline}. + \item Cancel pending vs running (flag \texttt{cancel\_requested}). + \item PDF corrupto $\rightarrow$ reintento o fallo por radicado. +\end{itemize} + +\section{Criterio global} +Tras chaos, \texttt{GET /health/live} debe volver a OK sin intervenci\'on manual (salvo dependencias externas como Imaging/LLM). diff --git a/docs/plan_pruebas/sections/09_datos_entornos.tex b/docs/plan_pruebas/sections/09_datos_entornos.tex new file mode 100644 index 0000000..30a3161 --- /dev/null +++ b/docs/plan_pruebas/sections/09_datos_entornos.tex @@ -0,0 +1,117 @@ +\chapter{Datos de prueba y entornos} +\label{ch:datos} + +\section{Host donde se ejecutan las pruebas} +\label{sec:host-pruebas} + +Las pruebas contra el stack desplegado (smoke, integraci\'on parcial, estr\'es k6) se realizan en el siguiente equipo. \textbf{Todo informe de ejecuci\'on debe citar este entorno} (o indicar expl\'icitamente si se us\'o otro). + +\subsection{Hardware y sistema} +\begin{table}[ht] +\centering +\begin{tabular}{@{}lp{8.5cm}@{}} +\toprule +\textbf{Campo} & \textbf{Valor} \\ +\midrule +Hostname & \texttt{ubuntu} \\ +SO & Ubuntu 24.04.4 LTS (kernel 6.17.0-35-generic) \\ +Arquitectura & x86-64 \\ +Equipo & ASUSTeK X441UAK \\ +CPU & Intel Core i5-7200U @ 2{,}50\,GHz (2 n\'ucleos / 4 hilos) \\ +RAM & 8\,GiB DDR4-2133 (l\'imite visible Docker $\approx$ 7{,}64\,GiB) \\ +Almacenamiento & HDD 500\,GB interno + disco USB 1\,TB EXT4 \\ +Contexto cloud CLI & \texttt{default/inmodata-builker} \\ +\bottomrule +\end{tabular} +\caption{Host de pruebas IPSExtractor (staging compartido).} +\label{tab:host-pruebas} +\end{table} + +\subsection{Stack IPSExtractor observado (idle)} +Medici\'on \texttt{docker stats --no-stream} (13 jul 2026), contenedores IPS: + +\begin{table}[ht] +\centering +\begin{tabular}{@{}lr@{}} +\toprule +\textbf{Contenedor} & \textbf{RAM aprox.} \\ +\midrule +\texttt{ipsextractor-api} (gateway) & 42\,MiB \\ +\texttt{ipsextractor-extraction} & 31\,MiB \\ +\texttt{ipsextractor-worker-1/2} & 28--32\,MiB c/u \\ +\texttt{ipsextractor-cleaning} & 36\,MiB \\ +\texttt{ipsextractor-bot-descarga} & 17\,MiB \\ +\texttt{ipsextractor-count-api} & 13\,MiB (l\'imite 4\,GiB) \\ +\texttt{ipsextractor-db} & 27\,MiB \\ +\texttt{ipsextractor-redis} & 8\,MiB \\ +\midrule +\textbf{Subtotal IPS (idle)} & $\approx$ 230--250\,MiB \\ +\bottomrule +\end{tabular} +\caption{Huella de memoria IPSExtractor en idle.} +\end{table} + +Health verificado: +\begin{lstlisting}[language=bash,caption={Smoke del gateway en el host}] +curl -s http://127.0.0.1:8189/health/live +# {"status":"ok"} + +curl -s http://127.0.0.1:8189/health +# status ok; extraction, cleaning, counting, bot_descarga ok +# Nota: el health agregado puede tardar ~10-12 s en este host. +\end{lstlisting} + +\subsection{Carga concurrente del host (no IPS)} +El mismo Docker Engine ejecuta muchos servicios ajenos a IPSExtractor. En la misma medici\'on destacaban, entre otros: + +\begin{itemize} + \item \texttt{mlflow-server} $\approx$ \textbf{1{,}86\,GiB} ($\sim$24\,\% de la RAM) + \item Airflow (scheduler + webserver + postgres) $\approx$ 530\,MiB + \item \texttt{n8n\_app} $\approx$ 291\,MiB + \item \texttt{postgresql} (instancia compartida) $\approx$ 255\,MiB + \item \texttt{minio-server} $\approx$ 136\,MiB, \texttt{uptime-kuma} $\approx$ 121\,MiB + \item Adem\'as: registry, MariaDB, MongoDB, Qdrant, Portainer, Mermaid, Metabase Postgres, Redis cache, Inmodata API, etc. +\end{itemize} + +\textbf{Consecuencia:} el host es un \emph{staging compartido}, no un laboratorio dedicado. Los SLOs de estr\'es del perfil \texttt{host-compartido-8gb} (cap.~\ref{ch:estres}) son los aplicables por defecto en este equipo. Un fallo por OOM o latencia alta \textbf{no} debe atribuirse autom\'aticamente a un bug de IPSExtractor sin revisar \texttt{docker stats} y \texttt{free -h}. + +\subsection{Requisitos previos a una campa\~na de estr\'es} +\begin{enumerate} + \item Registrar en el informe: fecha, hostname, \texttt{free -h}, salida de \texttt{docker stats --no-stream}. + \item Preferible pausar/detener MLflow y Airflow (y n8n si es posible) para liberar $\geq$2\,GiB antes de k6 ligero, o $\geq$3\,GiB antes de ST-COUNT. + \item Usar siempre \texttt{127.0.0.1:8189} (no \texttt{localhost} por IPv6). +\end{enumerate} + +\section{Fixtures recomendadas} +\begin{description} + \item[PDFs] Peque\~nos (1--2 p\'ag.), medianos, corruptos, $>$ l\'imite, con/sin texto. + \item[Excel bot] 10 / 100 / 1\,000 / 5\,000 radicados; NITs sucios; vac\'ios; columnas mal nombradas. + \item[CSV cleaning] Encodings, nulls, fechas ambiguas, montos COP. + \item[LLM] Respuestas fixture JSON v\'alido / inv\'alido / parcial (sin gastar cuota en CI). + \item[Imaging] HTML stub en CI; portal real solo en m\'aquina con VPN. +\end{description} + +\section{Variables de entorno relevantes} +\begin{longtable}{@{}p{4.2cm}p{8cm}@{}} +\caption{Variables cr\'iticas para pruebas.}\\ +\toprule +\textbf{Variable} & \textbf{Uso} \\ +\midrule +\endhead +\texttt{IPS\_DOCUMENT\_ROOT} & Montaje PDFs $\rightarrow$ \texttt{/data} \\ +\texttt{EXTRACTOR\_API\_KEY} / modelo & LLM extracci\'on \\ +\texttt{WORKER\_REPLICAS} & Escala ARQ \\ +\texttt{ASYNC\_QUEUE}, \texttt{REDIS\_URL} & Cola async \\ +\texttt{BOT\_API\_TOKEN} & Bearer bot API + agent + desktop \\ +\texttt{MINIO\_ENDPOINT}, \texttt{MINIO\_BUCKET} & S3 bot \\ +\texttt{BOT\_IMAGING\_URL} & Portal Selenium \\ +\texttt{OCR\_POOL\_SIZE}, \texttt{COUNT\_API\_MEMORY} & Tuning count-api \\ +\bottomrule +\end{longtable} + +\section{Seguridad en entornos de prueba} +\begin{itemize} + \item No usar API keys reales hardcodeadas en compose para CI/staging compartido. + \item Token de bot distinto por entorno; rotar tras pruebas p\'ublicas. + \item Datos sint\'eticos o anonimizados; nunca radicados reales en reportes p\'ublicos. +\end{itemize} diff --git a/docs/plan_pruebas/sections/10_herramientas_ci.tex b/docs/plan_pruebas/sections/10_herramientas_ci.tex new file mode 100644 index 0000000..42d23cf --- /dev/null +++ b/docs/plan_pruebas/sections/10_herramientas_ci.tex @@ -0,0 +1,47 @@ +\chapter{Herramientas profesionales y CI} +\label{ch:herramientas} + +\section{Stack de tooling} +\begin{table}[h] +\centering +\begin{tabular}{@{}llp{5.5cm}@{}} +\toprule +\textbf{Herramienta} & \textbf{Rol} & \textbf{D\'onde} \\ +\midrule +pytest & Unit/integraci\'on Python & bots, bot-descarga, extraction \\ +Vitest & Unit frontend & desktop\_app \\ +go test & Unit count-api & services-count-... \\ +k6 & Carga / estr\'es & \texttt{docs/plan\_pruebas/scripts} \\ +Docker Compose & Stack + smoke & ra\'iz del repo \\ +latexmk & Compilar este plan & \texttt{docs/plan\_pruebas} \\ +respx / httpx mock & Fake HTTP LLM/API & CI Python \\ +LocalStack / moto & MinIO local & Integraci\'on \\ +\bottomrule +\end{tabular} +\caption{Herramientas profesionales adoptadas.} +\end{table} + +\section{Pipeline CI objetivo (no implementado en esta entrega)} +Orden recomendado por PR: +\begin{enumerate} + \item \texttt{pytest} bots + bot-descarga. + \item \texttt{npm test} desktop. + \item \texttt{go test ./...} count-api. + \item \texttt{docker compose up} + curl smoke \texttt{/health/live}. + \item Nightly: k6 ST-GW-01 y ST-BOT-01 en staging. +\end{enumerate} + +\section{Compilar este documento} +\begin{lstlisting}[language=bash,caption={latexmk}] +cd docs/plan_pruebas +latexmk -pdf main.tex +\end{lstlisting} + +\section{Prioridad de implementaci\'on de tests (ROI)} +\begin{enumerate} + \item FastAPI TestClient bot-descarga (claim, cancel, auth, offline). + \item Integraci\'on gateway $\rightarrow$ bot-descarga $\rightarrow$ PG $\rightarrow$ MinIO local. + \item Estr\'es heartbeats + events (patr\'on de carga real del bot). + \item Estr\'es count-api (riesgo OOM). + \item CI m\'inimo para no perder cobertura. +\end{enumerate} diff --git a/docs/plan_pruebas/sections/11_cronograma_aceptacion.tex b/docs/plan_pruebas/sections/11_cronograma_aceptacion.tex new file mode 100644 index 0000000..1e646e0 --- /dev/null +++ b/docs/plan_pruebas/sections/11_cronograma_aceptacion.tex @@ -0,0 +1,45 @@ +\chapter{Cronograma y criterios de aceptaci\'on} +\label{ch:cronograma} + +\section{Fases sugeridas} +\begin{longtable}{@{}p{1.5cm}p{4.5cm}p{6.2cm}@{}} +\caption{Hoja de ruta de calidad.}\\ +\toprule +\textbf{Fase} & \textbf{Entrega} & \textbf{Criterio de cierre} \\ +\midrule +\endhead +0 & Este documento LaTeX + scripts k6 & PDF compilado; scripts documentados \\ +1 & CI + unitarios API bot & Pipeline verde en PR \\ +2 & Compose test + IT-BOT-01..06 & Integraci\'on bot estable \\ +3 & Extraction/cleaning + LLM mock & IT-EXT/CLN verdes \\ +4 & Campa\~nas k6 staging & SLOs cap.~\ref{ch:estres} cumplidos \\ +5 & E2E staging + Imaging & E2E-01..05 firmados \\ +6 & Chaos mensual & CH-01..06 con informe \\ +\bottomrule +\end{longtable} + +\section{Definition of Done por release} +Un release es aceptable cuando: +\begin{enumerate} + \item Checklist del ap\'endice ``Checklist de release'' completa. + \item Ning\'un caso \texttt{E2E-01}--\texttt{E2E-05} fallido sin waiver documentado. + \item ST-GW-01 y ST-BOT-01 dentro de SLO en staging. + \item Hallazgos P0/P1 de resiliencia cerrados o mitigados. +\end{enumerate} + +\section{Plantilla de informe de ejecuci\'on} +\begin{lstlisting}[language={},caption={Campos m\'inimos del informe}] +Fecha / entorno / commit +Casos ejecutados (IDs) y resultado +p95 latencia / error rate / max RSS +Jobs fallidos y causa +Costos LLM (si aplica) +Waivers y follow-ups +\end{lstlisting} + +\section{Responsables (roles)} +\begin{itemize} + \item \textbf{QA / Dev:} ejecutar unitarias e integraci\'on; mantener fixtures. + \item \textbf{Ops:} staging, k6, m\'etricas Docker/PG. + \item \textbf{Producto:} firmar E2E de negocio en release. +\end{itemize}