Pular para conteúdo

E2E local — nuvem → ERP → nuvem

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-20

Roteiro para provar o fluxo de entrada COMPLETO na máquina de desenvolvimento, usando o harness xadm/etc/tests/e2e-pied-local (Postgres + Mongo + PowerSync + Integrador + int-pied + integrador-client) e um pAbast fake (que faz o handshake e ecoa 006) no lugar do zimrtmu.exe. O harness é Windows-nativo (scripts PowerShell + Docker Desktop); os .sh/zimrtmu.exe POSIX que ainda estão na pasta são legado da fase WSL.

Subir e testar (Windows / PowerShell)

Dois modos. O simulado (recomendado p/ provar só integrador↔integrador-client↔ZIM) sobe a stack SEM o int-pied e injeta o pedido direto no Integrador via seed-curl.ps1 — um comando fecha o ponta a ponta:

cd C:\Work\Xadm\etc\tests\e2e-pied-local
.\startup.ps1 -SemIntPied    # sobe tudo menos o int-pied (Docker + Integrador + client)
.\seed-curl.ps1 -Esperar     # injeta um pedido (PUT /api/v1/xadm) e espera o cod_retorno voltar
                             # -> "ponta a ponta OK - contratos.E2E-SIM-1 cod_retorno=006"
.\shutdown.ps1               # ou -Wipe para zerar o banco

Java 25: o integrador-server (Micronaut 5.x) exige JVM 25 para buildar e rodar; o _config.ps1 aponta $JAVA para o JDK 25. O integrador-client é --release 8 e roda em qualquer JDK. O startup.ps1 builda os jars que faltarem.

O modo completo (com int-pied real + seed.sh/captura.json) segue no RUNBOOK.md do harness. Injeção manual equivalente ao seed-curl.ps1, para referência:

$body = @{ Origem='INT-PIED'
  propriedades=@(@{CgcCpf='55666777000188';CodProp='01';NomeProp='Cliente E2E';Cidade='Ponta Grossa';Estado=' PR'})
  estoque=@(@{CodigoAlt='GER-5KW';NomeProd='Gerador 5kW';Venda=18990.00;VendaPz=19990.00})
  contratos=@(@{xPed='E2E-F6-1';CgcCpfCliente='55666777000188';VlTot=18990.00;TpVda='C'})
  itensped=@(@{xPed='E2E-F6-1';CodigoAlt='GER-5KW';Qtde=1;Valor=18990.00;Total=18990.00}) } | ConvertTo-Json -Depth 6
Invoke-RestMethod -Method Put http://localhost:8081/api/v1/xadm -Headers @{Authorization='Bearer dev-e2e-token'} -ContentType application/json -Body $body

docker compose exec -T postgres psql -U postgres -d xadm_e2e -c "SELECT pied_x_ped, cod_retorno, msg_retorno FROM contratos;"

pAbast fake handshake-aware: no Windows o zim.executavel aponta para zim-fake/zimrtmu.cmd, que delega ao zimrtmu-fake.ps1 (preserva windows-1252/CRLF/espaços à esquerda). O fake faz a dança do handshake — escreve Iniciou Zim, espera IMPORTA_PIED, então ecoa 006 — igual ao src/test/resources/pabast-fake/feliz.bat. Um fake sem handshake faz o cliente atual matar o processo e retentar o lote pra sempre.

O caminho percorrido: PUT /api/v1/xadm grava as tabelas-espelho com cod_retorno=000 → PowerSync replica ao SQLite local do cliente → Processador coleta o lote na ordem dos fatos, marca 001, escreve o dXpEnvio, roda o pAbast (fake), lê o dXpRetorno → aplica 006 → o SDK faz o write-back (POST /api/v1/powersync) → o Postgres da nuvem termina com o status.

Com o manifesto ligado, o PUT também cria a remessa e o cliente só coleta o que ela cobre inteiro (decisão 0004). Enquanto as sync rules do maxsul/powersync não publicarem integracao_remessa/integracao_remessa_item, o e2e roda pelo caminho por presença — o mesmo de antes —, com o detalhe de que uma linha sem remessa cumpre 3 ciclos de carência se houver manifesto no banco local. Num e2e sem manifesto nenhum, não há carência e o comportamento é idêntico ao descrito acima.

