16 KiB
R2.0 — Plan de pruebas R2.1–R2.6
Ratificación posterior — 24 de octubre de 2026: D01–D10 y D04-R ratificadas en los términos recomendados de R2.0; variante A, Resource único con
scopeexplícito. Solo se autoriza implementar R2.1a. El registro vigente de alcance y evidencias está en 11 — Lectores compatibles. Los estados «propuesto», «recomendado» y «pendiente» del cuerpo se conservan como evidencia de la versión documental inicial y quedan actualizados por este registro; ratificación conceptual no equivale a ejecución de R2.1b–R2.6.
Estado: pruebas futuras, no tests implementados ni ejecutados por este contrato. Una decisión ratificada no equivale a una prueba pasada. Se aplica normativa de pruebas, AGENTS.md y Playwright MCP.
1. Estrategia y entorno
Unidades pequeñas y deterministas para invariantes de dominio/policy/schemas; integración real de SQL/HTTP en MariaDB metis_desk_test aislada y desechable; fronteras externas mockeadas solo cuando corresponda. No usar fixtures de producción, .env impreso, foreign_key_checks=0, sleeps arbitrarios ni pruebas cuyo único objetivo sea cubrir líneas. Barreras/promesas/latches coordinan carreras; no esperar un tiempo fijo para «suponer» que ocurrió un lock.
Los tests actuales de Resource, SoftwareInstallation y ApplicationConfiguration son puntos de extensión, no validan aún globales. APIs/DTO de consumidor mantienen fixtures legacy además de nuevos. resource.test.ts:38 resource-lifecycle.test.ts:94 software-installation.test.ts:52 application-configuration.test.ts:75 resources.integration.ts:19 software-installations.integration.ts:17 applications.integration.ts:18.
Futuros tests funcionales/listados/visuales: al menos 15 compañías, una principal A con 50 personas, 50 activos, 50 recursos locales, 50 perfiles y 50 puestos coherentes con restricciones; además B con recursos de cada familia para rechazar referencias y el resto de compañías con datos de aislamiento. Catálogo global separado, recomendado 30 productos mezclando activos/inactivos y homónimos. Contar y registrar volumen real por tabla antes de declarar cobertura; no inventar registros para completar prueba de producción. Incluir nombres largos, tildes, Unicode compuesto/descompuesto, distintas plantillas, sedes y estados. Conjuntos vacío/uno/pocos son pruebas complementarias.
R2.0 no crea nada de ese dataset. Volumen persistido utilizado ahora: cero.
2. Pruebas de invariantes y contrato
Los IDs T01–T26 están en correspondencia uno a uno con INV-01–INV-26 del documento 01. Cada prueba engloba varios casos observables, no un test trivial espejo de implementación.
| ID / invariante | Casos mínimos | Resultado esperado | Nivel / fase |
|---|---|---|---|
| T01 / INV-01 | Local con UUID válido, NULL/omitido/no UUID, dueño inexistente, UUID persistido v4 válido | Solo dueño válido; nuevo UUIDv7; no regenerar existentes; no escritura inválida | Dominio/schema/FK; R2.1 |
| T02 / INV-02 | global+NULL, company+UUID, global+UUID, company+NULL, scope NULL/desconocido/otra capitalización | Solo dos pares exactos aceptados; DB CHECK y schemas rechazan el resto | Dominio/Zod/SQL directo en test; R2.1 |
| T03 / INV-03 | Serie renombrada, UUID real distinto entre instalaciones, copia local/global usage application, cada tipo no permitido, campo local e integration manipulados | Solo serie global con campos globales; builtin de cliente no cambia resultado | Dominio/policy/HTTP; R2.1/R2.2 |
| T04 / INV-04 | Relación de A y B usa mismo global; companyId operativo NULL o ajeno, activo/perfil cruzado | Compañías/IDs operativos conservados; inválidos rechazados | Agregados/SQL/HTTP; R2.4/R2.5 |
| T05 / INV-05 | Software A con global application activa, local application, OS local; license/SMB/certificate/support/domain/general/global OS inválido | Acepta solo software válido, valida activo no retirado y pareja única | Application/HTTP; R2.4 |
| T06 / INV-06 | Perfil A con global/local application; OS local y todos los tipos restantes; profile/person/asset inactivos o ajenos; web+versión | Solo aplicación válida y contexto disponible; web no almacena versión | Dominio/Application/HTTP; R2.5 |
| T07 / INV-07 | licenseResourceId null; local A license activa/caduca hoy/caducada/inactiva; local B license; global application como licencia; cambio/desvinculación | Vigencia inclusiva UTC; enlace local; sin consumo/plazas ni matching ficticio de producto | Application/SQL/historia; R2.4 |
| T08 / INV-08 | Todas las familias locales de B enviadas en operación A, incluso manager; mismo UUID por path/batch/body | Denegar sin nombre/propietario; cero cambios; mismo error seguro que ausente | Políticas/HTTP; R2.2–R2.5 |
| T09 / INV-09 | Desactivar/repetir/reactivar global usado en A y B, con licencias locales | Solo Resource cambia; UUID/historia operativa/cantidad de vínculos intactos; status repetido no nueva revisión | Agregados/integración; R2.3–R2.5 |
| T10 / INV-10 | Sesión ausente, normal/admin inicial, authVersion revocada; leer admin/history; mutar plantilla global | 401/403 coherentes, actor del servidor y guard real, sin bypass por URL/body/header | HTTP/Identity; R2.2/R2.3 |
| T11 / INV-11 | Inspeccionar JSON de cada proyección con notas/campos extra/actores y operación B existentes | Solo whitelist; ningún campo privado/cliente/contador transversal, admin no recibe operaciones ajenas | Schema/HTTP; R2.2/R2.3 |
| T12 / INV-12 | Referencia histórica/inactiva, revisión antigua con licencia distinta; global renombrado | UUID y snapshots conservados; referencia mínima actual legible; no se promete nombre histórico congelado | Mapper/SQL/listado; R2.1/R2.4/R2.5 |
| T13 / INV-13 | Update de scope/owner/templateId; cambio de resourceId o destino operativo; mismo payload normalizado | Schema/dominio rechazan campos/cambios fijos; edición idéntica no nueva revisión | Dominio/HTTP; R2.1–R2.5 |
| T14 / INV-14 | GET/list local con globales existentes; CRUD local por ID global; consumidores remoto/Access/certificados | Respuesta legacy exacta, sin globales; UUID global no accede por ruta local | Contrato/integración; R2.1/R2.2 |
| T15 / INV-15 | Desactivar y asociar en ambos órdenes; update plantilla y asociación; borrado local usado concurrente; rutas con Access | Resultados seriales descritos en 05, sin TOCTOU ni lock order inverso; retries no duplican efectos | Integración MariaDB con barreras; R2.2/R2.4/R2.5 |
| T16 / INV-16 | Inactivo + nuevo pending/configured/terminal; existente notas sin cambio, retirada, cambio version/delivery/state; cerrado | Nueva asociación siempre rechazada; notas/retirada válidas conservadas; reconfiguración dependiente rechazada; closed sin edición | Application/HTTP; R2.4/R2.5 |
| T17 / INV-17 | Homónimos A/global, dos globales mismo nombre, fabricante ausente/distinto, Office 2021 frente a Microsoft 365, NOD32 con cifras/tildes | IDs distintos para productos distintos; equivalencia confirmada reutiliza existente sin POST nuevo; no merge/unique por nombre global; aviso fuerte solo D07; local NAME_EXISTS intacto | Dominio/consulta/UX; R2.3/R2.6 |
| T18 / INV-18 | Mismo creationId/payload/actor concurrente, retry tras timeout/reinicio y tras edición posterior; payload/actor distinto, ID de local | Una raíz/primera revisión; retry válido retorna mismo ID y estado actual; conflicto 409 sin datos ajenos | Integración/HTTP; R2.3 |
| T19 / INV-19 | Cliente legacy/nuevo contra legacy/scoped/solo locales/globales usados; strict parsing local y cabecera falsa sin privilegio | Contrato local exacto; compatibilidad señalada, upgrade_required donde corresponde; header no concede permiso | Contratos/HTTP/UI; R2.1–R2.5 |
| T20 / INV-20 | Migración repetida e interrumpida por paso, INSERT inválido, FK dependiente, restore de constraints, CHECK ON/OFF detectado | Backfill sin pérdida; inválidos rechazados con checks ON; no servicio en schema parcial | MariaDB 11.8; R2.1b |
| T21 / INV-21 | Plantilla global cambia nombre/campos/required/retirada con valor y sin valor, dos compañías y productos globales; fallo a mitad DML | Especificaciones actuales sincronizadas, snapshots antiguos intactos; fallo revierte todos los DML; no NULL en UniqueID local | Dominio/SQL; R2.1 |
| T22 / INV-22 | Renombrar/desactivar desde manager; A/B abiertos, foco/reconexión, logout/403, query fuera de página | Invalidación dirigida; refetch actualiza nombre/needsReview; no caché admin pública ni selección borrada; no push supuesto | Query/UI/HTTP; R2.3–R2.5 |
| T23 / INV-23 | /resource-catalog/global y nuevos productos, registros de relaciones tipadas y módulos |
Contratos de plantillas originales, sin nuevo módulo/proveedor ficticio ni ensanchamiento de capabilities | Contratos/composición; R2.2/R2.3 |
| T24 / INV-24 | Flags inválidas/combinaciones, catálogo off con existentes, backend V0 y schema parcial, cliente no compatible | Fallo cerrado/gate bloqueado; flags off no ocultan lectura/recuperación; ningún global producido temprano | Despliegue/HTTP; R2.1–R2.5 |
| T25 / INV-25 | Avisos/coexistencia inicial; intento de conversión owner/scope; plan de futura sucesión con colisión | Cero migración implícita, UUID/historia intactos; consolidación no ejecutable sin contrato adicional | Integración/UX documental; R2.6 |
| T26 / INV-26 | Global usado por perfil/software en ficha/puesto/entorno y proceso soportado, dashboard con globales sin usos y locales | Nombres/origen legibles por lote, métricas coherentes sin contar producto como instalación; proceso no inventa consumidores | Integración/Query/HTTP; R2.4/R2.5 |
3. Seguridad y matriz de consumidores
S01–S12 se definen en 03 y se ejecutan vía HTTP con usuario normal/admin, sesiones propias y requestId; mapear a T08/T10/T11/T15/T19. No se valida permiso solo mirando si hay un botón. Comprobar también Origin erróneo/ausente y CSRF erróneo/ausente, cabeceras desconocidas, query/body extras y payloads con scopes falsificados. Cerrar sesión o cambiar authVersion entre peticiones debe denegar la siguiente aunque se mantengan datos cacheados.
M01: parametrizar todas las celdas de las matrices de 06. Para P, ejecutar un caso válido; para R, intentar asociación/lectura y verificar error y cero efecto; para C, probar condiciones satisfechas y al menos cada condición fallida; para H, resolver UUID y probar recuperación admisible y alta nueva denegada. La matriz distingue local A/B, active/inactive y tipos; no basta usar un único recurso global y afirmar aislamiento.
No hacer una petición por cada ID si se comprueba lote: 1/100/101 UUIDs, vacíos, repetidos, formato inválido y mezcla de accesible/inaccesible. Error técnico de DB debe ser 500 saneado, no transformar todo a unavailable. Ausente, ajeno y tipo erróneo no revelan nombres ni propietarios.
4. API, SQL y rendimiento observable
A01 API: validar con schemas de request/response en ambos extremos; límites search 0/100/101, pageSize 0/1/100/101, cursor omitido/válido/otro propósito/contexto/corrupto/sobrelímite, literal con %, _, comillas y tildes. No cambiar semántica de nombres ni usar interpolación SQL. UNION no duplica por ID, conserva homónimos y aplica todos los filtros antes del límite. Paginación estática no omite ni repite filas; renombrado concurrente se recupera refrescando sin prometer snapshot.
P01 Persistencia: capturar SHOW CREATE antes/después y comparar acciones ON DELETE/UPDATE, tipos/collation/nullable e índices; comprobar tanto FKs current como history; prueba de referencia únicamente histórica protege Resource. Ensayar recuperar DDL interrumpido sin transacción ficticia. Plan rollback sin global y con primer global son escenarios distintos. No inferir compatibilidad porque QueryInterface compile.
P02 Consultas: instrumentar conteo/tamaño y EXPLAIN de candidatos catálogo/global+local con dataset reproducible. La carga debe usar proyección mínima y consulta por lote, sin historial de producto ni una llamada por fila. Establecer baseline real, no umbral de latencia inventado. Si el lock del catálogo causa contención inadmisible, no eludirlo sin ADR y prueba equivalente de serialización.
5. UI/Playwright y aceptación visual
U01 Catálogo: listado de entidades con búsqueda visible, fabricante/origen/estado, filtros/orden/página persistidos al volver, alta a derecha por permiso, edición modal propia. Inactivos identificables; público sin notas/actores. Vacío verdadero distinto de sin coincidencias, error, actualización o permiso denegado.
U02 Selectores: Chrome recupera global y local A, nunca B; no paso previo de scope; nombres idénticos conservan IDs/origen. Elegir/paginar/volver no pierde selección; búsqueda no guarda; cancelar modal mantiene formulario padre y foco. Opción actual inactiva se resuelve aparte y no se ofrece para nueva asociación. Error conserva trabajo; guardado repetido deshabilitado mientras pending; alta global reutiliza creationId al reintentar. Licencia de A aparte, versión y estado no autocompletados.
U03 Perfiles/software: destino fijo al editar; delivery web borra versión de forma explícita; estados y notas propios; referenciar global en un flujo no crea el otro. Desactivar y refetch muestra revisión de abiertas con causas correctas, cerradas conservadas. Notas/retirada accesibles con producto inactivo.
U04 Compactos: en dashboard/ficha usar CompactTable/CompactList/CollectionPreview con identidad, versión/estado/origen y enlace correcto; total solo si conocido, fuente fallida no se presenta como colección vacía. Componentes no agregan búsqueda/paginación por su cuenta. Navegación regresa a compañía/perfil/activo anterior.
U05 Accesibilidad/responsive: escritorio y 320 px, zoom 200/400%, teclado completo, lectura de etiquetas/errores/estados, foco visible y retorno, cierre por Escape/cancelación, alturas estables y scroll interno. Picker con selection compacta inicial y selección por zona no interactiva con alternativa de teclado. i18n es/en, celdas ausentes —, valores cero/false preservados. No afirmar WCAG sin evidencia efectiva.
Playwright con servidor MCP y procedimiento del repo, Docker/navegador fijados, sin instalar Chromium en WSL ni publicar puertos MCP. Confirmar origen/puerto Vite real y API de prueba. Guardar capturas y evidencias de interacción con datos sintéticos autorizados, nunca capturas de clientes reales para completar volumen. No se ejecuta nada de esto en R2.0.
6. Trazabilidad de riesgos de auditoría
| Riesgo previo | Pruebas/gate |
|---|---|
| A01 permisos globales; A02 ACL presupuesta | T10, S01/S05/S11/S12, G3 |
| A03 ensanchar consumidores | T05–T08/T14, M01, G3/G4/G5 |
| A04 DTO/mappers; A05 FKs/DDL | T01/T02/T19/T20, P01, G1/G2 |
| A06 borrado usado; A07 propagación | T12/T15/T20/T21, G2/G3 |
| A08 duplicados; A17 unicidad/reintentos | T17/T18/T25, G3b/G6 |
| A09 payload; A10 N+1 | A01/P02 y U02, G4/G5 |
| A11 caché; A13 dashboard | T22/T26/U04, G4/G5 |
| A12 TOCTOU | T15, S10, G3/G4/G5 |
| A14 privacidad; A15 plantilla/ámbito | T03/T10/T11/T13/T21, S06/S08/S11, G3 |
| A16 fronteras; A18 historia/nombres | T12/T23/T26, G3–G5 |
Las condiciones P/R/C/H, los invariantes y las operaciones de API son fuentes de casos, no tres implementaciones duplicadas de la misma regla. Centralizar fixtures/policies conforme al módulo propietario, sin trasladar validación de negocio a tests de JSX.
7. Salida por fase
Pruebas apropiadas al cambio y obligatorias transversales: pnpm typecheck, pnpm lint, pnpm test, pnpm check y pnpm build, más integración/Playwright/ensayo DDL de la fase. Registrar comandos/resultados/fallos previos y nuevos sin ocultar limitaciones; no volver a ejecutar indiscriminadamente si no hay cambio/fallo pendiente. Una falla de integridad/autorización impide activar aunque otras suites pasen.
R2.0 entrega esta matriz y validación documental; no declara implementados T01–T26, S01–S12, M01, A01, P01/P02 ni U01–U05. Las ejecuciones históricas de la auditoría siguen allí como evidencia de otra fase, no como resultados actuales de Resources v2.