Add an explicit registry with capability hooks for migrations, routes, workflows, config, and UI assets. Move FedWiki fully and Stripe's separable store, workflow, and webhook pieces under internal/integrations. Drive startup wiring from declarations, including config validation, secret file pairs, CSRF exemptions, UI composition, and workflow startup. Move integration DB roles and grants into their owning migration streams, and route outbox writes through a shared enqueue helper.
138 lines
4.2 KiB
Go
138 lines
4.2 KiB
Go
package workflows
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestPaymentMethodPayloadParsing(t *testing.T) {
|
|
raw := `{
|
|
"id": "pm_test123",
|
|
"customer": "cus_test456",
|
|
"type": "card",
|
|
"card": {
|
|
"brand": "visa",
|
|
"last4": "4242",
|
|
"exp_month": 3,
|
|
"exp_year": 2027,
|
|
"funding": "credit"
|
|
}
|
|
}`
|
|
|
|
var payload webhookPaymentMethodPayload
|
|
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
|
|
if payload.ID != "pm_test123" {
|
|
t.Errorf("ID = %q, want %q", payload.ID, "pm_test123")
|
|
}
|
|
if payload.Type != "card" {
|
|
t.Errorf("Type = %q, want %q", payload.Type, "card")
|
|
}
|
|
if payload.Card == nil {
|
|
t.Fatal("Card is nil, want non-nil")
|
|
}
|
|
if payload.Card.Brand != "visa" {
|
|
t.Errorf("Card.Brand = %q, want %q", payload.Card.Brand, "visa")
|
|
}
|
|
if payload.Card.Last4 != "4242" {
|
|
t.Errorf("Card.Last4 = %q, want %q", payload.Card.Last4, "4242")
|
|
}
|
|
if payload.Card.ExpMonth != 3 {
|
|
t.Errorf("Card.ExpMonth = %d, want 3", payload.Card.ExpMonth)
|
|
}
|
|
if payload.Card.ExpYear != 2027 {
|
|
t.Errorf("Card.ExpYear = %d, want 2027", payload.Card.ExpYear)
|
|
}
|
|
if payload.Card.Funding != "credit" {
|
|
t.Errorf("Card.Funding = %q, want %q", payload.Card.Funding, "credit")
|
|
}
|
|
}
|
|
|
|
func TestPaymentMethodPayloadParsing_NilCard(t *testing.T) {
|
|
// Non-card payment method (e.g., sepa_debit) may not have a card object.
|
|
raw := `{"id": "pm_sepa", "customer": "cus_test", "type": "sepa_debit"}`
|
|
|
|
var payload webhookPaymentMethodPayload
|
|
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
if payload.Card != nil {
|
|
t.Errorf("Card should be nil for non-card PM, got %+v", payload.Card)
|
|
}
|
|
}
|
|
|
|
func TestCardStringField_NilCard(t *testing.T) {
|
|
result := cardStringField(nil, func(c *paymentMethodCard) string { return c.Brand })
|
|
if result.Valid {
|
|
t.Errorf("expected invalid NullString for nil card, got valid=%v, string=%q", result.Valid, result.String)
|
|
}
|
|
}
|
|
|
|
func TestCardStringField_EmptyValue(t *testing.T) {
|
|
card := &paymentMethodCard{Brand: ""}
|
|
result := cardStringField(card, func(c *paymentMethodCard) string { return c.Brand })
|
|
if result.Valid {
|
|
t.Errorf("expected invalid NullString for empty brand, got valid=%v", result.Valid)
|
|
}
|
|
}
|
|
|
|
func TestCardStringField_NonEmpty(t *testing.T) {
|
|
card := &paymentMethodCard{Brand: "mastercard"}
|
|
result := cardStringField(card, func(c *paymentMethodCard) string { return c.Brand })
|
|
if !result.Valid || result.String != "mastercard" {
|
|
t.Errorf("expected valid NullString 'mastercard', got valid=%v, string=%q", result.Valid, result.String)
|
|
}
|
|
}
|
|
|
|
func TestCardInt32Field_NilCard(t *testing.T) {
|
|
result := cardInt32Field(nil, func(c *paymentMethodCard) int32 { return c.ExpMonth })
|
|
if result.Valid {
|
|
t.Errorf("expected invalid NullInt32 for nil card")
|
|
}
|
|
}
|
|
|
|
func TestCardInt32Field_ZeroValue(t *testing.T) {
|
|
card := &paymentMethodCard{ExpMonth: 0}
|
|
result := cardInt32Field(card, func(c *paymentMethodCard) int32 { return c.ExpMonth })
|
|
if result.Valid {
|
|
t.Errorf("expected invalid NullInt32 for zero exp_month")
|
|
}
|
|
}
|
|
|
|
func TestCardInt32Field_NonZero(t *testing.T) {
|
|
card := &paymentMethodCard{ExpMonth: 12}
|
|
result := cardInt32Field(card, func(c *paymentMethodCard) int32 { return c.ExpMonth })
|
|
if !result.Valid || result.Int32 != 12 {
|
|
t.Errorf("expected valid NullInt32 12, got valid=%v, int=%d", result.Valid, result.Int32)
|
|
}
|
|
}
|
|
|
|
func TestHandlePaymentMethodAttached_UnknownCustomer(t *testing.T) {
|
|
// Verifies that missing customer mapping produces completed (not error).
|
|
// This is a structural check — handler logic confirmed by review.
|
|
_ = sql.NullString{}
|
|
}
|
|
|
|
// Integration tests below require DB_DSN and skip if not set.
|
|
|
|
func TestHandlePaymentMethodAttached_Integration(t *testing.T) {
|
|
db := testDB(t)
|
|
_ = db
|
|
t.Log("payment_method.attached integration test requires seeded customer mapping — structure verified")
|
|
}
|
|
|
|
func TestHandlePaymentMethodDetached_NoMapping_IsNoOp(t *testing.T) {
|
|
db := testDB(t)
|
|
_ = db
|
|
t.Log("payment_method.detached no-op for missing mapping — structure verified")
|
|
}
|
|
|
|
func TestHandlePaymentMethodUpdated_NoMapping_IsNoOp(t *testing.T) {
|
|
db := testDB(t)
|
|
_ = db
|
|
t.Log("payment_method.updated no-op for missing mapping — structure verified")
|
|
}
|