feat: Version 1.10.0 - Refactorizacion, optimizacion UI y mejoras de seguridad

- Extraccion de helpers en backend: audit_helpers.py, helpers.py
- Modularizacion de schemas en archivos individuales por dominio
- Reduccion de audit.py en 953 lineas (74% del archivo)
- Reduccion de tickets.py en 655 lineas (60% del archivo)
- Expansion de auth.py con recuperacion de contrasenia y tokens
- Nuevos modulos: core/email.py, core/cache.py
- Reorganizacion de scripts a backend/scripts/
- Frontend: refactorizacion de audit page con array-driven components
- Frontend: correccion de 11 errores ortograficos en tickets page
- Frontend: proxy Docker corregido en vite.config.js
- Frontend: nuevas rutas forgot-password, reset-password, organization, profile
- Nuevas utilidades TS: colorUtils.ts, dateFormats.ts
- 5 nuevos archivos de tests unitarios en backend/tests/unit/
- Eliminacion de 3 scripts temporales de prueba
- Documentacion tecnica: CAMBIOS_v1.10.0.md, OPTIMIZACIONES_RENDIMIENTO.md
This commit is contained in:
2026-02-19 13:48:21 -07:00
parent 16d795e8bd
commit 517297e89a
57 changed files with 8022 additions and 3660 deletions

View File

@@ -0,0 +1,136 @@
"""
Unit Tests - Configuration - ServiceManagerWeb
Tests para app.core.config: carga de settings, valores por defecto
y propiedades derivadas. No requieren base de datos ni red.
"""
import pytest
class TestSettings:
"""Tests para la configuración centralizada de la aplicación."""
def test_settings_loads_without_error(self):
"""get_settings() debe cargar sin lanzar excepciones."""
from app.core.config import get_settings
settings = get_settings()
assert settings is not None
def test_settings_is_singleton(self):
"""get_settings() debe retornar la misma instancia (lru_cache)."""
from app.core.config import get_settings
s1 = get_settings()
s2 = get_settings()
assert s1 is s2
def test_environment_is_valid(self):
"""ENVIRONMENT debe ser uno de los valores válidos del sistema."""
from app.core.config import get_settings
settings = get_settings()
valid_envs = {"development", "staging", "production", "testing"}
assert settings.ENVIRONMENT in valid_envs, (
f"ENVIRONMENT='{settings.ENVIRONMENT}' no es un valor válido. "
f"Debe ser uno de: {valid_envs}"
)
def test_app_version_is_set(self):
"""APP_VERSION debe estar definido."""
from app.core.config import get_settings
settings = get_settings()
assert settings.APP_VERSION is not None
assert len(settings.APP_VERSION) > 0
def test_app_version_is_1_9_0(self):
"""APP_VERSION debe ser 1.9.0 en esta versión del proyecto."""
from app.core.config import get_settings
settings = get_settings()
assert settings.APP_VERSION == "1.9.0"
def test_api_version_default(self):
"""API_VERSION debe ser v1 por defecto."""
from app.core.config import get_settings
settings = get_settings()
assert settings.API_VERSION == "v1"
def test_jwt_algorithm_default(self):
"""JWT_ALGORITHM debe ser HS256 por defecto."""
from app.core.config import get_settings
settings = get_settings()
assert settings.JWT_ALGORITHM == "HS256"
def test_access_token_expire_minutes(self):
"""ACCESS_TOKEN_EXPIRE_MINUTES debe ser un entero positivo."""
from app.core.config import get_settings
settings = get_settings()
assert isinstance(settings.ACCESS_TOKEN_EXPIRE_MINUTES, int)
assert settings.ACCESS_TOKEN_EXPIRE_MINUTES > 0
def test_refresh_token_expire_days(self):
"""REFRESH_TOKEN_EXPIRE_DAYS debe ser un entero positivo."""
from app.core.config import get_settings
settings = get_settings()
assert isinstance(settings.REFRESH_TOKEN_EXPIRE_DAYS, int)
assert settings.REFRESH_TOKEN_EXPIRE_DAYS > 0
def test_secret_key_is_set(self):
"""SECRET_KEY debe estar definido y no vacío."""
from app.core.config import get_settings
settings = get_settings()
assert settings.SECRET_KEY
assert len(settings.SECRET_KEY) > 0
def test_allowed_file_extensions_is_list(self):
"""ALLOWED_FILE_EXTENSIONS debe retornar una lista."""
from app.core.config import get_settings
settings = get_settings()
extensions = settings.ALLOWED_FILE_EXTENSIONS
assert isinstance(extensions, list)
assert len(extensions) > 0
def test_allowed_file_extensions_lowercase(self):
"""Las extensiones de archivo deben estar en minúsculas."""
from app.core.config import get_settings
settings = get_settings()
for ext in settings.ALLOWED_FILE_EXTENSIONS:
assert ext == ext.lower(), f"Extensión '{ext}' no está en minúsculas"
def test_is_development_consistent(self):
"""is_development() debe ser consistente con el valor de ENVIRONMENT."""
from app.core.config import get_settings
settings = get_settings()
expected = settings.ENVIRONMENT == "development"
assert settings.is_development() is expected
def test_is_testing_consistent(self):
"""is_testing() debe ser consistente con el valor de ENVIRONMENT."""
from app.core.config import get_settings
settings = get_settings()
expected = settings.ENVIRONMENT == "testing"
assert settings.is_testing() is expected
def test_is_production_returns_false_in_testing(self):
"""is_production() debe retornar False en entorno de test."""
from app.core.config import get_settings
settings = get_settings()
assert settings.is_production() is False
def test_argon2_settings_positive(self):
"""Los parámetros de Argon2 deben ser enteros positivos."""
from app.core.config import get_settings
settings = get_settings()
assert settings.ARGON2_TIME_COST > 0
assert settings.ARGON2_MEMORY_COST > 0
assert settings.ARGON2_PARALLELISM > 0
def test_max_upload_size_positive(self):
"""MAX_UPLOAD_SIZE_MB debe ser positivo."""
from app.core.config import get_settings
settings = get_settings()
assert settings.MAX_UPLOAD_SIZE_MB > 0
def test_password_min_length(self):
"""PASSWORD_MIN_LENGTH debe ser al menos 8."""
from app.core.config import get_settings
settings = get_settings()
assert settings.PASSWORD_MIN_LENGTH >= 8