#!/usr/bin/env bash # # Teste de ponta a ponta dos webhooks de CRM. # # Para cada caso, calcula o HMAC-SHA256 do corpo CRU com o segredo da empresa, # envia no header X-Signature e confere o HTTP status retornado. # # Uso: # ./test_crm_endpoints.sh # BASE_URL=http://127.0.0.1:8080 COMPANY_ID=3 SECRET=xxxx ./test_crm_endpoints.sh # set -uo pipefail BASE_URL="${BASE_URL:-http://127.0.0.1:8080}" COMPANY_ID="${COMPANY_ID:-3}" SECRET="${SECRET:-50d5e7f5faadbdb7681edc0a63dcb7d6fce93e613d290794885d292cb10fcc5b}" URL="$BASE_URL/v1/webhooks/crm/$COMPANY_ID" # external_id único por execução para o teste de venda/idempotência ser determinístico. RUN_ID="TEST-$(date +%s)" PASS=0 FAIL=0 hmac() { # Assina o corpo CRU (sem newline) com o segredo, devolve o hex. printf '%s' "$1" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}' } # run [assinatura_forçada] run() { local desc="$1" expected="$2" body="$3" forced_sig="${4:-}" local sig if [[ -n "$forced_sig" ]]; then sig="$forced_sig" else sig="sha256=$(hmac "$body")" fi local resp http payload resp=$(curl -s -w $'\n%{http_code}' -X POST "$URL" \ -H "Content-Type: application/json" \ -H "X-Signature: $sig" \ --data "$body") http=$(printf '%s' "$resp" | tail -n1) payload=$(printf '%s' "$resp" | sed '$d') if [[ "$http" == "$expected" ]]; then printf ' ✅ PASS [%s] %s\n' "$http" "$desc" PASS=$((PASS + 1)) else printf ' ❌ FAIL [esperado %s, veio %s] %s\n' "$expected" "$http" "$desc" FAIL=$((FAIL + 1)) fi printf ' → %s\n' "$payload" } echo "Alvo: $URL (company_id=$COMPANY_ID)" echo "------------------------------------------------------------" echo "[1] PRODUCT — cria/atualiza SKU" run "product novo" 200 \ '{"type":"product","data":{"name":"Plano Pro CRM Test","value":199.90,"line":"Assinaturas","sold":0}}' echo "[2] PRODUCT — mesmo nome (atualiza, opcionais vazios permitidos)" run "product update com campos vazios" 200 \ '{"type":"product","data":{"name":"Plano Pro CRM Test","value":249.90,"line":""}}' echo "[3] CLIENT — cria/atualiza cliente" run "client" 200 \ '{"type":"client","data":{"phone":"+5511999990001","name":"Cliente Teste","email":"teste@crm.com","segment":"Premium"}}' echo "[4] SALE — registra venda (vincula ao produto, incrementa sku_sold)" run "sale nova" 200 \ "{\"type\":\"sale\",\"data\":{\"external_id\":\"$RUN_ID\",\"amount\":199.90,\"occurred_at\":\"2026-06-11T14:30:00\",\"product_name\":\"Plano Pro CRM Test\",\"quantity\":2,\"client_phone\":\"+5511999990001\"}}" echo "[5] SALE — reenvio do mesmo external_id (idempotência: não duplica)" run "sale duplicada" 200 \ "{\"type\":\"sale\",\"data\":{\"external_id\":\"$RUN_ID\",\"amount\":199.90,\"occurred_at\":\"2026-06-11T14:30:00\",\"product_name\":\"Plano Pro CRM Test\",\"quantity\":2}}" echo "------------------------------------------------------------" echo "Casos de erro (devem ser rejeitados):" echo "[6] Assinatura inválida → 401" run "assinatura errada" 401 \ '{"type":"product","data":{"name":"X","value":1}}' \ "sha256=deadbeef" echo "[7] Campo essencial faltando (sale sem amount) → 400" run "sale sem amount" 400 \ "{\"type\":\"sale\",\"data\":{\"external_id\":\"$RUN_ID-x\",\"occurred_at\":\"2026-06-11T14:30:00\"}}" echo "[8] type desconhecido → 400" run "type invalido" 400 \ '{"type":"foobar","data":{}}' echo "[9] Empresa inexistente → 404" COMPANY_ID_BKP="$COMPANY_ID" URL="$BASE_URL/v1/webhooks/crm/999999" run "company inexistente" 404 \ '{"type":"product","data":{"name":"X","value":1}}' URL="$BASE_URL/v1/webhooks/crm/$COMPANY_ID_BKP" echo "------------------------------------------------------------" printf 'RESULTADO: %d passou, %d falhou\n' "$PASS" "$FAIL" [[ "$FAIL" -eq 0 ]]