feat(v2): limit_aware 策略(UsageSource 留位)+ Router 按配置派发 + config.Routing
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/wangjia/pay/config"
|
||||
"github.com/wangjia/pay/internal/accounts"
|
||||
)
|
||||
|
||||
func TestLimitAwareFiltersOverLimit(t *testing.T) {
|
||||
usage := accounts.NewMemUsage()
|
||||
usage.Add("a1", 9000) // a1 今日已用 9000
|
||||
la := accounts.NewLimitAware(accounts.NewRoundRobin(), usage)
|
||||
cs := []config.AccountConfig{
|
||||
{AccountID: "a1", DailyLimit: 10000}, // 9000+2000=11000 > 10000 → 排除
|
||||
{AccountID: "a2", DailyLimit: 10000}, // 0+2000 <= 10000 → 合格
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
got, err := la.Pick("fake|global", cs, accounts.PickHint{AmountMinor: 2000})
|
||||
if err != nil || got.AccountID != "a2" {
|
||||
t.Fatalf("越限的 a1 应被过滤、只剩 a2, got %v err %v", got.AccountID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitAwareZeroLimitIsUnlimited(t *testing.T) {
|
||||
usage := accounts.NewMemUsage()
|
||||
usage.Add("a1", 1_000_000)
|
||||
la := accounts.NewLimitAware(accounts.NewRoundRobin(), usage)
|
||||
cs := []config.AccountConfig{{AccountID: "a1", DailyLimit: 0}} // 0=不限
|
||||
got, err := la.Pick("fake|global", cs, accounts.PickHint{AmountMinor: 999})
|
||||
if err != nil || got.AccountID != "a1" {
|
||||
t.Fatalf("DailyLimit=0 应不限, got %v err %v", got.AccountID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitAwareAllOverLimit(t *testing.T) {
|
||||
usage := accounts.NewMemUsage()
|
||||
usage.Add("a1", 10000)
|
||||
la := accounts.NewLimitAware(accounts.NewRoundRobin(), usage)
|
||||
cs := []config.AccountConfig{{AccountID: "a1", DailyLimit: 10000}}
|
||||
if _, err := la.Pick("fake|global", cs, accounts.PickHint{AmountMinor: 1}); !errors.Is(err, accounts.ErrNoAccount) {
|
||||
t.Fatalf("全部越限应 ErrNoAccount, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNopUsageDegradesToBase(t *testing.T) {
|
||||
la := accounts.NewLimitAware(accounts.NewRoundRobin(), accounts.NopUsage{})
|
||||
cs := []config.AccountConfig{
|
||||
{AccountID: "a1", DailyLimit: 100}, {AccountID: "a2", DailyLimit: 100},
|
||||
}
|
||||
// 空用量源 → 谁都不越限 → 行为 = round_robin。
|
||||
// 注:AmountMinor 须 <= DailyLimit,否则即便 used=0 单笔也会越限(0+amount>limit),
|
||||
// 那样测的是「单笔超限」而非「NopUsage 退化」,与用例名/注释矛盾——故取 10 而非 999。
|
||||
g1, _ := la.Pick("fake|global", cs, accounts.PickHint{AmountMinor: 10})
|
||||
g2, _ := la.Pick("fake|global", cs, accounts.PickHint{AmountMinor: 10})
|
||||
if g1.AccountID != "a1" || g2.AccountID != "a2" {
|
||||
t.Fatalf("NopUsage 下应退化为轮询 a1,a2, got %s,%s", g1.AccountID, g2.AccountID)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user