package feeds import ( "context" "fmt" "os" "strings" "testing" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) // TestRotateExportFeedPublicToken creates an ephemeral sandbox company (never A1 / // Platform Demo), rotates the export public token, and asserts revoke semantics. func TestRotateExportFeedPublicToken(t *testing.T) { dsn := strings.TrimSpace(os.Getenv("DATABASE_URL")) if dsn == "" { t.Skip("DATABASE_URL not set") } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() pg, err := pgxpool.New(ctx, dsn) if err != nil { t.Fatalf("pool: %v", err) } defer pg.Close() companyID := uuid.New() prefix := companyID.String()[:8] _, err = pg.Exec(ctx, `INSERT INTO companies (id, name) VALUES ($1, $2)`, companyID, "export-rotate-"+prefix) if err != nil { t.Fatalf("seed company: %v", err) } t.Cleanup(func() { _, _ = pg.Exec(context.Background(), `DELETE FROM companies WHERE id = $1`, companyID) }) svc := &Service{Pool: pg} created, err := svc.CreateExportFeed(ctx, companyID, CreateExportInput{ Name: "rotate-smoke-" + prefix, Format: "xml", }) if err != nil { t.Fatalf("CreateExportFeed: %v", err) } oldTok, _ := created["public_token"].(string) if !validPublicToken(oldTok) || len(oldTok) != 64 { t.Fatalf("create public_token=%q want 64-hex", oldTok) } feedID, ok := created["id"].(uuid.UUID) if !ok { idStr := fmt.Sprint(created["id"]) feedID, err = uuid.Parse(idStr) if err != nil { t.Fatalf("export id: %v (%v)", err, created["id"]) } } rotated, err := svc.RotateExportFeedPublicToken(ctx, companyID, feedID) if err != nil { t.Fatalf("RotateExportFeedPublicToken: %v", err) } newTok, _ := rotated["public_token"].(string) if !validPublicToken(newTok) || len(newTok) != 64 { t.Fatalf("rotated public_token=%q want 64-hex", newTok) } if newTok == oldTok { t.Fatal("rotate must replace public_token") } got, err := svc.GetExportFeed(ctx, companyID, feedID) if err != nil { t.Fatalf("GetExportFeed: %v", err) } if fmt.Sprint(got["public_token"]) != newTok { t.Fatalf("persisted token=%v want %s", got["public_token"], newTok) } var byOld int err = pg.QueryRow(ctx, ` SELECT COUNT(*) FROM export_feeds WHERE company_id = $1 AND public_token = $2`, companyID, oldTok).Scan(&byOld) if err != nil { t.Fatalf("count old token: %v", err) } if byOld != 0 { t.Fatal("old public_token still present after rotate (not revoked)") } otherCompany := uuid.New() _, err = svc.RotateExportFeedPublicToken(ctx, otherCompany, feedID) if err == nil || !strings.Contains(err.Error(), "not found") { t.Fatalf("cross-tenant rotate err=%v want not found", err) } }