Iniciativa Cidadã Independente · Transparência Parlamentar
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()