#!/usr/bin/env python3
"""
teste_e2e.py — o fluxo inteiro, do upload ao download, sem servidor rodando.
Usa o test client do Flask: exercita exatamente as rotas de app/servidor.py,
sem porta aberta e sem depender de o servidor estar de pé.
O que esta suíte existe para provar, na ordem:
1. upload NUNCA baixa nada — o download só sai do /exportar, depois de um
clique, e só quando o exportador não tem pendência;
2. SD com pendência é recusada no servidor mesmo por POST direto, e a tela
mostra formulário SÓ com os campos pendentes;
3. a correção feita no formulário chega ao JSON — e o JSON é byte-idêntico
ao do exporta_sd.py na linha de comando sobre um SD.md com a mesma
correção;
4. campo não pendente não é tocado por um Salvar (o formulário só manda o
que está pendente, e o servidor só toca no que vem).
Roda assim:
python3 scripts/teste_e2e.py
0 = tudo passou; 1 = alguma checagem falhou
"""
from __future__ import annotations
import html as H
import json
import re
import subprocess
import sys
import tempfile
from io import BytesIO
from pathlib import Path
RAIZ = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(RAIZ / "scripts"))
sys.path.insert(0, str(RAIZ / "app"))
from caminhos import PROJETOS # noqa: E402
from regras_sd import ler_sd_texto, secao # noqa: E402
import servidor # noqa: E402
FALHAS: list[str] = []
CLIENTE = servidor.app.test_client()
SD8 = PROJETOS / "P2-vacinacao/sds/SD8-mvp-vacina-em-dia/SD.md"
SD10 = PROJETOS / "P2-vacinacao/sds/SD10-crie/SD.md"
SD20 = PROJETOS / "P4-cancer-de-mama/sds/SD20-siscan-d1/SD.md"
SD24 = PROJETOS / "P5-portal-rmds/sds/SD24-mvp-institucional/SD.md"
SD31 = PROJETOS / "P7-assistencia-farmaceutica/sds/SD31-fundacao-da-base-de-dispensacao/SD.md"
def ck(cond, desc):
print(f" {'ok ' if cond else 'FALHA'} {desc}")
if not cond:
FALHAS.append(desc)
def post(rota, dados=None, **kw):
return CLIENTE.post(rota, data=dados or {}, follow_redirects=True, **kw)
def texto(resp):
return resp.get_data(as_text=True)
def enviar(caminho: Path, nome: str | None = None, conteudo: bytes | None = None):
dados = {"arquivo": (BytesIO(conteudo if conteudo is not None else caminho.read_bytes()),
nome or caminho.name)}
return post("/upload", dados, content_type="multipart/form-data")
def pagina():
return texto(CLIENTE.get("/revisar", follow_redirects=True))
def reiniciar():
post("/reiniciar")
def campos_do_form(pag: str) -> dict:
"""Relê o formulário de pendências como o navegador o reenviaria."""
campos = {}
for m in re.finditer(r']*name="([^"]+)"[^>]*>', pag):
tag = m.group(0)
if any(t in tag for t in ('type="radio"', 'type="checkbox"', 'type="file"')):
continue
v = re.search(r'value="([^"]*)"', tag)
campos[m.group(1)] = H.unescape(v.group(1)) if v else ""
for m in re.finditer(r'', pag, re.S):
campos[m.group(1)] = H.unescape(m.group(2))
for m in re.finditer(r'', pag, re.S):
sel = re.search(r'