TS104 linhas3.611 bytes
apps/worker/tests/adm-falhas.ts
SHA-256
17d1af49de0245cfc36a197afb25c14d623f443639ee78c06f38a40154a746c4
Somente leiturafonte-acf635076da2
/**
* Reprodução do bug: falha upstream do ADM vira "zero despesas" silencioso.
*
* Esperado APÓS o fix: getCeapLeg57 lança erro em vez de devolver {} quando
* o upstream falha (HTTP != 2xx, corpo não-array, ou timeout).
*/
import type { Env } from '../src/types'
import { getCeapLeg57 } from '../src/services/adm'
const memKV = () => {
const m = new Map<string, unknown>()
return {
get: async (k: string) => (m.has(k) ? m.get(k) : null),
put: async (k: string, v: string) => void m.set(k, JSON.parse(v)),
delete: async (k: string) => void m.delete(k),
list: async () => ({ keys: [] }),
}
}
function fakeEnv(): Env {
return { ADM_BASE_URL: 'https://adm.test', SENADO_CACHE: memKV() } as unknown as Env
}
const origFetch = globalThis.fetch
async function cenario(nome: string, resposta: () => Response | Promise<never>) {
globalThis.fetch = (async () => resposta()) as typeof fetch
try {
const out = await getCeapLeg57(fakeEnv())
const soma = Object.values(out).reduce((a, b) => a + b, 0)
console.log(
`FALHOU ${nome}: retornou ${Object.keys(out).length} senadores / soma ${soma} ` +
`(deveria ter lançado erro)`,
)
return false
} catch (e) {
console.log(`OK ${nome}: lançou ${(e as Error).message}`)
return true
} finally {
globalThis.fetch = origFetch
}
}
const json = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' } })
async function main() {
const r: boolean[] = []
r.push(await cenario('HTTP 503 do ADM', () => json({ erro: 'indisponivel' }, 503)))
r.push(await cenario('HTTP 429 do ADM', () => json({ erro: 'rate limit' }, 429)))
r.push(
await cenario('HTTP 200 com corpo que não é lista', () =>
json({ statusCode: 500, msg: 'Erro ao gerar dados' }),
),
)
r.push(
await cenario('HTTP 200 com lista vazia (upstream degradado)', () => json([])),
)
r.push(
await cenario('HTTP 200 com envelope de lista vazia', () =>
json({ statusCode: 200, msg: 'Dados gerados com sucesso', data: [] }),
),
)
r.push(
await cenario('timeout de conexão', () => {
throw new TypeError('fetch failed')
}),
)
// Envelope COM registros deve ser desembrulhado (formato novo do ADM)
globalThis.fetch = (async () =>
json({
statusCode: 200,
msg: 'Dados gerados com sucesso',
data: [{ codSenador: 739, valorReembolsado: 10, mes: 1, tipoDespesa: 'Divulgação' }],
})) as typeof fetch
const env2 = await getCeapLeg57(fakeEnv())
globalThis.fetch = origFetch
const envOk = Object.keys(env2).length === 1 && Object.values(env2)[0] === 40
console.log(`${envOk ? 'OK ' : 'FALHOU '} envelope com registros: ${JSON.stringify(env2)}`)
r.push(envOk)
// Caminho feliz continua funcionando
globalThis.fetch = (async () =>
json([
{ codSenador: 739, valorReembolsado: 100, mes: 1, tipoDespesa: 'Divulgação' },
{ codSenador: 5936, valorReembolsado: 250, mes: 2, tipoDespesa: 'Passagens' },
])) as typeof fetch
const ok = await getCeapLeg57(fakeEnv())
globalThis.fetch = origFetch
const somaOk = Object.values(ok).reduce((a, b) => a + b, 0)
const felizOk = Object.keys(ok).length === 2 && somaOk === 1400 // 4 anos x 350
console.log(
`${felizOk ? 'OK ' : 'FALHOU '} caminho feliz: ${Object.keys(ok).length} senadores, soma ${somaOk}`,
)
r.push(felizOk)
const falhas = r.filter((x) => !x).length
console.log(`\n${r.length - falhas}/${r.length} passaram`)
process.exit(falhas > 0 ? 1 : 0)
}
main()