Add a full payment and subscription system supporting EasyPay (Alipay/WeChat), Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
207 lines
5.8 KiB
Go
207 lines
5.8 KiB
Go
package service
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/payment"
|
|
)
|
|
|
|
func TestPcParseFloat(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
defaultVal float64
|
|
expected float64
|
|
}{
|
|
{"empty string returns default", "", 1.0, 1.0},
|
|
{"valid float", "3.14", 0, 3.14},
|
|
{"valid integer as float", "42", 0, 42.0},
|
|
{"invalid string returns default", "notanumber", 9.99, 9.99},
|
|
{"zero value", "0", 5.0, 0},
|
|
{"negative value", "-10.5", 0, -10.5},
|
|
{"very large value", "99999999.99", 0, 99999999.99},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
got := pcParseFloat(tt.input, tt.defaultVal)
|
|
if got != tt.expected {
|
|
t.Fatalf("pcParseFloat(%q, %v) = %v, want %v", tt.input, tt.defaultVal, got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPcParseInt(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
defaultVal int
|
|
expected int
|
|
}{
|
|
{"empty string returns default", "", 30, 30},
|
|
{"valid int", "10", 0, 10},
|
|
{"invalid string returns default", "abc", 5, 5},
|
|
{"float string returns default", "3.14", 0, 0},
|
|
{"zero value", "0", 99, 0},
|
|
{"negative value", "-1", 0, -1},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
got := pcParseInt(tt.input, tt.defaultVal)
|
|
if got != tt.expected {
|
|
t.Fatalf("pcParseInt(%q, %v) = %v, want %v", tt.input, tt.defaultVal, got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParsePaymentConfig(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := &PaymentConfigService{}
|
|
|
|
t.Run("empty vals uses defaults", func(t *testing.T) {
|
|
t.Parallel()
|
|
cfg := svc.parsePaymentConfig(map[string]string{})
|
|
if cfg.Enabled {
|
|
t.Fatal("expected Enabled=false by default")
|
|
}
|
|
if cfg.MinAmount != 1 {
|
|
t.Fatalf("expected MinAmount=1, got %v", cfg.MinAmount)
|
|
}
|
|
if cfg.MaxAmount != 0 {
|
|
t.Fatalf("expected MaxAmount=0 (no limit), got %v", cfg.MaxAmount)
|
|
}
|
|
if cfg.OrderTimeoutMin != 30 {
|
|
t.Fatalf("expected OrderTimeoutMin=30, got %v", cfg.OrderTimeoutMin)
|
|
}
|
|
if cfg.MaxPendingOrders != 3 {
|
|
t.Fatalf("expected MaxPendingOrders=3, got %v", cfg.MaxPendingOrders)
|
|
}
|
|
if cfg.LoadBalanceStrategy != payment.DefaultLoadBalanceStrategy {
|
|
t.Fatalf("expected LoadBalanceStrategy=%s, got %q", payment.DefaultLoadBalanceStrategy, cfg.LoadBalanceStrategy)
|
|
}
|
|
if len(cfg.EnabledTypes) != 0 {
|
|
t.Fatalf("expected empty EnabledTypes, got %v", cfg.EnabledTypes)
|
|
}
|
|
})
|
|
|
|
t.Run("all values populated", func(t *testing.T) {
|
|
t.Parallel()
|
|
vals := map[string]string{
|
|
SettingPaymentEnabled: "true",
|
|
SettingMinRechargeAmount: "5.00",
|
|
SettingMaxRechargeAmount: "1000.00",
|
|
SettingDailyRechargeLimit: "5000.00",
|
|
SettingOrderTimeoutMinutes: "15",
|
|
SettingMaxPendingOrders: "5",
|
|
SettingEnabledPaymentTypes: "alipay,wxpay,stripe",
|
|
SettingBalancePayDisabled: "true",
|
|
SettingLoadBalanceStrategy: "least_amount",
|
|
SettingProductNamePrefix: "PRE",
|
|
SettingProductNameSuffix: "SUF",
|
|
}
|
|
cfg := svc.parsePaymentConfig(vals)
|
|
|
|
if !cfg.Enabled {
|
|
t.Fatal("expected Enabled=true")
|
|
}
|
|
if cfg.MinAmount != 5 {
|
|
t.Fatalf("MinAmount = %v, want 5", cfg.MinAmount)
|
|
}
|
|
if cfg.MaxAmount != 1000 {
|
|
t.Fatalf("MaxAmount = %v, want 1000", cfg.MaxAmount)
|
|
}
|
|
if cfg.DailyLimit != 5000 {
|
|
t.Fatalf("DailyLimit = %v, want 5000", cfg.DailyLimit)
|
|
}
|
|
if cfg.OrderTimeoutMin != 15 {
|
|
t.Fatalf("OrderTimeoutMin = %v, want 15", cfg.OrderTimeoutMin)
|
|
}
|
|
if cfg.MaxPendingOrders != 5 {
|
|
t.Fatalf("MaxPendingOrders = %v, want 5", cfg.MaxPendingOrders)
|
|
}
|
|
if len(cfg.EnabledTypes) != 3 {
|
|
t.Fatalf("EnabledTypes len = %d, want 3", len(cfg.EnabledTypes))
|
|
}
|
|
if cfg.EnabledTypes[0] != "alipay" || cfg.EnabledTypes[1] != "wxpay" || cfg.EnabledTypes[2] != "stripe" {
|
|
t.Fatalf("EnabledTypes = %v, want [alipay wxpay stripe]", cfg.EnabledTypes)
|
|
}
|
|
if !cfg.BalanceDisabled {
|
|
t.Fatal("expected BalanceDisabled=true")
|
|
}
|
|
if cfg.LoadBalanceStrategy != "least_amount" {
|
|
t.Fatalf("LoadBalanceStrategy = %q, want %q", cfg.LoadBalanceStrategy, "least_amount")
|
|
}
|
|
if cfg.ProductNamePrefix != "PRE" {
|
|
t.Fatalf("ProductNamePrefix = %q, want %q", cfg.ProductNamePrefix, "PRE")
|
|
}
|
|
if cfg.ProductNameSuffix != "SUF" {
|
|
t.Fatalf("ProductNameSuffix = %q, want %q", cfg.ProductNameSuffix, "SUF")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled types with spaces are trimmed", func(t *testing.T) {
|
|
t.Parallel()
|
|
vals := map[string]string{
|
|
SettingEnabledPaymentTypes: " alipay , wxpay ",
|
|
}
|
|
cfg := svc.parsePaymentConfig(vals)
|
|
if len(cfg.EnabledTypes) != 2 {
|
|
t.Fatalf("EnabledTypes len = %d, want 2", len(cfg.EnabledTypes))
|
|
}
|
|
if cfg.EnabledTypes[0] != "alipay" || cfg.EnabledTypes[1] != "wxpay" {
|
|
t.Fatalf("EnabledTypes = %v, want [alipay wxpay]", cfg.EnabledTypes)
|
|
}
|
|
})
|
|
|
|
t.Run("empty enabled types string", func(t *testing.T) {
|
|
t.Parallel()
|
|
vals := map[string]string{
|
|
SettingEnabledPaymentTypes: "",
|
|
}
|
|
cfg := svc.parsePaymentConfig(vals)
|
|
if len(cfg.EnabledTypes) != 0 {
|
|
t.Fatalf("expected empty EnabledTypes for empty string, got %v", cfg.EnabledTypes)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetBasePaymentType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
input string
|
|
expected string
|
|
}{
|
|
{payment.TypeEasyPay, payment.TypeEasyPay},
|
|
{payment.TypeStripe, payment.TypeStripe},
|
|
{payment.TypeCard, payment.TypeStripe},
|
|
{payment.TypeLink, payment.TypeStripe},
|
|
{payment.TypeAlipay, payment.TypeAlipay},
|
|
{payment.TypeAlipayDirect, payment.TypeAlipay},
|
|
{payment.TypeWxpay, payment.TypeWxpay},
|
|
{payment.TypeWxpayDirect, payment.TypeWxpay},
|
|
{"unknown", "unknown"},
|
|
{"", ""},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
t.Parallel()
|
|
got := payment.GetBasePaymentType(tt.input)
|
|
if got != tt.expected {
|
|
t.Fatalf("GetBasePaymentType(%q) = %q, want %q", tt.input, got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|