From 4a91954532a2d6facc6e64c4925056c78e38a950 Mon Sep 17 00:00:00 2001 From: shaw Date: Tue, 3 Mar 2026 16:00:51 +0800 Subject: [PATCH] fix: correct migration 061 checksum and add missing BillingCache mock methods - Fix fileChecksum for 061 migration: use TrimSpace hash (66207e7a) instead of raw sha256sum (97bdd9a3), matching the actual runtime computation - Add 222b4a09 as accepted DB checksum for 061 migration - Add missing GetAPIKeyRateLimit/SetAPIKeyRateLimit/UpdateAPIKeyRateLimitUsage/ InvalidateAPIKeyRateLimit methods to mock BillingCache in test stubs - Fix NewBillingCacheService call in singleflight test (add apiKeyRepo param) --- ...allowed_groups_contract_integration_test.go | 2 +- backend/internal/repository/api_key_repo.go | 6 +++++- .../api_key_repo_integration_test.go | 4 ++-- .../internal/repository/migrations_runner.go | 3 ++- .../migrations_runner_checksum_test.go | 11 ++++++++++- .../soft_delete_ent_integration_test.go | 6 +++--- .../billing_cache_service_singleflight_test.go | 18 +++++++++++++++++- backend/internal/service/user_service_test.go | 12 ++++++++++++ 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/backend/internal/repository/allowed_groups_contract_integration_test.go b/backend/internal/repository/allowed_groups_contract_integration_test.go index 0d0f11e5..b0af0d54 100644 --- a/backend/internal/repository/allowed_groups_contract_integration_test.go +++ b/backend/internal/repository/allowed_groups_contract_integration_test.go @@ -98,7 +98,7 @@ func TestGroupRepository_DeleteCascade_RemovesAllowedGroupsAndClearsApiKeys(t *t userRepo := newUserRepositoryWithSQL(entClient, tx) groupRepo := newGroupRepositoryWithSQL(entClient, tx) - apiKeyRepo := NewAPIKeyRepository(entClient) + apiKeyRepo := newAPIKeyRepositoryWithSQL(entClient, tx) u := &service.User{ Email: uniqueTestValue(t, "cascade-user") + "@example.com", diff --git a/backend/internal/repository/api_key_repo.go b/backend/internal/repository/api_key_repo.go index 6007a739..3d56bd53 100644 --- a/backend/internal/repository/api_key_repo.go +++ b/backend/internal/repository/api_key_repo.go @@ -21,7 +21,11 @@ type apiKeyRepository struct { } func NewAPIKeyRepository(client *dbent.Client, sqlDB *sql.DB) service.APIKeyRepository { - return &apiKeyRepository{client: client, sql: sqlDB} + return newAPIKeyRepositoryWithSQL(client, sqlDB) +} + +func newAPIKeyRepositoryWithSQL(client *dbent.Client, sqlq sqlExecutor) *apiKeyRepository { + return &apiKeyRepository{client: client, sql: sqlq} } func (r *apiKeyRepository) activeQuery() *dbent.APIKeyQuery { diff --git a/backend/internal/repository/api_key_repo_integration_test.go b/backend/internal/repository/api_key_repo_integration_test.go index 303d7126..d7115413 100644 --- a/backend/internal/repository/api_key_repo_integration_test.go +++ b/backend/internal/repository/api_key_repo_integration_test.go @@ -26,7 +26,7 @@ func (s *APIKeyRepoSuite) SetupTest() { s.ctx = context.Background() tx := testEntTx(s.T()) s.client = tx.Client() - s.repo = NewAPIKeyRepository(s.client).(*apiKeyRepository) + s.repo = newAPIKeyRepositoryWithSQL(s.client, tx) } func TestAPIKeyRepoSuite(t *testing.T) { @@ -421,7 +421,7 @@ func (s *APIKeyRepoSuite) TestIncrementQuotaUsed_DeletedKey() { // 注意:此测试使用 testEntClient(非事务隔离),数据会真正写入数据库。 func TestIncrementQuotaUsed_Concurrent(t *testing.T) { client := testEntClient(t) - repo := NewAPIKeyRepository(client).(*apiKeyRepository) + repo := NewAPIKeyRepository(client, integrationDB).(*apiKeyRepository) ctx := context.Background() // 创建测试用户和 API Key diff --git a/backend/internal/repository/migrations_runner.go b/backend/internal/repository/migrations_runner.go index 017d578c..9cf3b392 100644 --- a/backend/internal/repository/migrations_runner.go +++ b/backend/internal/repository/migrations_runner.go @@ -67,9 +67,10 @@ var migrationChecksumCompatibilityRules = map[string]migrationChecksumCompatibil }, }, "061_add_usage_log_request_type.sql": { - fileChecksum: "97bdd9a32d921986f74a0231ab90735567a9234fb7062f4d9d1baf108ba59769", + fileChecksum: "66207e7aa5dd0429c2e2c0fabdaf79783ff157fa0af2e81adff2ee03790ec65c", acceptedDBChecksum: map[string]struct{}{ "08a248652cbab7cfde147fc6ef8cda464f2477674e20b718312faa252e0481c0": {}, + "222b4a09c797c22e5922b6b172327c824f5463aaa8760e4f621bc5c22e2be0f3": {}, }, }, } diff --git a/backend/internal/repository/migrations_runner_checksum_test.go b/backend/internal/repository/migrations_runner_checksum_test.go index 67cad963..6c3ad725 100644 --- a/backend/internal/repository/migrations_runner_checksum_test.go +++ b/backend/internal/repository/migrations_runner_checksum_test.go @@ -29,7 +29,16 @@ func TestIsMigrationChecksumCompatible(t *testing.T) { ok := isMigrationChecksumCompatible( "061_add_usage_log_request_type.sql", "08a248652cbab7cfde147fc6ef8cda464f2477674e20b718312faa252e0481c0", - "97bdd9a32d921986f74a0231ab90735567a9234fb7062f4d9d1baf108ba59769", + "66207e7aa5dd0429c2e2c0fabdaf79783ff157fa0af2e81adff2ee03790ec65c", + ) + require.True(t, ok) + }) + + t.Run("061第二个历史checksum可兼容", func(t *testing.T) { + ok := isMigrationChecksumCompatible( + "061_add_usage_log_request_type.sql", + "222b4a09c797c22e5922b6b172327c824f5463aaa8760e4f621bc5c22e2be0f3", + "66207e7aa5dd0429c2e2c0fabdaf79783ff157fa0af2e81adff2ee03790ec65c", ) require.True(t, ok) }) diff --git a/backend/internal/repository/soft_delete_ent_integration_test.go b/backend/internal/repository/soft_delete_ent_integration_test.go index ef63fbee..8c2b23da 100644 --- a/backend/internal/repository/soft_delete_ent_integration_test.go +++ b/backend/internal/repository/soft_delete_ent_integration_test.go @@ -41,7 +41,7 @@ func TestEntSoftDelete_ApiKey_DefaultFilterAndSkip(t *testing.T) { u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user")+"@example.com") - repo := NewAPIKeyRepository(client) + repo := NewAPIKeyRepository(client, integrationDB) key := &service.APIKey{ UserID: u.ID, Key: uniqueSoftDeleteValue(t, "sk-soft-delete"), @@ -73,7 +73,7 @@ func TestEntSoftDelete_ApiKey_DeleteIdempotent(t *testing.T) { u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user2")+"@example.com") - repo := NewAPIKeyRepository(client) + repo := NewAPIKeyRepository(client, integrationDB) key := &service.APIKey{ UserID: u.ID, Key: uniqueSoftDeleteValue(t, "sk-soft-delete2"), @@ -93,7 +93,7 @@ func TestEntSoftDelete_ApiKey_HardDeleteViaSkipSoftDelete(t *testing.T) { u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user3")+"@example.com") - repo := NewAPIKeyRepository(client) + repo := NewAPIKeyRepository(client, integrationDB) key := &service.APIKey{ UserID: u.ID, Key: uniqueSoftDeleteValue(t, "sk-soft-delete3"), diff --git a/backend/internal/service/billing_cache_service_singleflight_test.go b/backend/internal/service/billing_cache_service_singleflight_test.go index 1b12c402..4a8b8f03 100644 --- a/backend/internal/service/billing_cache_service_singleflight_test.go +++ b/backend/internal/service/billing_cache_service_singleflight_test.go @@ -51,6 +51,22 @@ func (s *billingCacheMissStub) InvalidateSubscriptionCache(ctx context.Context, return nil } +func (s *billingCacheMissStub) GetAPIKeyRateLimit(ctx context.Context, keyID int64) (*APIKeyRateLimitCacheData, error) { + return nil, errors.New("cache miss") +} + +func (s *billingCacheMissStub) SetAPIKeyRateLimit(ctx context.Context, keyID int64, data *APIKeyRateLimitCacheData) error { + return nil +} + +func (s *billingCacheMissStub) UpdateAPIKeyRateLimitUsage(ctx context.Context, keyID int64, cost float64) error { + return nil +} + +func (s *billingCacheMissStub) InvalidateAPIKeyRateLimit(ctx context.Context, keyID int64) error { + return nil +} + type balanceLoadUserRepoStub struct { mockUserRepo calls atomic.Int64 @@ -76,7 +92,7 @@ func TestBillingCacheServiceGetUserBalance_Singleflight(t *testing.T) { delay: 80 * time.Millisecond, balance: 12.34, } - svc := NewBillingCacheService(cache, userRepo, nil, &config.Config{}) + svc := NewBillingCacheService(cache, userRepo, nil, nil, &config.Config{}) t.Cleanup(svc.Stop) const goroutines = 16 diff --git a/backend/internal/service/user_service_test.go b/backend/internal/service/user_service_test.go index 5ba2b99e..05fe5056 100644 --- a/backend/internal/service/user_service_test.go +++ b/backend/internal/service/user_service_test.go @@ -96,6 +96,18 @@ func (m *mockBillingCache) UpdateSubscriptionUsage(context.Context, int64, int64 func (m *mockBillingCache) InvalidateSubscriptionCache(context.Context, int64, int64) error { return nil } +func (m *mockBillingCache) GetAPIKeyRateLimit(context.Context, int64) (*APIKeyRateLimitCacheData, error) { + return nil, nil +} +func (m *mockBillingCache) SetAPIKeyRateLimit(context.Context, int64, *APIKeyRateLimitCacheData) error { + return nil +} +func (m *mockBillingCache) UpdateAPIKeyRateLimitUsage(context.Context, int64, float64) error { + return nil +} +func (m *mockBillingCache) InvalidateAPIKeyRateLimit(context.Context, int64) error { + return nil +} // --- 测试 ---