fix: 修复账户配额跨越时调度快照入队逻辑

This commit is contained in:
wucm667
2026-04-23 14:53:57 +08:00
parent 6449da6c8d
commit bcf4aedcde
2 changed files with 107 additions and 2 deletions

View File

@@ -199,6 +199,94 @@ func TestUsageBillingRepositoryApply_UpdatesAccountQuota(t *testing.T) {
require.InDelta(t, 3.5, quotaUsed, 0.000001)
}
func TestUsageBillingRepositoryApply_EnqueuesSchedulerOutboxOnQuotaCrossing(t *testing.T) {
ctx := context.Background()
client := testEntClient(t)
repo := NewUsageBillingRepository(client, integrationDB)
newFixture := func(t *testing.T, extra map[string]any) (int64, int64) {
t.Helper()
user := mustCreateUser(t, client, &service.User{
Email: fmt.Sprintf("usage-billing-outbox-user-%d-%s@example.com", time.Now().UnixNano(), uuid.NewString()),
PasswordHash: "hash",
})
apiKey := mustCreateApiKey(t, client, &service.APIKey{
UserID: user.ID,
Key: "sk-usage-billing-outbox-" + uuid.NewString(),
Name: "billing-outbox",
})
account := mustCreateAccount(t, client, &service.Account{
Name: "usage-billing-outbox-" + uuid.NewString(),
Type: service.AccountTypeAPIKey,
Extra: extra,
})
return apiKey.ID, account.ID
}
outboxCountFor := func(t *testing.T, accountID int64) int {
t.Helper()
var count int
require.NoError(t, integrationDB.QueryRowContext(ctx,
"SELECT COUNT(*) FROM scheduler_outbox WHERE event_type = $1 AND account_id = $2",
service.SchedulerOutboxEventAccountChanged, accountID,
).Scan(&count))
return count
}
t.Run("daily_first_crossing_enqueues", func(t *testing.T) {
apiKeyID, accountID := newFixture(t, map[string]any{
"quota_daily_limit": 10.0,
})
// 第一次低于日限额:不应入队 outbox
_, err := repo.Apply(ctx, &service.UsageBillingCommand{
RequestID: uuid.NewString(),
APIKeyID: apiKeyID,
AccountID: accountID,
AccountType: service.AccountTypeAPIKey,
AccountQuotaCost: 4,
})
require.NoError(t, err)
require.Equal(t, 0, outboxCountFor(t, accountID), "below limit should not enqueue")
// 第二次跨越日限额:应入队一次 outbox
_, err = repo.Apply(ctx, &service.UsageBillingCommand{
RequestID: uuid.NewString(),
APIKeyID: apiKeyID,
AccountID: accountID,
AccountType: service.AccountTypeAPIKey,
AccountQuotaCost: 8,
})
require.NoError(t, err)
require.Equal(t, 1, outboxCountFor(t, accountID), "crossing daily limit should enqueue once")
// 再次递增(已超):不应重复入队
_, err = repo.Apply(ctx, &service.UsageBillingCommand{
RequestID: uuid.NewString(),
APIKeyID: apiKeyID,
AccountID: accountID,
AccountType: service.AccountTypeAPIKey,
AccountQuotaCost: 2,
})
require.NoError(t, err)
require.Equal(t, 1, outboxCountFor(t, accountID), "subsequent increments beyond limit should not re-enqueue")
})
t.Run("weekly_first_crossing_enqueues", func(t *testing.T) {
apiKeyID, accountID := newFixture(t, map[string]any{
"quota_weekly_limit": 10.0,
})
_, err := repo.Apply(ctx, &service.UsageBillingCommand{
RequestID: uuid.NewString(),
APIKeyID: apiKeyID,
AccountID: accountID,
AccountType: service.AccountTypeAPIKey,
AccountQuotaCost: 15, // 单次即跨越
})
require.NoError(t, err)
require.Equal(t, 1, outboxCountFor(t, accountID), "single-shot crossing weekly limit should enqueue once")
})
}
func TestDashboardAggregationRepositoryCleanupUsageBillingDedup_BatchDeletesOldRows(t *testing.T) {
ctx := context.Background()
repo := newDashboardAggregationRepositoryWithSQL(integrationDB)