La integración VCard vivía solo en /api/v1, que autentica por cookie de sesión: obliga a manejar cookie jar, no permite allowlist por IP y no se puede revocar sin tocar la contraseña del usuario (ver docs/api-v1-contrato.md, punto 7). Ahora los mismos controladores están también bajo /api/v2/vcard/* con Bearer + IP + scope, que es lo que administra la pantalla /app/api-keys. El scope "vcard" acota la llave a estos 12 endpoints: sin él, esa integración tendría acceso a los otros ~300 de v2. /api/v1 se mantiene intacto — esto es un camino nuevo, no un reemplazo forzado, así que lo que ya está instalado sigue andando mientras migran. Se agregan dos chequeos porque el compilador no ve ninguno de los dos errores: que las 12 rutas queden registradas con su método y path (un typo se descubriría recién con un 404 del lado del integrador), y que todas figuren en el spec de /api/v2, que se mantiene a mano y se desincroniza en silencio. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package routes
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// Las rutas de VCard en /api/v2 son el camino que va a usar una integración
|
|
// externa. Un error de tipeo en un path no lo detecta el compilador — se
|
|
// descubre cuando el integrador recibe un 404. Esto lo fija.
|
|
func TestRutasVcardRegistradas(t *testing.T) {
|
|
app := fiber.New()
|
|
AdminApiRoutes(app)
|
|
|
|
registradas := map[string]bool{}
|
|
for _, capa := range app.Stack() {
|
|
for _, r := range capa {
|
|
registradas[r.Method+" "+r.Path] = true
|
|
}
|
|
}
|
|
|
|
esperadas := []string{
|
|
"POST /v2/vcard/qr-tmp",
|
|
"POST /v2/vcard/qr",
|
|
"POST /v2/vcard/qr-url",
|
|
"POST /v2/vcard/vcf",
|
|
"POST /v2/vcard/dlocal/planes",
|
|
"GET /v2/vcard/dlocal/planes",
|
|
"GET /v2/vcard/dlocal/planes/:planID",
|
|
"PATCH /v2/vcard/dlocal/planes/:planID",
|
|
"PATCH /v2/vcard/dlocal/planes/:planId/suscripciones/:subscriptionId/desactivar",
|
|
"GET /v2/vcard/dlocal/suscripciones/:subscriptionId/ejecuciones/:invoiceId",
|
|
"POST /v2/vcard/dlocal/pagos",
|
|
"POST /v2/vcard/rapyd/wallets",
|
|
}
|
|
for _, e := range esperadas {
|
|
if !registradas[e] {
|
|
t.Errorf("falta la ruta %q", e)
|
|
}
|
|
}
|
|
}
|
|
|
|
// El spec de /api/v2 se mantiene a mano, así que se desincroniza en silencio.
|
|
// Este chequeo obliga a que cada ruta nueva de vcard aparezca documentada.
|
|
func TestSpecDocumentaLasRutasVcard(t *testing.T) {
|
|
app := fiber.New()
|
|
AdminApiRoutes(app)
|
|
|
|
var paths []string
|
|
for _, capa := range app.Stack() {
|
|
for _, r := range capa {
|
|
if strings.HasPrefix(r.Path, "/v2/vcard/") && r.Method != "HEAD" {
|
|
paths = append(paths, "/api"+r.Path)
|
|
}
|
|
}
|
|
}
|
|
if len(paths) == 0 {
|
|
t.Fatal("no se registró ninguna ruta de vcard")
|
|
}
|
|
|
|
spec, err := leerSpecComoTexto()
|
|
if err != nil {
|
|
t.Skipf("no se pudo leer el spec: %v", err)
|
|
}
|
|
for _, p := range paths {
|
|
if !strings.Contains(spec, p) {
|
|
t.Errorf("la ruta %q está registrada pero no figura en el spec de /api/v2", p)
|
|
}
|
|
}
|
|
}
|