Refactorizar y mejorar suite de tests con validaciones robustas
Problemas resueltos: - Eliminada dependencia de UUIDs hardcodeados en tests - Agregadas validaciones específicas de valores esperados - Implementado cleanup automático de datos de test Cambios principales: Tests organizados por categoría (7 archivos nuevos): - test_structure.sql: 8 tests de estructura de BD - test_constraints.sql: 6 tests de validaciones - test_triggers.sql: 3 tests de triggers automáticos - test_queries.sql: 5 tests de queries típicas - test_functions.sql: 3 tests de funciones auxiliares - test_edge_cases.sql: 7 tests de casos límite - test_indexes.sql: 6 tests de uso de índices Mejoras implementadas: - Cada test genera sus propios datos dinámicamente - Tests usan bloques DO $$ con UUIDs generados - Validaciones específicas con valores esperados - Cleanup automático al finalizar cada test - Tests de casos edge (arrays vacíos, NULL, límites) - Verificación de uso de índices con EXPLAIN test_all.sql actualizado: - Ahora ejecuta todos los archivos organizados - Total: ~38 tests independientes y robustos - Progreso visual por categoría - ASCII art y mejor presentación Todos los tests verificados y funcionando correctamente
This commit is contained in:
@@ -1,493 +1,138 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Validación
|
||||
-- rioCata - Suite Completa de Tests
|
||||
-- ============================================
|
||||
-- Este script ejecuta tests para validar:
|
||||
-- 1. Estructura de tablas y constraints
|
||||
-- 2. Triggers (updated_at, puntaje_final)
|
||||
-- 3. Validaciones de arrays y JSONB
|
||||
-- 4. Queries típicas
|
||||
-- 5. Funciones auxiliares
|
||||
-- Ejecuta todos los tests organizados por categoría
|
||||
-- ============================================
|
||||
|
||||
\echo ''
|
||||
\echo '██████╗ ██╗ ██████╗ ██████╗ █████╗ ████████╗ █████╗ '
|
||||
\echo '██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗╚══██╔══╝██╔══██╗'
|
||||
\echo '██████╔╝██║██║ ██║██║ ███████║ ██║ ███████║'
|
||||
\echo '██╔══██╗██║██║ ██║██║ ██╔══██║ ██║ ██╔══██║'
|
||||
\echo '██║ ██║██║╚██████╔╝╚██████╗██║ ██║ ██║ ██║ ██║'
|
||||
\echo '╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝'
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo 'rioCata - Test Suite'
|
||||
\echo 'Suite Completa de Tests - rioCata'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
\echo 'Esta suite ejecuta todos los tests organizados en categorías:'
|
||||
\echo ' 1. Estructura de Base de Datos'
|
||||
\echo ' 2. Constraints y Validaciones'
|
||||
\echo ' 3. Triggers Automáticos'
|
||||
\echo ' 4. Queries Típicas'
|
||||
\echo ' 5. Funciones Auxiliares'
|
||||
\echo ' 6. Casos Límite (Edge Cases)'
|
||||
\echo ' 7. Uso de Índices'
|
||||
\echo ''
|
||||
\echo 'Iniciando tests...'
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- 1. Tests de Estructura
|
||||
-- ============================================
|
||||
\i postgres/tests/test_structure.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '1/7 Estructura completada ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 1: Verificar que las tablas existen
|
||||
-- 2. Tests de Constraints
|
||||
-- ============================================
|
||||
\echo '[TEST 1] Verificando existencia de tablas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
tabla_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO tabla_count
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name IN ('sesion', 'sesion_participante', 'muestra', 'evaluacion');
|
||||
|
||||
IF tabla_count = 4 THEN
|
||||
RAISE NOTICE '✓ Todas las tablas principales existen (4/4)';
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Faltan tablas. Encontradas: %/4', tabla_count;
|
||||
END IF;
|
||||
|
||||
-- Verificar tabla auth.users
|
||||
SELECT COUNT(*) INTO tabla_count
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'auth' AND table_name = 'users';
|
||||
|
||||
IF tabla_count = 1 THEN
|
||||
RAISE NOTICE '✓ Tabla auth.users existe';
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Tabla auth.users no existe';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 2: Verificar tipo ENUM defecto_tipo
|
||||
-- ============================================
|
||||
\echo '[TEST 2] Verificando tipo ENUM defecto_tipo...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
enum_exists boolean;
|
||||
BEGIN
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM pg_type WHERE typname = 'defecto_tipo'
|
||||
) INTO enum_exists;
|
||||
|
||||
IF enum_exists THEN
|
||||
RAISE NOTICE '✓ Tipo ENUM defecto_tipo existe';
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Tipo ENUM defecto_tipo no existe';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 3: Verificar triggers
|
||||
-- ============================================
|
||||
\echo '[TEST 3] Verificando triggers...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
trigger_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO trigger_count
|
||||
FROM information_schema.triggers
|
||||
WHERE trigger_name IN ('trg_eval_updated_at', 'trg_eval_score_bi');
|
||||
|
||||
IF trigger_count = 2 THEN
|
||||
RAISE NOTICE '✓ Todos los triggers existen (2/2)';
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Faltan triggers. Encontrados: %/2', trigger_count;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 4: Verificar índices
|
||||
-- ============================================
|
||||
\echo '[TEST 4] Verificando índices...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
index_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO index_count
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'public'
|
||||
AND indexname LIKE 'idx_%';
|
||||
|
||||
IF index_count >= 15 THEN
|
||||
RAISE NOTICE '✓ Índices creados correctamente (% encontrados)', index_count;
|
||||
ELSE
|
||||
RAISE WARNING '⚠ Se esperaban al menos 15 índices, se encontraron: %', index_count;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 5: Test de constraint - tazas_no_uniformes válidas
|
||||
-- ============================================
|
||||
\echo '[TEST 5] Validando constraint tazas_no_uniformes (valores 1-5)...'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Intentar insertar valor inválido (6)
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, tazas_no_uniformes
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1}}'::jsonb,
|
||||
ARRAY[6]::smallint[]
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint tazas_no_uniformes NO funcionó (aceptó valor 6)';
|
||||
EXCEPTION
|
||||
WHEN check_violation THEN
|
||||
RAISE NOTICE '✓ Constraint tazas_no_uniformes funciona correctamente';
|
||||
END;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 6: Test de constraint - gustos_predominantes (máximo 2)
|
||||
-- ============================================
|
||||
\echo '[TEST 6] Validando constraint gustos_predominantes (máximo 2 elementos)...'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Intentar insertar 3 gustos (debería fallar)
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, gustos_predominantes
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1}}'::jsonb,
|
||||
ARRAY['Ácido', 'Dulce', 'Amargo']::text[]
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint gustos_predominantes NO funcionó (aceptó 3 elementos)';
|
||||
EXCEPTION
|
||||
WHEN check_violation THEN
|
||||
RAISE NOTICE '✓ Constraint gustos_predominantes funciona correctamente';
|
||||
END;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 7: Test de constraint - sensacion_en_boca (valores válidos)
|
||||
-- ============================================
|
||||
\echo '[TEST 7] Validando constraint sensacion_en_boca (valores permitidos)...'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Intentar insertar valor no permitido
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, sensacion_en_boca
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1}}'::jsonb,
|
||||
ARRAY['Raro', 'Extraño']::text[]
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint sensacion_en_boca NO funcionó';
|
||||
EXCEPTION
|
||||
WHEN check_violation THEN
|
||||
RAISE NOTICE '✓ Constraint sensacion_en_boca funciona correctamente';
|
||||
END;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 8: Test de constraint - rangos de intensidades
|
||||
-- ============================================
|
||||
\echo '[TEST 8] Validando constraint rangos de intensidades (descriptiva 1-15, afectiva 1-10)...'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Intentar insertar descriptiva > 15
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":20,"afectiva":5}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint de rangos NO funcionó (aceptó descriptiva=20)';
|
||||
EXCEPTION
|
||||
WHEN check_violation THEN
|
||||
RAISE NOTICE '✓ Constraint rangos de intensidades funciona (descriptiva)';
|
||||
END;
|
||||
|
||||
-- Intentar insertar afectiva > 10
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":15}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint de rangos NO funcionó (aceptó afectiva=15)';
|
||||
EXCEPTION
|
||||
WHEN check_violation THEN
|
||||
RAISE NOTICE '✓ Constraint rangos de intensidades funciona (afectiva)';
|
||||
END;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 9: Test de trigger - puntaje_final se calcula automáticamente
|
||||
-- ============================================
|
||||
\echo '[TEST 9] Validando trigger de cálculo automático de puntaje_final...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
puntaje_calculado int;
|
||||
puntaje_esperado int := 75; -- Suma de afectivos: 9+9+10+9+9+10+9+10 = 75
|
||||
BEGIN
|
||||
-- Verificar evaluación existente
|
||||
SELECT puntaje_final INTO puntaje_calculado
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
|
||||
AND sesion_participante_id = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';
|
||||
|
||||
IF puntaje_calculado = puntaje_esperado THEN
|
||||
RAISE NOTICE '✓ Trigger puntaje_final funciona correctamente (% = %)', puntaje_calculado, puntaje_esperado;
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Puntaje calculado (%) no coincide con esperado (%)', puntaje_calculado, puntaje_esperado;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 10: Test de constraint UNIQUE - una evaluación por participante por muestra
|
||||
-- ============================================
|
||||
\echo '[TEST 10] Validando constraint UNIQUE (una evaluación por participante/muestra)...'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Intentar insertar evaluación duplicada
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION '✗ El constraint UNIQUE NO funcionó (permitió duplicado)';
|
||||
EXCEPTION
|
||||
WHEN unique_violation THEN
|
||||
RAISE NOTICE '✓ Constraint UNIQUE funciona correctamente';
|
||||
END;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 11: Query típica - Promedio de parámetro afectivo
|
||||
-- ============================================
|
||||
\echo '[TEST 11] Probando query: Promedio de dulzor afectivo por sesión...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
avg_dulzor numeric;
|
||||
BEGIN
|
||||
SELECT AVG( ((e.intensidades->'dulzor'->>'afectiva')::int) )
|
||||
INTO avg_dulzor
|
||||
FROM sesion s
|
||||
JOIN muestra m ON m.sesion_id = s.id
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
WHERE s.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
|
||||
|
||||
IF avg_dulzor IS NOT NULL THEN
|
||||
RAISE NOTICE '✓ Query promedio funciona. Dulzor promedio: %', ROUND(avg_dulzor, 2);
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Query promedio falló';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 12: Query típica - Buscar por defecto
|
||||
-- ============================================
|
||||
\echo '[TEST 12] Probando query: Buscar evaluaciones con defecto Fenólico...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
defecto_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO defecto_count
|
||||
FROM evaluacion
|
||||
WHERE defecto = 'Fenólico';
|
||||
|
||||
IF defecto_count > 0 THEN
|
||||
RAISE NOTICE '✓ Query por defecto funciona. Evaluaciones con defecto Fenólico: %', defecto_count;
|
||||
ELSE
|
||||
RAISE WARNING '⚠ No se encontraron evaluaciones con defecto Fenólico (puede ser normal)';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 13: Query típica - Buscar por taza defectuosa específica
|
||||
-- ============================================
|
||||
\echo '[TEST 13] Probando query: Buscar evaluaciones donde taza 5 fue defectuosa...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
taza_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO taza_count
|
||||
FROM evaluacion
|
||||
WHERE tazas_defectuosas @> ARRAY[5]::smallint[];
|
||||
|
||||
IF taza_count > 0 THEN
|
||||
RAISE NOTICE '✓ Query con array @> funciona. Evaluaciones con taza 5 defectuosa: %', taza_count;
|
||||
ELSE
|
||||
RAISE WARNING '⚠ No se encontraron evaluaciones con taza 5 defectuosa';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 14: Query típica - Top muestras por puntaje
|
||||
-- ============================================
|
||||
\echo '[TEST 14] Probando query: Top 3 muestras por puntaje final...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
top_muestra text;
|
||||
top_puntaje int;
|
||||
BEGIN
|
||||
SELECT m.codigo, e.puntaje_final
|
||||
INTO top_muestra, top_puntaje
|
||||
FROM muestra m
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
JOIN sesion_participante sp ON sp.id = e.sesion_participante_id
|
||||
WHERE m.sesion_id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||
ORDER BY e.puntaje_final DESC
|
||||
LIMIT 1;
|
||||
|
||||
IF top_muestra IS NOT NULL THEN
|
||||
RAISE NOTICE '✓ Query top muestras funciona. Mejor muestra: % (puntaje: %)', top_muestra, top_puntaje;
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Query top muestras falló';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 15: Función auxiliar - get_promedio_parametro_afectivo
|
||||
-- ============================================
|
||||
\echo '[TEST 15] Probando función: get_promedio_parametro_afectivo...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
avg_acidez numeric;
|
||||
BEGIN
|
||||
SELECT get_promedio_parametro_afectivo(
|
||||
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
||||
'acidez'
|
||||
) INTO avg_acidez;
|
||||
|
||||
IF avg_acidez IS NOT NULL THEN
|
||||
RAISE NOTICE '✓ Función get_promedio_parametro_afectivo funciona. Acidez promedio: %', ROUND(avg_acidez, 2);
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Función get_promedio_parametro_afectivo falló';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 16: Función auxiliar - get_top_muestras
|
||||
-- ============================================
|
||||
\echo '[TEST 16] Probando función: get_top_muestras...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
resultado record;
|
||||
count_resultados int := 0;
|
||||
BEGIN
|
||||
FOR resultado IN
|
||||
SELECT * FROM get_top_muestras('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 3)
|
||||
LOOP
|
||||
count_resultados := count_resultados + 1;
|
||||
RAISE NOTICE ' - %: % puntos (catador: %)', resultado.muestra_codigo, resultado.puntaje_final, resultado.catador_nombre;
|
||||
END LOOP;
|
||||
|
||||
IF count_resultados > 0 THEN
|
||||
RAISE NOTICE '✓ Función get_top_muestras funciona. Resultados: %', count_resultados;
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Función get_top_muestras no devolvió resultados';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 17: Query con índice funcional - filtrar por acidez afectiva
|
||||
-- ============================================
|
||||
\echo '[TEST 17] Probando query con índice funcional: acidez afectiva >= 8...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
count_acidez int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO count_acidez
|
||||
FROM evaluacion
|
||||
WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8;
|
||||
|
||||
IF count_acidez >= 0 THEN
|
||||
RAISE NOTICE '✓ Query con índice funcional funciona. Evaluaciones con acidez >= 8: %', count_acidez;
|
||||
ELSE
|
||||
RAISE EXCEPTION '✗ Query con índice funcional falló';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST 18: Validar datos de prueba cargados
|
||||
-- ============================================
|
||||
\echo '[TEST 18] Validando que los datos de prueba se cargaron correctamente...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
count_users int;
|
||||
count_sesiones int;
|
||||
count_muestras int;
|
||||
count_evaluaciones int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO count_users FROM auth.users;
|
||||
SELECT COUNT(*) INTO count_sesiones FROM sesion;
|
||||
SELECT COUNT(*) INTO count_muestras FROM muestra;
|
||||
SELECT COUNT(*) INTO count_evaluaciones FROM evaluacion;
|
||||
|
||||
IF count_users >= 3 AND count_sesiones >= 1 AND count_muestras >= 3 AND count_evaluaciones >= 5 THEN
|
||||
RAISE NOTICE '✓ Datos de prueba cargados:';
|
||||
RAISE NOTICE ' - Usuarios: %', count_users;
|
||||
RAISE NOTICE ' - Sesiones: %', count_sesiones;
|
||||
RAISE NOTICE ' - Muestras: %', count_muestras;
|
||||
RAISE NOTICE ' - Evaluaciones: %', count_evaluaciones;
|
||||
ELSE
|
||||
RAISE WARNING '⚠ Algunos datos de prueba pueden faltar:';
|
||||
RAISE WARNING ' - Usuarios: % (esperado: >= 3)', count_users;
|
||||
RAISE WARNING ' - Sesiones: % (esperado: >= 1)', count_sesiones;
|
||||
RAISE WARNING ' - Muestras: % (esperado: >= 3)', count_muestras;
|
||||
RAISE WARNING ' - Evaluaciones: % (esperado: >= 5)', count_evaluaciones;
|
||||
END IF;
|
||||
END $$;
|
||||
\i postgres/tests/test_constraints.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo 'Tests completados'
|
||||
\echo '2/7 Constraints completados ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
\echo 'Ejecuta queries de ejemplo con:'
|
||||
\echo ' \i postgres/tests/example_queries.sql'
|
||||
|
||||
-- ============================================
|
||||
-- 3. Tests de Triggers
|
||||
-- ============================================
|
||||
\i postgres/tests/test_triggers.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '3/7 Triggers completados ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- 4. Tests de Queries
|
||||
-- ============================================
|
||||
\i postgres/tests/test_queries.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '4/7 Queries completadas ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- 5. Tests de Funciones
|
||||
-- ============================================
|
||||
\i postgres/tests/test_functions.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '5/7 Funciones completadas ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- 6. Tests de Edge Cases
|
||||
-- ============================================
|
||||
\i postgres/tests/test_edge_cases.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '6/7 Edge Cases completados ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- 7. Tests de Índices
|
||||
-- ============================================
|
||||
\i postgres/tests/test_indexes.sql
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo '7/7 Índices completados ✓'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- Resumen Final
|
||||
-- ============================================
|
||||
\echo ''
|
||||
\echo '╔════════════════════════════════════════╗'
|
||||
\echo '║ SUITE COMPLETA DE TESTS FINALIZADA ║'
|
||||
\echo '╚════════════════════════════════════════╝'
|
||||
\echo ''
|
||||
\echo 'Categorías ejecutadas:'
|
||||
\echo ' ✓ Estructura (8 tests)'
|
||||
\echo ' ✓ Constraints (6 tests)'
|
||||
\echo ' ✓ Triggers (3 tests)'
|
||||
\echo ' ✓ Queries (5 tests)'
|
||||
\echo ' ✓ Funciones (3 tests)'
|
||||
\echo ' ✓ Edge Cases (7 tests)'
|
||||
\echo ' ✓ Índices (6 tests)'
|
||||
\echo ''
|
||||
\echo 'Total: ~38 tests ejecutados'
|
||||
\echo ''
|
||||
\echo 'Para ejecutar categorías individuales:'
|
||||
\echo ' \\i postgres/tests/test_structure.sql'
|
||||
\echo ' \\i postgres/tests/test_constraints.sql'
|
||||
\echo ' \\i postgres/tests/test_triggers.sql'
|
||||
\echo ' \\i postgres/tests/test_queries.sql'
|
||||
\echo ' \\i postgres/tests/test_functions.sql'
|
||||
\echo ' \\i postgres/tests/test_edge_cases.sql'
|
||||
\echo ' \\i postgres/tests/test_indexes.sql'
|
||||
\echo ''
|
||||
\echo 'Para ver queries de ejemplo:'
|
||||
\echo ' \\i postgres/tests/example_queries.sql'
|
||||
\echo ''
|
||||
|
||||
454
postgres/tests/test_constraints.sql
Normal file
454
postgres/tests/test_constraints.sql
Normal file
@@ -0,0 +1,454 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Constraints
|
||||
-- ============================================
|
||||
-- Tests que verifican la validación de constraints
|
||||
-- de la base de datos sin depender de datos hardcodeados
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Constraints'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint tazas_no_uniformes (solo valores 1-5)
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 1] Validando tazas_no_uniformes (valores 1-5)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint1@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-1', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M1');
|
||||
|
||||
-- Test 1: Valores válidos (1-5) deben pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, tazas_no_uniformes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[1,2,3,4,5]::smallint[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta valores válidos 1-5';
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó valores válidos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 2: Valor inválido (0) debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, tazas_no_uniformes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[0]::smallint[]
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó valor inválido 0';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente valor 0';
|
||||
END;
|
||||
|
||||
-- Test 3: Valor inválido (6) debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, tazas_no_uniformes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[6]::smallint[]
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó valor inválido 6';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente valor 6';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint tazas_no_uniformes funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint tazas_defectuosas (solo valores 1-5)
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 2] Validando tazas_defectuosas (valores 1-5)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint2@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-2', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M2');
|
||||
|
||||
-- Test: Valor inválido (-1) debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, tazas_defectuosas
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[-1]::smallint[]
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó valor inválido -1';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente valor -1';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint tazas_defectuosas funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint gustos_predominantes (máximo 2 elementos)
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 3] Validando gustos_predominantes (máximo 2 elementos)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint3@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-3', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
-- Test 1: 0 elementos debe pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, gustos_predominantes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[]::text[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta 0 elementos';
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó 0 elementos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 2: 1 elemento debe pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, gustos_predominantes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY['Dulce']::text[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta 1 elemento';
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó 1 elemento: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 3: 2 elementos debe pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, gustos_predominantes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY['Dulce', 'Ácido']::text[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta 2 elementos';
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó 2 elementos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 4: 3 elementos debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, gustos_predominantes
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY['Dulce', 'Ácido', 'Amargo']::text[]
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó 3 elementos';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente 3 elementos';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint gustos_predominantes funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint sensacion_en_boca (valores permitidos)
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 4] Validando sensacion_en_boca (valores permitidos)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint4@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-4', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M4');
|
||||
|
||||
-- Test 1: Valores válidos deben pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, sensacion_en_boca
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY['Áspero', 'Suave', 'Aceitoso', 'Metálico', 'Astringente']::text[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta todos los valores permitidos';
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó valores válidos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 2: Valor inválido debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, sensacion_en_boca
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY['Raro', 'Extraño']::text[]
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó valores inválidos';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente valores inválidos';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint sensacion_en_boca funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint rangos de intensidades
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 5] Validando rangos intensidades (descriptiva 1-15, afectiva 1-10)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint5@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-5', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M5');
|
||||
|
||||
-- Test 1: Valores en límites válidos (1 y 15 para descriptiva)
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1},"aroma":{"descriptiva":15,"afectiva":10}}'::jsonb
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta límites válidos (descriptiva: 1 y 15, afectiva: 1 y 10)';
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó límites válidos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 2: descriptiva < 1 debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":0,"afectiva":5}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó descriptiva=0';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente descriptiva < 1';
|
||||
END;
|
||||
|
||||
-- Test 3: descriptiva > 15 debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":16,"afectiva":5}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó descriptiva=16';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente descriptiva > 15';
|
||||
END;
|
||||
|
||||
-- Test 4: afectiva < 1 debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":0}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó afectiva=0';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente afectiva < 1';
|
||||
END;
|
||||
|
||||
-- Test 5: afectiva > 10 debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":11}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Aceptó afectiva=11';
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente afectiva > 10';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint rangos de intensidades funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Constraint UNIQUE (una evaluación por participante/muestra)
|
||||
-- ============================================
|
||||
\echo '[CONSTRAINT 6] Validando constraint UNIQUE (una evaluación por participante/muestra)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_constraint6@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-CONST-6', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M6');
|
||||
|
||||
-- Test 1: Primera evaluación debe pasar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta primera evaluación';
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó primera evaluación: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Test 2: Segunda evaluación de mismo participante/muestra debe fallar
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":7,"afectiva":8}}'::jsonb
|
||||
);
|
||||
RAISE EXCEPTION ' ✗ Permitió evaluación duplicada';
|
||||
EXCEPTION WHEN unique_violation THEN
|
||||
RAISE NOTICE ' ✓ Rechaza correctamente evaluación duplicada';
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Constraint UNIQUE funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Constraints completados'
|
||||
\echo '=========================================='
|
||||
432
postgres/tests/test_edge_cases.sql
Normal file
432
postgres/tests/test_edge_cases.sql
Normal file
@@ -0,0 +1,432 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Casos Límite (Edge Cases)
|
||||
-- ============================================
|
||||
-- Tests que verifican comportamiento en casos límite
|
||||
-- y situaciones especiales
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Casos Límite'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Arrays vacíos son válidos
|
||||
-- ============================================
|
||||
\echo '[EDGE 1] Validando arrays vacíos...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge1@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-1', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M1');
|
||||
|
||||
-- Test: evaluación con todos los arrays vacíos
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades,
|
||||
tazas_no_uniformes, tazas_defectuosas,
|
||||
sensacion_en_boca, gustos_predominantes
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[]::smallint[], ARRAY[]::smallint[],
|
||||
ARRAY[]::text[], ARRAY[]::text[]
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta arrays vacíos correctamente';
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó arrays vacíos: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Arrays vacíos funcionan correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Campos opcionales en NULL
|
||||
-- ============================================
|
||||
\echo '[EDGE 2] Validando campos opcionales en NULL...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge2@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-2', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M2');
|
||||
|
||||
-- Test: evaluación con campos opcionales en NULL
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades,
|
||||
defecto, otras_notas
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
NULL, NULL
|
||||
);
|
||||
RAISE NOTICE ' ✓ Acepta campos opcionales NULL';
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó campos NULL: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Campos opcionales NULL funcionan correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: JSONB con solo un parámetro
|
||||
-- ============================================
|
||||
\echo '[EDGE 3] Validando intensidades con un solo parámetro...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
puntaje int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge3@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-3', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
-- Test: solo un parámetro en intensidades
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":7}}'::jsonb
|
||||
) RETURNING puntaje_final INTO puntaje;
|
||||
|
||||
IF puntaje = 7 THEN
|
||||
RAISE NOTICE ' ✓ Acepta un solo parámetro y calcula puntaje correcto: %', puntaje;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje incorrecto con un parámetro: % (esperado: 7)', puntaje;
|
||||
END IF;
|
||||
EXCEPTION WHEN check_violation THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó un solo parámetro: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Un solo parámetro funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Valores descriptivos NULL con afectivos presentes
|
||||
-- ============================================
|
||||
\echo '[EDGE 4] Validando descriptiva NULL con afectiva presente...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
puntaje int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge4@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-4', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M4');
|
||||
|
||||
-- Test: impresionGlobal con descriptiva NULL (caso común)
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"impresionGlobal":{"descriptiva":null,"afectiva":8}}'::jsonb
|
||||
) RETURNING puntaje_final INTO puntaje;
|
||||
|
||||
IF puntaje = 8 THEN
|
||||
RAISE NOTICE ' ✓ Acepta descriptiva NULL y calcula puntaje correcto: %', puntaje;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje incorrecto: % (esperado: 8)', puntaje;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó descriptiva NULL: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Descriptiva NULL funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: JSONB arrays con múltiples elementos
|
||||
-- ============================================
|
||||
\echo '[EDGE 5] Validando arrays JSONB con múltiples notas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
notas_count int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge5@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-5', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M5');
|
||||
|
||||
-- Test: múltiples notas de fragancia/aroma
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades,
|
||||
fragancia_aroma_notas, sabor_notas
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
'[
|
||||
{"categoria":"Afrutado","subcategoria":"Cítricos","notaEspecifica":"Naranja"},
|
||||
{"categoria":"Floral","subcategoria":"Jazmín","notaEspecifica":null},
|
||||
{"categoria":"Especiado","subcategoria":"Canela","notaEspecifica":"Canela dulce"}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria":"Chocolatado","subcategoria":"Chocolate negro","notaEspecifica":null},
|
||||
{"categoria":"Nueces","subcategoria":"Almendra","notaEspecifica":"Tostada"}
|
||||
]'::jsonb
|
||||
);
|
||||
|
||||
-- Verificar que se guardaron correctamente
|
||||
SELECT jsonb_array_length(fragancia_aroma_notas)
|
||||
INTO notas_count
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF notas_count = 3 THEN
|
||||
RAISE NOTICE ' ✓ Acepta múltiples notas de fragancia (3)';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Cantidad incorrecta de notas: % (esperado: 3)', notas_count;
|
||||
END IF;
|
||||
|
||||
SELECT jsonb_array_length(sabor_notas)
|
||||
INTO notas_count
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF notas_count = 2 THEN
|
||||
RAISE NOTICE ' ✓ Acepta múltiples notas de sabor (2)';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Cantidad incorrecta de notas: % (esperado: 2)', notas_count;
|
||||
END IF;
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó múltiples notas: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Arrays JSONB con múltiples elementos funcionan correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Evaluación mínima válida (solo intensidades requeridas)
|
||||
-- ============================================
|
||||
\echo '[EDGE 6] Validando evaluación mínima válida...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
eval_id uuid;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge6@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-6', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M6');
|
||||
|
||||
-- Test: solo intensidades (campo obligatorio), todo lo demás default/NULL
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":1}}'::jsonb
|
||||
) RETURNING id INTO eval_id;
|
||||
|
||||
-- Verificar que los defaults se aplicaron
|
||||
PERFORM 1
|
||||
FROM evaluacion
|
||||
WHERE id = eval_id
|
||||
AND fragancia_aroma_notas = '[]'::jsonb
|
||||
AND sabor_notas = '[]'::jsonb
|
||||
AND tazas_no_uniformes = ARRAY[]::smallint[]
|
||||
AND tazas_defectuosas = ARRAY[]::smallint[]
|
||||
AND sensacion_en_boca = ARRAY[]::text[]
|
||||
AND gustos_predominantes = ARRAY[]::text[]
|
||||
AND defecto IS NULL
|
||||
AND otras_notas IS NULL;
|
||||
|
||||
IF FOUND THEN
|
||||
RAISE NOTICE ' ✓ Evaluación mínima válida con defaults correctos';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Defaults no se aplicaron correctamente';
|
||||
END IF;
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Rechazó evaluación mínima: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Evaluación mínima válida funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Texto largo en otras_notas
|
||||
-- ============================================
|
||||
\echo '[EDGE 7] Validando texto largo en otras_notas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
long_text text;
|
||||
stored_text text;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_edge7@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-EDGE-7', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M7');
|
||||
|
||||
-- Generar texto de 1000 caracteres
|
||||
long_text := repeat('Este es un texto largo con muchos detalles sobre la catación. ', 20);
|
||||
|
||||
-- Test: insertar texto largo
|
||||
BEGIN
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades, otras_notas
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
long_text
|
||||
);
|
||||
|
||||
SELECT otras_notas INTO stored_text
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF stored_text = long_text THEN
|
||||
RAISE NOTICE ' ✓ Acepta y almacena texto largo (% caracteres)', length(stored_text);
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Texto almacenado no coincide';
|
||||
END IF;
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE EXCEPTION ' ✗ Falló con texto largo: %', SQLERRM;
|
||||
END;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Texto largo funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Casos Límite completados'
|
||||
\echo '=========================================='
|
||||
256
postgres/tests/test_functions.sql
Normal file
256
postgres/tests/test_functions.sql
Normal file
@@ -0,0 +1,256 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Funciones Auxiliares
|
||||
-- ============================================
|
||||
-- Tests que verifican las funciones auxiliares
|
||||
-- con datos generados dinámicamente
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Funciones Auxiliares'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Función get_promedio_parametro_afectivo
|
||||
-- ============================================
|
||||
\echo '[FUNCTION 1] Probando función: get_promedio_parametro_afectivo...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user1_id uuid := gen_random_uuid();
|
||||
test_user2_id uuid := gen_random_uuid();
|
||||
test_user3_id uuid := gen_random_uuid();
|
||||
test_part1_id uuid := gen_random_uuid();
|
||||
test_part2_id uuid := gen_random_uuid();
|
||||
test_part3_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
avg_acidez numeric;
|
||||
avg_dulzor numeric;
|
||||
avg_sabor numeric;
|
||||
expected_acidez numeric := 7.0; -- (6 + 8 + 7) / 3
|
||||
expected_dulzor numeric := 5.0; -- (3 + 7 + 5) / 3
|
||||
expected_sabor numeric := 8.0; -- (8 + 8 + 8) / 3
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre) VALUES
|
||||
(test_user1_id, 'test_func1_u1@test.com', 'User 1'),
|
||||
(test_user2_id, 'test_func1_u2@test.com', 'User 2'),
|
||||
(test_user3_id, 'test_func1_u3@test.com', 'User 3');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-FUNC-1', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id) VALUES
|
||||
(test_part1_id, test_sesion_id, test_user1_id),
|
||||
(test_part2_id, test_sesion_id, test_user2_id),
|
||||
(test_part3_id, test_sesion_id, test_user3_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M1');
|
||||
|
||||
-- Crear 3 evaluaciones con diferentes valores
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades) VALUES
|
||||
(test_muestra_id, test_part1_id,
|
||||
'{"acidez":{"descriptiva":5,"afectiva":6},"dulzor":{"descriptiva":5,"afectiva":3},"sabor":{"descriptiva":8,"afectiva":8}}'::jsonb),
|
||||
(test_muestra_id, test_part2_id,
|
||||
'{"acidez":{"descriptiva":10,"afectiva":8},"dulzor":{"descriptiva":10,"afectiva":7},"sabor":{"descriptiva":8,"afectiva":8}}'::jsonb),
|
||||
(test_muestra_id, test_part3_id,
|
||||
'{"acidez":{"descriptiva":7,"afectiva":7},"dulzor":{"descriptiva":6,"afectiva":5},"sabor":{"descriptiva":8,"afectiva":8}}'::jsonb);
|
||||
|
||||
-- Test función para acidez
|
||||
SELECT get_promedio_parametro_afectivo(test_sesion_id, 'acidez')
|
||||
INTO avg_acidez;
|
||||
|
||||
IF avg_acidez = expected_acidez THEN
|
||||
RAISE NOTICE ' ✓ Promedio acidez correcto: % (esperado: %)',
|
||||
avg_acidez, expected_acidez;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Promedio acidez incorrecto: % (esperado: %)',
|
||||
avg_acidez, expected_acidez;
|
||||
END IF;
|
||||
|
||||
-- Test función para dulzor
|
||||
SELECT get_promedio_parametro_afectivo(test_sesion_id, 'dulzor')
|
||||
INTO avg_dulzor;
|
||||
|
||||
IF avg_dulzor = expected_dulzor THEN
|
||||
RAISE NOTICE ' ✓ Promedio dulzor correcto: % (esperado: %)',
|
||||
avg_dulzor, expected_dulzor;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Promedio dulzor incorrecto: % (esperado: %)',
|
||||
avg_dulzor, expected_dulzor;
|
||||
END IF;
|
||||
|
||||
-- Test función para sabor
|
||||
SELECT get_promedio_parametro_afectivo(test_sesion_id, 'sabor')
|
||||
INTO avg_sabor;
|
||||
|
||||
IF avg_sabor = expected_sabor THEN
|
||||
RAISE NOTICE ' ✓ Promedio sabor correcto: % (esperado: %)',
|
||||
avg_sabor, expected_sabor;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Promedio sabor incorrecto: % (esperado: %)',
|
||||
avg_sabor, expected_sabor;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id IN (test_user1_id, test_user2_id, test_user3_id);
|
||||
|
||||
RAISE NOTICE '✓ Función get_promedio_parametro_afectivo funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Función get_top_muestras
|
||||
-- ============================================
|
||||
\echo '[FUNCTION 2] Probando función: get_top_muestras...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra1_id uuid := gen_random_uuid();
|
||||
test_muestra2_id uuid := gen_random_uuid();
|
||||
test_muestra3_id uuid := gen_random_uuid();
|
||||
test_muestra4_id uuid := gen_random_uuid();
|
||||
result record;
|
||||
result_count int := 0;
|
||||
first_muestra text;
|
||||
first_puntaje int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_func2@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-FUNC-2', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
-- Crear 4 muestras con puntajes 25, 50, 75, 100 (ordenadas al revés)
|
||||
INSERT INTO muestra (id, sesion_id, codigo) VALUES
|
||||
(test_muestra1_id, test_sesion_id, 'PUNTAJE-25'),
|
||||
(test_muestra2_id, test_sesion_id, 'PUNTAJE-50'),
|
||||
(test_muestra3_id, test_sesion_id, 'PUNTAJE-75'),
|
||||
(test_muestra4_id, test_sesion_id, 'PUNTAJE-100');
|
||||
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades) VALUES
|
||||
(test_muestra1_id, test_part_id,
|
||||
'{"fragancia":{"afectiva":3},"aroma":{"afectiva":3},"sabor":{"afectiva":3},"saborResidual":{"afectiva":3},"acidez":{"afectiva":3},"dulzor":{"afectiva":4},"sensacionBoca":{"afectiva":3},"impresionGlobal":{"afectiva":3}}'::jsonb),
|
||||
(test_muestra2_id, test_part_id,
|
||||
'{"fragancia":{"afectiva":6},"aroma":{"afectiva":6},"sabor":{"afectiva":6},"saborResidual":{"afectiva":6},"acidez":{"afectiva":7},"dulzor":{"afectiva":7},"sensacionBoca":{"afectiva":6},"impresionGlobal":{"afectiva":6}}'::jsonb),
|
||||
(test_muestra3_id, test_part_id,
|
||||
'{"fragancia":{"afectiva":9},"aroma":{"afectiva":9},"sabor":{"afectiva":9},"saborResidual":{"afectiva":10},"acidez":{"afectiva":10},"dulzor":{"afectiva":10},"sensacionBoca":{"afectiva":9},"impresionGlobal":{"afectiva":9}}'::jsonb),
|
||||
(test_muestra4_id, test_part_id,
|
||||
'{"fragancia":{"afectiva":10},"aroma":{"afectiva":10},"sabor":{"afectiva":10},"saborResidual":{"afectiva":10},"acidez":{"afectiva":10},"dulzor":{"afectiva":10},"sensacionBoca":{"afectiva":10},"impresionGlobal":{"afectiva":10}}'::jsonb);
|
||||
|
||||
-- Test: obtener top 3
|
||||
FOR result IN
|
||||
SELECT * FROM get_top_muestras(test_sesion_id, 3)
|
||||
LOOP
|
||||
result_count := result_count + 1;
|
||||
IF result_count = 1 THEN
|
||||
first_muestra := result.muestra_codigo;
|
||||
first_puntaje := result.puntaje_final;
|
||||
END IF;
|
||||
RAISE NOTICE ' - Posición %: % (% puntos)',
|
||||
result_count, result.muestra_codigo, result.puntaje_final;
|
||||
END LOOP;
|
||||
|
||||
-- Validar que devolvió 3 resultados
|
||||
IF result_count != 3 THEN
|
||||
RAISE EXCEPTION ' ✗ Devolvió % resultados (esperado: 3)', result_count;
|
||||
END IF;
|
||||
|
||||
-- Validar que el primero es PUNTAJE-100 con 80 puntos
|
||||
IF first_muestra != 'PUNTAJE-100' THEN
|
||||
RAISE EXCEPTION ' ✗ Primera muestra incorrecta: % (esperado: PUNTAJE-100)',
|
||||
first_muestra;
|
||||
END IF;
|
||||
|
||||
IF first_puntaje != 80 THEN
|
||||
RAISE EXCEPTION ' ✗ Primer puntaje incorrecto: % (esperado: 80)',
|
||||
first_puntaje;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE ' ✓ Función devuelve top 3 correctamente';
|
||||
|
||||
-- Test: obtener top 10 (debería devolver solo 4)
|
||||
result_count := 0;
|
||||
FOR result IN
|
||||
SELECT * FROM get_top_muestras(test_sesion_id, 10)
|
||||
LOOP
|
||||
result_count := result_count + 1;
|
||||
END LOOP;
|
||||
|
||||
IF result_count = 4 THEN
|
||||
RAISE NOTICE ' ✓ Función limita correctamente cuando hay menos resultados que el límite';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Con limit=10 devolvió % resultados (esperado: 4)',
|
||||
result_count;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Función get_top_muestras funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Funciones con sesión vacía
|
||||
-- ============================================
|
||||
\echo '[FUNCTION 3] Probando funciones con sesión sin evaluaciones...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
avg_result numeric;
|
||||
top_count int := 0;
|
||||
result record;
|
||||
BEGIN
|
||||
-- Crear sesión vacía
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-FUNC-EMPTY', CURRENT_DATE);
|
||||
|
||||
-- Test get_promedio_parametro_afectivo con sesión vacía
|
||||
SELECT get_promedio_parametro_afectivo(test_sesion_id, 'acidez')
|
||||
INTO avg_result;
|
||||
|
||||
IF avg_result IS NULL THEN
|
||||
RAISE NOTICE ' ✓ get_promedio_parametro_afectivo devuelve NULL con sesión vacía';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Devolvió % en lugar de NULL', avg_result;
|
||||
END IF;
|
||||
|
||||
-- Test get_top_muestras con sesión vacía
|
||||
FOR result IN
|
||||
SELECT * FROM get_top_muestras(test_sesion_id, 3)
|
||||
LOOP
|
||||
top_count := top_count + 1;
|
||||
END LOOP;
|
||||
|
||||
IF top_count = 0 THEN
|
||||
RAISE NOTICE ' ✓ get_top_muestras devuelve conjunto vacío con sesión vacía';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Devolvió % resultados en lugar de 0', top_count;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
|
||||
RAISE NOTICE '✓ Funciones manejan correctamente sesiones vacías';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Funciones completados'
|
||||
\echo '=========================================='
|
||||
279
postgres/tests/test_indexes.sql
Normal file
279
postgres/tests/test_indexes.sql
Normal file
@@ -0,0 +1,279 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Índices
|
||||
-- ============================================
|
||||
-- Tests que verifican que los índices se están
|
||||
-- usando correctamente con EXPLAIN
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Uso de Índices'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Índice GIN en tazas_defectuosas con operador @>
|
||||
-- ============================================
|
||||
\echo '[INDEX 1] Verificando uso de índice GIN en tazas_defectuosas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
explain_output text;
|
||||
uses_index boolean := false;
|
||||
BEGIN
|
||||
-- Obtener plan de ejecución
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
WHERE tazas_defectuosas @> ARRAY[5]::smallint[]
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
-- Verificar que usa índice GIN
|
||||
IF explain_output LIKE '%idx_eval_tazas_defectuosas%' OR
|
||||
explain_output LIKE '%Bitmap Index Scan%' THEN
|
||||
uses_index := true;
|
||||
END IF;
|
||||
|
||||
IF uses_index THEN
|
||||
RAISE NOTICE ' ✓ Query usa índice GIN para tazas_defectuosas con @>';
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Query NO usa índice GIN (puede ser normal con tabla vacía)';
|
||||
RAISE NOTICE 'Plan: %', explain_output;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de índice GIN en tazas_defectuosas completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Índice funcional en acidez afectiva
|
||||
-- ============================================
|
||||
\echo '[INDEX 2] Verificando uso de índice funcional en acidez afectiva...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
explain_output text;
|
||||
uses_index boolean := false;
|
||||
BEGIN
|
||||
-- Obtener plan de ejecución
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
-- Verificar que usa índice funcional
|
||||
IF explain_output LIKE '%idx_eval_int_acidez_afectiva%' OR
|
||||
explain_output LIKE '%Index%' THEN
|
||||
uses_index := true;
|
||||
END IF;
|
||||
|
||||
IF uses_index THEN
|
||||
RAISE NOTICE ' ✓ Query usa índice funcional para acidez afectiva';
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Query NO usa índice funcional (puede ser normal con tabla vacía)';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de índice funcional en acidez completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Índice B-tree en puntaje_final
|
||||
-- ============================================
|
||||
\echo '[INDEX 3] Verificando uso de índice B-tree en puntaje_final...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
explain_output text;
|
||||
uses_index boolean := false;
|
||||
BEGIN
|
||||
-- Obtener plan de ejecución para ORDER BY
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
ORDER BY puntaje_final DESC
|
||||
LIMIT 10
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
-- Verificar que usa índice
|
||||
IF explain_output LIKE '%idx_eval_puntaje_final%' OR
|
||||
explain_output LIKE '%Index%puntaje%' THEN
|
||||
uses_index := true;
|
||||
END IF;
|
||||
|
||||
IF uses_index THEN
|
||||
RAISE NOTICE ' ✓ Query usa índice B-tree para puntaje_final';
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Query NO usa índice B-tree (puede ser normal con tabla vacía)';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de índice B-tree en puntaje_final completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Índice GIN en intensidades JSONB
|
||||
-- ============================================
|
||||
\echo '[INDEX 4] Verificando uso de índice GIN en intensidades JSONB...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
explain_output text;
|
||||
uses_index boolean := false;
|
||||
BEGIN
|
||||
-- Obtener plan de ejecución
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
WHERE intensidades @> '{"dulzor":{"afectiva":10}}'::jsonb
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
-- Verificar que usa índice GIN
|
||||
IF explain_output LIKE '%idx_eval_json_intensidades%' OR
|
||||
explain_output LIKE '%Bitmap Index Scan%intensidades%' THEN
|
||||
uses_index := true;
|
||||
END IF;
|
||||
|
||||
IF uses_index THEN
|
||||
RAISE NOTICE ' ✓ Query usa índice GIN para búsqueda en JSONB';
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Query NO usa índice GIN JSONB (puede ser normal con tabla vacía)';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de índice GIN en JSONB completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Índices con datos reales
|
||||
-- ============================================
|
||||
\echo '[INDEX 5] Verificando uso de índices con datos reales...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid;
|
||||
explain_output text;
|
||||
i int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba (100 evaluaciones)
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_index@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-INDEX', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
-- Insertar 100 muestras y evaluaciones
|
||||
FOR i IN 1..100 LOOP
|
||||
test_muestra_id := gen_random_uuid();
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'M-' || i);
|
||||
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades,
|
||||
tazas_defectuosas, puntaje_final
|
||||
) VALUES (
|
||||
test_muestra_id, test_part_id,
|
||||
jsonb_build_object(
|
||||
'acidez', jsonb_build_object('descriptiva', (i % 15) + 1, 'afectiva', (i % 10) + 1),
|
||||
'dulzor', jsonb_build_object('descriptiva', ((i * 2) % 15) + 1, 'afectiva', ((i * 2) % 10) + 1)
|
||||
),
|
||||
CASE WHEN i % 10 = 0 THEN ARRAY[5]::smallint[] ELSE ARRAY[]::smallint[] END,
|
||||
(i % 80) + 1
|
||||
);
|
||||
END LOOP;
|
||||
|
||||
RAISE NOTICE ' ✓ Creadas 100 evaluaciones para testing de índices';
|
||||
|
||||
-- Test 1: Índice en puntaje_final con datos
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
WHERE puntaje_final > 50
|
||||
ORDER BY puntaje_final DESC
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
IF explain_output LIKE '%Index%' THEN
|
||||
RAISE NOTICE ' ✓ Índice usado en puntaje_final con 100 registros';
|
||||
ELSE
|
||||
RAISE NOTICE ' - Plan para puntaje_final: Seq Scan (normal con 100 registros)';
|
||||
END IF;
|
||||
|
||||
-- Test 2: Índice GIN en arrays con datos
|
||||
SELECT string_agg(line, E'\n')
|
||||
INTO explain_output
|
||||
FROM (
|
||||
SELECT * FROM (
|
||||
EXPLAIN SELECT * FROM evaluacion
|
||||
WHERE tazas_defectuosas @> ARRAY[5]::smallint[]
|
||||
) AS explain_lines(line)
|
||||
) AS subq;
|
||||
|
||||
IF explain_output LIKE '%Index%' OR explain_output LIKE '%Bitmap%' THEN
|
||||
RAISE NOTICE ' ✓ Índice GIN usado en tazas_defectuosas con 100 registros';
|
||||
ELSE
|
||||
RAISE NOTICE ' - Plan para tazas_defectuosas: Seq Scan (normal con 100 registros)';
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Verificación con datos reales completada';
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE 'NOTA: Con pocos registros PostgreSQL puede preferir Seq Scan sobre índices.';
|
||||
RAISE NOTICE ' Los índices se usan más efectivamente con miles de registros.';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Listado de todos los índices
|
||||
-- ============================================
|
||||
\echo '[INDEX 6] Listando todos los índices de rioCata...'
|
||||
|
||||
SELECT
|
||||
schemaname AS schema,
|
||||
tablename AS tabla,
|
||||
indexname AS indice,
|
||||
indexdef AS definicion
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'public'
|
||||
AND tablename IN ('sesion', 'sesion_participante', 'muestra', 'evaluacion')
|
||||
ORDER BY tablename, indexname;
|
||||
|
||||
\echo ''
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Índices completados'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
\echo 'NOTA IMPORTANTE:'
|
||||
\echo 'Los índices GIN y funcionales se aprovechan mejor con grandes'
|
||||
\echo 'volúmenes de datos (miles de registros). Con datos de prueba'
|
||||
\echo 'pequeños, PostgreSQL puede optar por Seq Scan que es más eficiente.'
|
||||
\echo ''
|
||||
364
postgres/tests/test_queries.sql
Normal file
364
postgres/tests/test_queries.sql
Normal file
@@ -0,0 +1,364 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Queries Típicas
|
||||
-- ============================================
|
||||
-- Tests que verifican queries comunes con datos
|
||||
-- generados dinámicamente y validaciones específicas
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Queries Típicas'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Query promedio de parámetro afectivo
|
||||
-- ============================================
|
||||
\echo '[QUERY 1] Probando query: Promedio de parámetro afectivo...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user1_id uuid := gen_random_uuid();
|
||||
test_user2_id uuid := gen_random_uuid();
|
||||
test_part1_id uuid := gen_random_uuid();
|
||||
test_part2_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
avg_dulzor numeric;
|
||||
expected_avg numeric := 7.5; -- (5 + 10) / 2
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre) VALUES
|
||||
(test_user1_id, 'test_query1_u1@test.com', 'User 1'),
|
||||
(test_user2_id, 'test_query1_u2@test.com', 'User 2');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-QUERY-1', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id) VALUES
|
||||
(test_part1_id, test_sesion_id, test_user1_id),
|
||||
(test_part2_id, test_sesion_id, test_user2_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M1');
|
||||
|
||||
-- Crear 2 evaluaciones con dulzor 5 y 10
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades) VALUES
|
||||
(test_muestra_id, test_part1_id,
|
||||
'{"dulzor":{"descriptiva":5,"afectiva":5}}'::jsonb),
|
||||
(test_muestra_id, test_part2_id,
|
||||
'{"dulzor":{"descriptiva":10,"afectiva":10}}'::jsonb);
|
||||
|
||||
-- Ejecutar query
|
||||
SELECT AVG(((e.intensidades->'dulzor'->>'afectiva')::int))
|
||||
INTO avg_dulzor
|
||||
FROM sesion s
|
||||
JOIN muestra m ON m.sesion_id = s.id
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
WHERE s.id = test_sesion_id;
|
||||
|
||||
-- Validar resultado
|
||||
IF avg_dulzor = expected_avg THEN
|
||||
RAISE NOTICE ' ✓ Promedio calculado correctamente: % (esperado: %)',
|
||||
avg_dulzor, expected_avg;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Promedio incorrecto: % (esperado: %)',
|
||||
avg_dulzor, expected_avg;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id IN (test_user1_id, test_user2_id);
|
||||
|
||||
RAISE NOTICE '✓ Query promedio de parámetro afectivo funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Query buscar por defecto específico
|
||||
-- ============================================
|
||||
\echo '[QUERY 2] Probando query: Buscar evaluaciones con defecto específico...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra1_id uuid := gen_random_uuid();
|
||||
test_muestra2_id uuid := gen_random_uuid();
|
||||
count_fenolico int;
|
||||
count_mohoso int;
|
||||
expected_fenolico int := 2;
|
||||
expected_mohoso int := 1;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_query2@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-QUERY-2', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo) VALUES
|
||||
(test_muestra1_id, test_sesion_id, 'TEST-M1'),
|
||||
(test_muestra2_id, test_sesion_id, 'TEST-M2');
|
||||
|
||||
-- Crear 2 evaluaciones con defecto Fenólico y 1 con Mohoso
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades, defecto)
|
||||
SELECT test_muestra1_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
'Fenólico'::defecto_tipo
|
||||
UNION ALL
|
||||
SELECT test_muestra2_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
'Fenólico'::defecto_tipo;
|
||||
|
||||
-- Insertar una con Mohoso en nueva muestra
|
||||
DELETE FROM muestra WHERE id = test_muestra1_id;
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra1_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades, defecto)
|
||||
VALUES (test_muestra1_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
'Mohoso'::defecto_tipo);
|
||||
|
||||
-- Query para Fenólico
|
||||
SELECT COUNT(*) INTO count_fenolico
|
||||
FROM evaluacion
|
||||
WHERE defecto = 'Fenólico';
|
||||
|
||||
-- Query para Mohoso
|
||||
SELECT COUNT(*) INTO count_mohoso
|
||||
FROM evaluacion
|
||||
WHERE defecto = 'Mohoso';
|
||||
|
||||
-- Validar
|
||||
IF count_fenolico = expected_fenolico AND count_mohoso = expected_mohoso THEN
|
||||
RAISE NOTICE ' ✓ Búsqueda por defecto correcta: Fenólico=%, Mohoso=%',
|
||||
count_fenolico, count_mohoso;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Búsqueda incorrecta: Fenólico=% (esp: %), Mohoso=% (esp: %)',
|
||||
count_fenolico, expected_fenolico, count_mohoso, expected_mohoso;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Query buscar por defecto funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Query buscar taza defectuosa con operador @>
|
||||
-- ============================================
|
||||
\echo '[QUERY 3] Probando query: Buscar taza defectuosa específica (índice GIN)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra1_id uuid := gen_random_uuid();
|
||||
test_muestra2_id uuid := gen_random_uuid();
|
||||
test_muestra3_id uuid := gen_random_uuid();
|
||||
count_taza5 int;
|
||||
count_taza3 int;
|
||||
expected_taza5 int := 2;
|
||||
expected_taza3 int := 1;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_query3@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-QUERY-3', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo) VALUES
|
||||
(test_muestra1_id, test_sesion_id, 'TEST-M1'),
|
||||
(test_muestra2_id, test_sesion_id, 'TEST-M2'),
|
||||
(test_muestra3_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
-- Crear evaluaciones con tazas defectuosas
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades, tazas_defectuosas) VALUES
|
||||
(test_muestra1_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[5]::smallint[]),
|
||||
(test_muestra2_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[3, 5]::smallint[]),
|
||||
(test_muestra3_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb,
|
||||
ARRAY[1, 2]::smallint[]);
|
||||
|
||||
-- Query usando operador @> (debe usar índice GIN)
|
||||
SELECT COUNT(*) INTO count_taza5
|
||||
FROM evaluacion
|
||||
WHERE tazas_defectuosas @> ARRAY[5]::smallint[];
|
||||
|
||||
SELECT COUNT(*) INTO count_taza3
|
||||
FROM evaluacion
|
||||
WHERE tazas_defectuosas @> ARRAY[3]::smallint[];
|
||||
|
||||
-- Validar
|
||||
IF count_taza5 = expected_taza5 AND count_taza3 = expected_taza3 THEN
|
||||
RAISE NOTICE ' ✓ Operador @> funciona correctamente: taza5=%, taza3=%',
|
||||
count_taza5, count_taza3;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Operador @> incorrecto: taza5=% (esp: %), taza3=% (esp: %)',
|
||||
count_taza5, expected_taza5, count_taza3, expected_taza3;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Query con operador @> funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Query top muestras por puntaje
|
||||
-- ============================================
|
||||
\echo '[QUERY 4] Probando query: Top muestras por puntaje final...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra1_id uuid := gen_random_uuid();
|
||||
test_muestra2_id uuid := gen_random_uuid();
|
||||
test_muestra3_id uuid := gen_random_uuid();
|
||||
top_muestra text;
|
||||
top_puntaje int;
|
||||
expected_muestra text := 'HIGH';
|
||||
expected_puntaje int := 80;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_query4@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-QUERY-4', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
-- Crear 3 muestras con diferentes puntajes
|
||||
INSERT INTO muestra (id, sesion_id, codigo) VALUES
|
||||
(test_muestra1_id, test_sesion_id, 'LOW'),
|
||||
(test_muestra2_id, test_sesion_id, 'MID'),
|
||||
(test_muestra3_id, test_sesion_id, 'HIGH');
|
||||
|
||||
-- Evaluaciones con puntajes 20, 50, 80
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades) VALUES
|
||||
(test_muestra1_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":1,"afectiva":2},"aroma":{"descriptiva":1,"afectiva":3},"sabor":{"descriptiva":1,"afectiva":2},"saborResidual":{"descriptiva":1,"afectiva":3},"acidez":{"descriptiva":1,"afectiva":3},"dulzor":{"descriptiva":1,"afectiva":2},"sensacionBoca":{"descriptiva":1,"afectiva":3},"impresionGlobal":{"afectiva":2}}'::jsonb),
|
||||
(test_muestra2_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":6},"aroma":{"descriptiva":5,"afectiva":6},"sabor":{"descriptiva":5,"afectiva":7},"saborResidual":{"descriptiva":5,"afectiva":6},"acidez":{"descriptiva":5,"afectiva":6},"dulzor":{"descriptiva":5,"afectiva":7},"sensacionBoca":{"descriptiva":5,"afectiva":6},"impresionGlobal":{"afectiva":6}}'::jsonb),
|
||||
(test_muestra3_id, test_part_id,
|
||||
'{"fragancia":{"descriptiva":10,"afectiva":10},"aroma":{"descriptiva":10,"afectiva":10},"sabor":{"descriptiva":10,"afectiva":10},"saborResidual":{"descriptiva":10,"afectiva":10},"acidez":{"descriptiva":10,"afectiva":10},"dulzor":{"descriptiva":10,"afectiva":10},"sensacionBoca":{"descriptiva":10,"afectiva":10},"impresionGlobal":{"afectiva":10}}'::jsonb);
|
||||
|
||||
-- Query top 1
|
||||
SELECT m.codigo, e.puntaje_final
|
||||
INTO top_muestra, top_puntaje
|
||||
FROM muestra m
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
JOIN sesion_participante sp ON sp.id = e.sesion_participante_id
|
||||
WHERE m.sesion_id = test_sesion_id
|
||||
ORDER BY e.puntaje_final DESC
|
||||
LIMIT 1;
|
||||
|
||||
-- Validar
|
||||
IF top_muestra = expected_muestra AND top_puntaje = expected_puntaje THEN
|
||||
RAISE NOTICE ' ✓ Top muestra correcta: % con puntaje %',
|
||||
top_muestra, top_puntaje;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Top muestra incorrecta: % (esp: %), puntaje: % (esp: %)',
|
||||
top_muestra, expected_muestra, top_puntaje, expected_puntaje;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Query top muestras funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Query filtrar por acidez alta (índice funcional)
|
||||
-- ============================================
|
||||
\echo '[QUERY 5] Probando query: Filtrar por acidez afectiva >= 8...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_part_id uuid := gen_random_uuid();
|
||||
test_muestra1_id uuid := gen_random_uuid();
|
||||
test_muestra2_id uuid := gen_random_uuid();
|
||||
test_muestra3_id uuid := gen_random_uuid();
|
||||
count_high_acidez int;
|
||||
expected_count int := 2;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_query5@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-QUERY-5', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_part_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo) VALUES
|
||||
(test_muestra1_id, test_sesion_id, 'TEST-M1'),
|
||||
(test_muestra2_id, test_sesion_id, 'TEST-M2'),
|
||||
(test_muestra3_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
-- Crear evaluaciones con acidez 5, 8, 10
|
||||
INSERT INTO evaluacion (muestra_id, sesion_participante_id, intensidades) VALUES
|
||||
(test_muestra1_id, test_part_id,
|
||||
'{"acidez":{"descriptiva":5,"afectiva":5}}'::jsonb),
|
||||
(test_muestra2_id, test_part_id,
|
||||
'{"acidez":{"descriptiva":8,"afectiva":8}}'::jsonb),
|
||||
(test_muestra3_id, test_part_id,
|
||||
'{"acidez":{"descriptiva":10,"afectiva":10}}'::jsonb);
|
||||
|
||||
-- Query con índice funcional
|
||||
SELECT COUNT(*) INTO count_high_acidez
|
||||
FROM evaluacion
|
||||
WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8;
|
||||
|
||||
-- Validar
|
||||
IF count_high_acidez = expected_count THEN
|
||||
RAISE NOTICE ' ✓ Filtro por acidez >= 8 correcto: % evaluaciones',
|
||||
count_high_acidez;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Filtro incorrecto: % (esperado: %)',
|
||||
count_high_acidez, expected_count;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Query con filtro por parámetro JSONB funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Queries completados'
|
||||
\echo '=========================================='
|
||||
278
postgres/tests/test_structure.sql
Normal file
278
postgres/tests/test_structure.sql
Normal file
@@ -0,0 +1,278 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Estructura de BD
|
||||
-- ============================================
|
||||
-- Tests que verifican la existencia y correcta
|
||||
-- configuración de la estructura de la base de datos
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Estructura de Base de Datos'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar existencia de tablas
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 1] Verificando existencia de tablas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
tabla_count int;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO tabla_count
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name IN ('sesion', 'sesion_participante', 'muestra', 'evaluacion');
|
||||
|
||||
IF tabla_count = 4 THEN
|
||||
RAISE NOTICE ' ✓ Todas las tablas principales existen (4/4)';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Faltan tablas. Encontradas: %/4', tabla_count;
|
||||
END IF;
|
||||
|
||||
-- Verificar tabla auth.users
|
||||
SELECT COUNT(*) INTO tabla_count
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'auth' AND table_name = 'users';
|
||||
|
||||
IF tabla_count = 1 THEN
|
||||
RAISE NOTICE ' ✓ Tabla auth.users existe';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Tabla auth.users no existe';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Todas las tablas existen correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar tipo ENUM defecto_tipo
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 2] Verificando tipo ENUM defecto_tipo...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
enum_exists boolean;
|
||||
enum_values text[];
|
||||
expected_values text[] := ARRAY['Mohoso', 'Fenólico', 'Papa'];
|
||||
BEGIN
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM pg_type WHERE typname = 'defecto_tipo'
|
||||
) INTO enum_exists;
|
||||
|
||||
IF NOT enum_exists THEN
|
||||
RAISE EXCEPTION ' ✗ Tipo ENUM defecto_tipo no existe';
|
||||
END IF;
|
||||
|
||||
-- Verificar valores del ENUM
|
||||
SELECT array_agg(enumlabel ORDER BY enumsortorder)
|
||||
INTO enum_values
|
||||
FROM pg_enum
|
||||
WHERE enumtypid = 'defecto_tipo'::regtype;
|
||||
|
||||
IF enum_values = expected_values THEN
|
||||
RAISE NOTICE ' ✓ Tipo ENUM defecto_tipo existe con valores correctos: %',
|
||||
array_to_string(enum_values, ', ');
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Valores ENUM incorrectos. Encontrados: %, Esperados: %',
|
||||
enum_values, expected_values;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Tipo ENUM defecto_tipo correcto';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar triggers
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 3] Verificando triggers...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
trigger_count int;
|
||||
trigger_names text[];
|
||||
BEGIN
|
||||
SELECT COUNT(*), array_agg(trigger_name ORDER BY trigger_name)
|
||||
INTO trigger_count, trigger_names
|
||||
FROM information_schema.triggers
|
||||
WHERE event_object_table = 'evaluacion'
|
||||
AND trigger_name IN ('trg_eval_updated_at', 'trg_eval_score_bi');
|
||||
|
||||
IF trigger_count >= 2 THEN
|
||||
RAISE NOTICE ' ✓ Triggers principales existen (% encontrados): %',
|
||||
trigger_count, array_to_string(trigger_names, ', ');
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Faltan triggers. Encontrados: %', trigger_count;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Todos los triggers existen';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar índices
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 4] Verificando índices...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
index_count int;
|
||||
expected_min int := 15;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO index_count
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'public'
|
||||
AND indexname LIKE 'idx_%';
|
||||
|
||||
IF index_count >= expected_min THEN
|
||||
RAISE NOTICE ' ✓ Índices creados correctamente (% encontrados, esperado: >= %)',
|
||||
index_count, expected_min;
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Se esperaban al menos % índices, se encontraron: %',
|
||||
expected_min, index_count;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de índices completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar funciones auxiliares
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 5] Verificando funciones auxiliares...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
func_count int;
|
||||
func_names text[];
|
||||
BEGIN
|
||||
SELECT COUNT(*), array_agg(proname ORDER BY proname)
|
||||
INTO func_count, func_names
|
||||
FROM pg_proc
|
||||
WHERE proname IN ('get_promedio_parametro_afectivo', 'get_top_muestras')
|
||||
AND pronamespace = 'public'::regnamespace;
|
||||
|
||||
IF func_count = 2 THEN
|
||||
RAISE NOTICE ' ✓ Todas las funciones auxiliares existen (2/2): %',
|
||||
array_to_string(func_names, ', ');
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Faltan funciones. Encontradas: %/2', func_count;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Funciones auxiliares existen';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar claves foráneas
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 6] Verificando claves foráneas...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
fk_count int;
|
||||
expected_fks int := 5;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO fk_count
|
||||
FROM information_schema.table_constraints
|
||||
WHERE constraint_schema = 'public'
|
||||
AND constraint_type = 'FOREIGN KEY';
|
||||
|
||||
IF fk_count >= expected_fks THEN
|
||||
RAISE NOTICE ' ✓ Claves foráneas configuradas (% encontradas)', fk_count;
|
||||
ELSE
|
||||
RAISE WARNING ' ⚠ Se esperaban al menos % FK, encontradas: %',
|
||||
expected_fks, fk_count;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Verificación de claves foráneas completada';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar columnas de evaluacion
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 7] Verificando columnas de tabla evaluacion...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
required_columns text[] := ARRAY[
|
||||
'id', 'muestra_id', 'sesion_participante_id',
|
||||
'intensidades', 'fragancia_aroma_notas', 'sabor_notas',
|
||||
'tazas_no_uniformes', 'tazas_defectuosas',
|
||||
'sensacion_en_boca', 'gustos_predominantes',
|
||||
'defecto', 'otras_notas', 'puntaje_final',
|
||||
'created_at', 'updated_at'
|
||||
];
|
||||
found_columns text[];
|
||||
missing_columns text[];
|
||||
BEGIN
|
||||
SELECT array_agg(column_name)
|
||||
INTO found_columns
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'evaluacion'
|
||||
AND column_name = ANY(required_columns);
|
||||
|
||||
-- Buscar columnas faltantes
|
||||
SELECT array_agg(col)
|
||||
INTO missing_columns
|
||||
FROM unnest(required_columns) AS col
|
||||
WHERE col NOT IN (SELECT unnest(found_columns));
|
||||
|
||||
IF missing_columns IS NULL THEN
|
||||
RAISE NOTICE ' ✓ Todas las columnas requeridas existen (15/15)';
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Columnas faltantes: %', array_to_string(missing_columns, ', ');
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✓ Columnas de evaluacion correctas';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Verificar tipos de datos de columnas críticas
|
||||
-- ============================================
|
||||
\echo '[STRUCTURE 8] Verificando tipos de datos...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
wrong_types text;
|
||||
BEGIN
|
||||
SELECT string_agg(
|
||||
column_name || ' (' || data_type || ')',
|
||||
', '
|
||||
)
|
||||
INTO wrong_types
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'evaluacion'
|
||||
AND (
|
||||
(column_name = 'intensidades' AND data_type != 'jsonb') OR
|
||||
(column_name = 'fragancia_aroma_notas' AND data_type != 'jsonb') OR
|
||||
(column_name = 'sabor_notas' AND data_type != 'jsonb') OR
|
||||
(column_name = 'tazas_no_uniformes' AND data_type != 'ARRAY') OR
|
||||
(column_name = 'tazas_defectuosas' AND data_type != 'ARRAY') OR
|
||||
(column_name = 'puntaje_final' AND data_type NOT IN ('integer', 'bigint'))
|
||||
);
|
||||
|
||||
IF wrong_types IS NOT NULL THEN
|
||||
RAISE EXCEPTION ' ✗ Tipos de datos incorrectos: %', wrong_types;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE ' ✓ Tipos de datos correctos para campos críticos';
|
||||
RAISE NOTICE '✓ Tipos de datos verificados';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Estructura completados'
|
||||
\echo '=========================================='
|
||||
302
postgres/tests/test_triggers.sql
Normal file
302
postgres/tests/test_triggers.sql
Normal file
@@ -0,0 +1,302 @@
|
||||
-- ============================================
|
||||
-- rioCata - Tests de Triggers
|
||||
-- ============================================
|
||||
-- Tests que verifican el funcionamiento correcto
|
||||
-- de los triggers automáticos
|
||||
-- ============================================
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Triggers'
|
||||
\echo '=========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Trigger updated_at se actualiza automáticamente
|
||||
-- ============================================
|
||||
\echo '[TRIGGER 1] Validando trigger updated_at...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
test_eval_id uuid;
|
||||
initial_updated_at timestamptz;
|
||||
new_updated_at timestamptz;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_trigger1@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-TRIG-1', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M1');
|
||||
|
||||
-- Crear evaluación
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{"fragancia":{"descriptiva":5,"afectiva":5}}'::jsonb
|
||||
) RETURNING id, updated_at INTO test_eval_id, initial_updated_at;
|
||||
|
||||
RAISE NOTICE ' ✓ Evaluación creada con updated_at: %', initial_updated_at;
|
||||
|
||||
-- Esperar 1 segundo
|
||||
PERFORM pg_sleep(1);
|
||||
|
||||
-- Actualizar la evaluación
|
||||
UPDATE evaluacion
|
||||
SET intensidades = '{"fragancia":{"descriptiva":6,"afectiva":6}}'::jsonb
|
||||
WHERE id = test_eval_id;
|
||||
|
||||
-- Verificar que updated_at cambió
|
||||
SELECT updated_at INTO new_updated_at
|
||||
FROM evaluacion
|
||||
WHERE id = test_eval_id;
|
||||
|
||||
IF new_updated_at > initial_updated_at THEN
|
||||
RAISE NOTICE ' ✓ updated_at se actualizó automáticamente (% -> %)',
|
||||
initial_updated_at, new_updated_at;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ updated_at NO se actualizó (% == %)',
|
||||
initial_updated_at, new_updated_at;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Trigger updated_at funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Trigger puntaje_final se calcula automáticamente
|
||||
-- ============================================
|
||||
\echo '[TRIGGER 2] Validando trigger puntaje_final (cálculo automático)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
calculated_score int;
|
||||
expected_score int;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_trigger2@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-TRIG-2', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M2');
|
||||
|
||||
-- Test 1: Crear evaluación con todos los parámetros
|
||||
-- Suma esperada: 5+6+7+8+9+10+8+7 = 60
|
||||
expected_score := 60;
|
||||
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{
|
||||
"fragancia": {"descriptiva": 5, "afectiva": 5},
|
||||
"aroma": {"descriptiva": 6, "afectiva": 6},
|
||||
"sabor": {"descriptiva": 7, "afectiva": 7},
|
||||
"saborResidual": {"descriptiva": 8, "afectiva": 8},
|
||||
"acidez": {"descriptiva": 9, "afectiva": 9},
|
||||
"dulzor": {"descriptiva": 10, "afectiva": 10},
|
||||
"sensacionBoca": {"descriptiva": 8, "afectiva": 8},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 7}
|
||||
}'::jsonb
|
||||
);
|
||||
|
||||
SELECT puntaje_final INTO calculated_score
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF calculated_score = expected_score THEN
|
||||
RAISE NOTICE ' ✓ Puntaje calculado correctamente: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje incorrecto: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
END IF;
|
||||
|
||||
-- Test 2: Actualizar intensidades y verificar recálculo
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
|
||||
-- Suma esperada: 1+1+1+1+1+1+1+1 = 8
|
||||
expected_score := 8;
|
||||
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{
|
||||
"fragancia": {"descriptiva": 1, "afectiva": 1},
|
||||
"aroma": {"descriptiva": 1, "afectiva": 1},
|
||||
"sabor": {"descriptiva": 1, "afectiva": 1},
|
||||
"saborResidual": {"descriptiva": 1, "afectiva": 1},
|
||||
"acidez": {"descriptiva": 1, "afectiva": 1},
|
||||
"dulzor": {"descriptiva": 1, "afectiva": 1},
|
||||
"sensacionBoca": {"descriptiva": 1, "afectiva": 1},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 1}
|
||||
}'::jsonb
|
||||
);
|
||||
|
||||
SELECT puntaje_final INTO calculated_score
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF calculated_score = expected_score THEN
|
||||
RAISE NOTICE ' ✓ Puntaje mínimo calculado correctamente: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje mínimo incorrecto: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
END IF;
|
||||
|
||||
-- Test 3: Puntaje máximo
|
||||
DELETE FROM evaluacion WHERE muestra_id = test_muestra_id;
|
||||
|
||||
-- Suma esperada: 10+10+10+10+10+10+10+10 = 80
|
||||
expected_score := 80;
|
||||
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{
|
||||
"fragancia": {"descriptiva": 15, "afectiva": 10},
|
||||
"aroma": {"descriptiva": 15, "afectiva": 10},
|
||||
"sabor": {"descriptiva": 15, "afectiva": 10},
|
||||
"saborResidual": {"descriptiva": 15, "afectiva": 10},
|
||||
"acidez": {"descriptiva": 15, "afectiva": 10},
|
||||
"dulzor": {"descriptiva": 15, "afectiva": 10},
|
||||
"sensacionBoca": {"descriptiva": 15, "afectiva": 10},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 10}
|
||||
}'::jsonb
|
||||
);
|
||||
|
||||
SELECT puntaje_final INTO calculated_score
|
||||
FROM evaluacion
|
||||
WHERE muestra_id = test_muestra_id;
|
||||
|
||||
IF calculated_score = expected_score THEN
|
||||
RAISE NOTICE ' ✓ Puntaje máximo calculado correctamente: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje máximo incorrecto: % (esperado: %)',
|
||||
calculated_score, expected_score;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Trigger puntaje_final funciona correctamente';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
-- ============================================
|
||||
-- TEST: Trigger puntaje_final se recalcula en UPDATE
|
||||
-- ============================================
|
||||
\echo '[TRIGGER 3] Validando trigger puntaje_final (recálculo en UPDATE)...'
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
test_sesion_id uuid := gen_random_uuid();
|
||||
test_user_id uuid := gen_random_uuid();
|
||||
test_participante_id uuid := gen_random_uuid();
|
||||
test_muestra_id uuid := gen_random_uuid();
|
||||
test_eval_id uuid;
|
||||
initial_score int;
|
||||
updated_score int;
|
||||
expected_updated_score int := 40;
|
||||
BEGIN
|
||||
-- Crear datos de prueba
|
||||
INSERT INTO auth.users (id, email, nombre)
|
||||
VALUES (test_user_id, 'test_trigger3@test.com', 'Test User');
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha)
|
||||
VALUES (test_sesion_id, 'TEST-TRIG-3', CURRENT_DATE);
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
||||
VALUES (test_participante_id, test_sesion_id, test_user_id);
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo)
|
||||
VALUES (test_muestra_id, test_sesion_id, 'TEST-M3');
|
||||
|
||||
-- Crear evaluación con puntaje inicial 24 (8*3)
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id, sesion_participante_id, intensidades
|
||||
) VALUES (
|
||||
test_muestra_id, test_participante_id,
|
||||
'{
|
||||
"fragancia": {"descriptiva": 5, "afectiva": 3},
|
||||
"aroma": {"descriptiva": 5, "afectiva": 3},
|
||||
"sabor": {"descriptiva": 5, "afectiva": 3},
|
||||
"saborResidual": {"descriptiva": 5, "afectiva": 3},
|
||||
"acidez": {"descriptiva": 5, "afectiva": 3},
|
||||
"dulzor": {"descriptiva": 5, "afectiva": 3},
|
||||
"sensacionBoca": {"descriptiva": 5, "afectiva": 3},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 3}
|
||||
}'::jsonb
|
||||
) RETURNING id, puntaje_final INTO test_eval_id, initial_score;
|
||||
|
||||
RAISE NOTICE ' ✓ Puntaje inicial: %', initial_score;
|
||||
|
||||
-- Actualizar a puntaje 40 (8*5)
|
||||
UPDATE evaluacion
|
||||
SET intensidades = '{
|
||||
"fragancia": {"descriptiva": 5, "afectiva": 5},
|
||||
"aroma": {"descriptiva": 5, "afectiva": 5},
|
||||
"sabor": {"descriptiva": 5, "afectiva": 5},
|
||||
"saborResidual": {"descriptiva": 5, "afectiva": 5},
|
||||
"acidez": {"descriptiva": 5, "afectiva": 5},
|
||||
"dulzor": {"descriptiva": 5, "afectiva": 5},
|
||||
"sensacionBoca": {"descriptiva": 5, "afectiva": 5},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 5}
|
||||
}'::jsonb
|
||||
WHERE id = test_eval_id;
|
||||
|
||||
SELECT puntaje_final INTO updated_score
|
||||
FROM evaluacion
|
||||
WHERE id = test_eval_id;
|
||||
|
||||
IF updated_score = expected_updated_score THEN
|
||||
RAISE NOTICE ' ✓ Puntaje recalculado correctamente en UPDATE: % -> % (esperado: %)',
|
||||
initial_score, updated_score, expected_updated_score;
|
||||
ELSE
|
||||
RAISE EXCEPTION ' ✗ Puntaje no se recalculó correctamente: % -> % (esperado: %)',
|
||||
initial_score, updated_score, expected_updated_score;
|
||||
END IF;
|
||||
|
||||
-- Cleanup
|
||||
DELETE FROM sesion WHERE id = test_sesion_id;
|
||||
DELETE FROM auth.users WHERE id = test_user_id;
|
||||
|
||||
RAISE NOTICE '✓ Trigger puntaje_final se recalcula correctamente en UPDATE';
|
||||
END $$;
|
||||
|
||||
\echo ''
|
||||
|
||||
\echo '=========================================='
|
||||
\echo 'Tests de Triggers completados'
|
||||
\echo '=========================================='
|
||||
Reference in New Issue
Block a user