- Added a new function to reject documentation placeholder hosts in database URLs, improving error handling for misconfigurations. - Updated the `get_database_url` function to incorporate this new validation, ensuring that users are alerted when using "host" as a placeholder. - Enhanced error messages to provide clearer guidance on valid host configurations. These changes aim to improve the robustness and clarity of database connection handling in the application.
159 lines
7.9 KiB
Markdown
159 lines
7.9 KiB
Markdown
# Backend test strategy (Anexo24)
|
|
|
|
## Test suites
|
|
|
|
- `tests/e2e/`: full business flow (catalogs -> import -> export -> balances/discharges).
|
|
- `tests/integration/`: process API behavior and edge cases.
|
|
- `tests/unit/`: critical algorithms only (no trivial CRUD tests).
|
|
|
|
---
|
|
|
|
## Vista del flujo de tests (backend)
|
|
|
|
### Dónde vive todo
|
|
|
|
| Capa | Ruta | Rol |
|
|
|------|------|-----|
|
|
| Infra | [conftest.py](conftest.py) | DB en transacción + rollback, Celery eager, app mínima con router de process, overrides de DB/usuario, tareas import/export **inline** en la misma sesión |
|
|
| Datos | [fixtures/builders.py](fixtures/builders.py) | Catálogos, tenant/company, facturas import/export con líneas enlazadas |
|
|
| E2E | [e2e/test_inventory_flow_anexo24.py](e2e/test_inventory_flow_anexo24.py) | Flujo negocio completo import → export → saldos/descargas |
|
|
| Integración | [integration/test_import_process_api.py](integration/test_import_process_api.py), [integration/test_export_process_api.py](integration/test_export_process_api.py) | API HTTP + reglas por tipo de factura, saldo, doble proceso |
|
|
| Unit | [unit/invoices/test_balance_algorithm.py](unit/invoices/test_balance_algorithm.py), [unit/invoices/test_currency_conversion_imports.py](unit/invoices/test_currency_conversion_imports.py) | Algoritmos puros / subprocesos sin HTTP |
|
|
|
|
### Infraestructura (flujo común)
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph fixtures [Fixtures conftest]
|
|
db[db_session: conexion + begin + Session]
|
|
roll[teardown: rollback + close]
|
|
celery[celery_eager autouse: memory broker]
|
|
app[app: FastAPI + process router]
|
|
client[TestClient]
|
|
end
|
|
db --> roll
|
|
celery --> app
|
|
db --> app
|
|
app --> client
|
|
subgraph inline [Monkeypatch rutas]
|
|
imp[process_invoice_task -> main_process import en db_session]
|
|
exp[process_export_invoice_task -> main_process export en db_session]
|
|
end
|
|
app --> inline
|
|
```
|
|
|
|
- **BD**: `TEST_DATABASE_URL` o `CORE_DATABASE_URL` o `settings.core_database_url`. Cada test corre dentro de una transacción; al terminar **no persiste** nada (rollback).
|
|
- **Celery**: sin Redis; `task_always_eager` para que el endpoint dispare lógica síncrona.
|
|
- **Seguridad en tests**: `validate_access_to_resource` se reemplaza por un stub que devuelve `tenant_id` del usuario fake.
|
|
|
|
### Builders: qué se construye antes de llamar a la API
|
|
|
|
Orden típico en casi todos los tests que tocan proceso:
|
|
|
|
1. `ensure_reference_data`: tipos de factura (`TEM`, `DEF`, `MEX`, `DONAC`) y régimen `A1` si no existen.
|
|
2. `ensure_tenant_company(tenant_id=1, company_id=1)`.
|
|
3. `create_business_catalogs`: proveedor/cliente/destinatario (con dirección idempotente vía `_ensure_client_provider_address`), agente aduanal, UoM, part number FA, tipo cambio, etc.
|
|
4. `create_import_invoice_with_line` / `create_export_invoice_with_line` según el caso.
|
|
|
|
### Parches al pipeline (import / export)
|
|
|
|
Los tests **no** ejecutan validadores pesados del proceso real; sustituyen funciones en `main_process` para aislar el comportamiento de saldos y API:
|
|
|
|
**Import** (varios tests): `pre_validators` devuelve la línea creada; se anulan reviews de clase, tipo de cambio, pesos, SISIMP, `_validate_lines`.
|
|
|
|
**Export**: análogo con `pre_validators` + reviews de clase, TC, asignación, cantidad vs peso, costo, series.
|
|
|
|
**Caso especial** — `test_process_endpoint_prevents_double_processing_import` en [integration/test_export_process_api.py](integration/test_export_process_api.py): usa `_patch_import_pipeline_without_prevalidators` (sin parchear `pre_validators`) para que el **segundo** `POST /process` recorra el flujo real y dispare la validación de “ya procesado”.
|
|
|
|
### Mapa por archivo y edge cases
|
|
|
|
#### E2E — [e2e/test_inventory_flow_anexo24.py](e2e/test_inventory_flow_anexo24.py)
|
|
|
|
- **Flujo**: datos ref + tenant/company + catálogos → factura import `TEM` qty 10 → `POST .../process` → comprueba `BalanceMovement` tipo `ENTRY` → factura export ligada a import/línea qty 4 → `POST process` → comprueba `CONSUMPTION`, `DischargeHeader`, `DischargeDetail` con `movement_id`.
|
|
- **Edge implícito**: saldo neto por línea de import ≥ 0 y < 10 tras consumo parcial (no agota todo el inventario del escenario).
|
|
|
|
#### Integración import — [integration/test_import_process_api.py](integration/test_import_process_api.py)
|
|
|
|
| Test | Qué valida |
|
|
|------|------------|
|
|
| `test_process_import_endpoint_creates_balance_entries` | `TEM` + process → al menos un `ENTRY` por factura/línea |
|
|
| `test_process_import_def_does_not_create_balance_entries` | `DEF` + process → **ningún** movimiento de saldo (edge: tipo operación no genera entradas de balance) |
|
|
|
|
#### Integración export + doble proceso — [integration/test_export_process_api.py](integration/test_export_process_api.py)
|
|
|
|
| Test | Qué valida |
|
|
|------|------------|
|
|
| `_prepare_inventory` + `test_process_export_endpoint_consumes_existing_balances` | Tras import `TEM` qty 10, export qty 3 → existen `CONSUMPTION` |
|
|
| `test_process_export_prevents_negative_balance` | Export qty 99 vs saldo 10 → `ValidationException` y **cero** consumos para esa factura export |
|
|
| `test_process_endpoint_prevents_double_processing_import` | Segundo `POST` misma factura import → `ValidationException`; exactamente **un** `ENTRY` (no duplicar PEPS) |
|
|
|
|
#### Unit saldos / FIFO — [unit/invoices/test_balance_algorithm.py](unit/invoices/test_balance_algorithm.py)
|
|
|
|
- **`test_net_balance_accounts_for_returns_and_entry_void`**: `_net_balance_for_lot` con ENTRY, CONSUMPTION, RETURN, ENTRY_VOID (fórmula documentada en el docstring: 10 - 4 + 1 - 2 = 5).
|
|
- **`test_fifo_consumption_algorithm_uses_oldest_lots_first`**: `compare_balances` con dos `AvailableLot` (órdenes 1 y 2), demanda 6; parche `_resolve_import_uom` → PZA; comprueba consumo 3+3 y `quantity_used == 6`.
|
|
|
|
#### Unit IVA / moneda — [unit/invoices/test_currency_conversion_imports.py](unit/invoices/test_currency_conversion_imports.py)
|
|
|
|
- Tres monedas en `assign_values_iva_lines`: **FOREIGN (ME)**, **LOCAL (MN)**, **MANUAL (MC)** con `SimpleNamespace` (sin BD).
|
|
|
|
### Diagrama de flujo de negocio (E2E + integración export)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant T as Test
|
|
participant API as POST process
|
|
participant DB as Session PostgreSQL
|
|
T->>DB: seed ref + catalogs + import invoice
|
|
T->>API: process import
|
|
API->>DB: ENTRY movements
|
|
T->>DB: export invoice linked
|
|
T->>API: process export
|
|
alt qty OK
|
|
API->>DB: CONSUMPTION + discharges
|
|
else qty over balance
|
|
API-->>T: ValidationException
|
|
end
|
|
```
|
|
|
|
### Resumen de edge cases explícitos en la suite
|
|
|
|
- **Tipo factura import**: `TEM` genera saldo; `DEF` no.
|
|
- **Saldo insuficiente en export**: error y sin consumos.
|
|
- **Doble procesamiento import**: error en segundo POST y una sola entrada.
|
|
- **Neteo de movimientos**: retornos y anulaciones de entrada en el cálculo de saldo.
|
|
- **FIFO**: reparto entre lotes por `order_peps`.
|
|
- **Moneda / IVA**: tres modos de captura y conversión esperada.
|
|
|
|
### BD compartida / CI
|
|
|
|
Si `TEST_DATABASE_URL` apunta a una base con datos previos, los builders reutilizan filas existentes donde aplica (por ejemplo direcciones de clientes vía `_ensure_client_provider_address`). Para máximo aislamiento, usar una BD o esquema dedicado a tests.
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
- PostgreSQL test database available.
|
|
- Environment variable:
|
|
- `TEST_DATABASE_URL=postgresql://user:pass@127.0.0.1:5432/db_name` (sustituye por el host real alcanzable desde el runner; no uses el literal `host` de los ejemplos genéricos)
|
|
|
|
## Run commands
|
|
|
|
- Fast subset (CI gate):
|
|
- `pytest -q tests/unit tests/integration`
|
|
- Full suite:
|
|
- `pytest -q tests`
|
|
- `pytest tests -v -ra`
|
|
- `pytest tests -v -ra -s`
|
|
- E2E only:
|
|
- `pytest -q tests/e2e`
|
|
|
|
## CI recommendations
|
|
|
|
- Pull request gate:
|
|
- Run unit + integration on every PR.
|
|
- Nightly / main branch:
|
|
- Run full suite including E2E.
|
|
- Keep Celery eager mode for deterministic process endpoint tests:
|
|
- `task_always_eager=True`
|
|
- `task_eager_propagates=True`
|