Evidência

Windows, modo simulado (2026-07-28): .\startup.ps1 -SemIntPied + .\seed-curl.ps1 -Esperar com o fake handshake-aware (zimrtmu.cmd→zimrtmu-fake.ps1):

Injetando pedido E2E-SIM-1 no Integrador (PUT /api/v1/xadm)... resposta: {"requestId":1,"resultado":"SUCESSO"}
Processador - lote com 5 registro(s) pendente(s)
EnvioRetornoHttp - write-back propriedades|fones|estoque|contratos|itensped aceito
Processador - lote aplicado: 5 gravado(s), 0 erro(s) terminal(is), 0 para retentar
ponta a ponta OK - contratos.E2E-SIM-1 cod_retorno=006 (todas as 5 tabelas: 006 Gravado pelo fake)

Linux/WSL, modo completo (execução histórica de 2026-07-20, ambiente zerado com --wipe):

Log do integrador-client:

16:47:11.664 INFO Processador - lote com 4 registro(s) pendente(s)
16:47:11.742 INFO Processador - lote aplicado: 4 gravado(s), 0 erro(s) terminal(is), 0 para retentar
16:47:12.123 INFO EnvioRetornoHttp - write-back propriedades id=2e53a8e3-… aceito (requestId=6)
16:47:12.169 INFO EnvioRetornoHttp - write-back estoque      id=729b335c-… aceito (requestId=7)
16:47:12.205 INFO EnvioRetornoHttp - write-back contratos    id=60a52038-… aceito (requestId=8)
16:47:12.244 INFO EnvioRetornoHttp - write-back itensped     id=0173bab2-… aceito (requestId=9)

Postgres da nuvem ao final:

      t       |      chave      | cod_retorno |    msg_retorno
--------------+-----------------+-------------+-------------------
 contratos    | E2E-F6-1        | 006         | Gravado pelo fake
 itensped     | E2E-F6-1        | 006         | Gravado pelo fake
 propriedades | 55666777000188  | 006         | Gravado pelo fake
 estoque      | GER-5KW         | 006         | Gravado pelo fake

Notas

  • A chave dev do harness (keys/dev-private.pem, kid poc-key-v1) é gerada localmente e o JWK público correspondente vive inline no powersync/config.yaml do harness — nada de produção.
  • Comportamento do SDK observado e coberto: enquanto houver CRUD local sem upload confirmado, checkpoints novos NÃO são aplicados (offline-first) — com o write-back real a fila anda e o download segue.
  • Contra o ZIM real, basta trocar zim.executavel/zim.diretorio no properties — o contrato é o de dev/contrato-pabast.md.

Backoff em erro transiente (baixa de MDF-e)

O harness etc/tests/local/e2e-sascar-mdfe prova ponta a ponta a desaceleração/backoff do cliente quando o ZIM devolve 9XX (reprocessável) — o bug do retry frenético. O zim-fake responde 933 nas primeiras K tentativas (arquivo zim-fake/transiente.count) e 006 depois; o seed-backoff.ps1 dirige a baixa e assere no log que o item foi retentado poucas vezes com intervalo crescente (piso 1s → ~2s → ~4s), não em loop apertado, terminando em 006. Cobre o comportamento do Agendador/Processador (desaceleração no 9XX aplicado) num ambiente real.

O irmão seed-writeback-down.ps1 derruba o integrador-server durante a write-back. Achado do e2e: o PowerSync Kotlin 1.13.x não re-tenta o upload que falhou quando a nuvem volta (nem o cliente Kotlin nem o Rust; upgrade pra 1.14.1 não corrige e regride o teardown no Windows) — a operação fica presa na ps_crud até reconectar. Por isso o cliente tem o VigiaWriteBack: se a fila fica presa

20s, reconecta e re-dispara o upload. O seed prova o ciclo completo: servidor fora → nuvem retida → servidor volta → vigia reconecta → 006 reconcilia. Evidência no log: VigiaWriteBack - write-back preso: N operação(ões) na fila há ~20s — reconectando.