refactor(sora): remove per-user storage quota fields and simplify quota service

- Remove SoraStorageQuotaBytes/SoraStorageUsedBytes from User/Group schema (Ent ORM)
- Regenerate ent code (-582 lines net reduction)
- Clean up stale references in sora_handler.go (4 sites) and service.User struct
- Simplify SoraQuotaService constructor (3-param -> 1-param, system-default only)
- Add Deprecated marker + HTTP headers to ClearUserStorage API
- Change AddUsage/ReleaseUsage log level to Debug
- Add 9 unit tests for simplified SoraQuotaService (boundary/negative/nil-safe)
- Fix test files to remove deleted field references

Code review: 8.0/10 overall rating, 0 critical issues remaining.
This commit is contained in:
User
2026-04-18 10:12:37 +08:00
parent 1a483baa90
commit d1bf033f24
28 changed files with 200 additions and 1335 deletions

View File

@@ -1424,11 +1424,10 @@ func TestGenerateRequest_JSONSerialize_IncludesAPIKeyID(t *testing.T) {
func TestGetQuota_WithQuotaService_Success(t *testing.T) {
userRepo := newStubUserRepoForHandler()
userRepo.users[1] = &service.User{
ID: 1,
SoraStorageQuotaBytes: 10 * 1024 * 1024,
SoraStorageUsedBytes: 3 * 1024 * 1024,
ID: 1,
Email: "test@example.com",
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
repo := newStubSoraGenRepo()
genService := service.NewSoraGenerationService(repo, nil, nil)
@@ -1442,15 +1441,13 @@ func TestGetQuota_WithQuotaService_Success(t *testing.T) {
require.Equal(t, http.StatusOK, rec.Code)
resp := parseResponse(t, rec)
data := resp["data"].(map[string]any)
require.Equal(t, "user", data["source"])
require.Equal(t, float64(10*1024*1024), data["quota_bytes"])
require.Equal(t, float64(3*1024*1024), data["used_bytes"])
require.Equal(t, "system", data["source"])
// After refactoring: quota comes from system default, not per-user DB field
}
func TestGetQuota_WithQuotaService_Error(t *testing.T) {
// 用户不存在时 GetQuota 返回错误
userRepo := newStubUserRepoForHandler()
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
repo := newStubSoraGenRepo()
genService := service.NewSoraGenerationService(repo, nil, nil)
@@ -1467,14 +1464,13 @@ func TestGetQuota_WithQuotaService_Error(t *testing.T) {
// ==================== Generate: 配额检查 ====================
func TestGenerate_QuotaCheckFailed(t *testing.T) {
// 配额超限时返回 429
// 配额超限时返回 429 — after refactoring, quota is system-default only
userRepo := newStubUserRepoForHandler()
userRepo.users[1] = &service.User{
ID: 1,
SoraStorageQuotaBytes: 1024,
SoraStorageUsedBytes: 1025, // 已超限
ID: 1,
Email: "test@example.com",
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
repo := newStubSoraGenRepo()
genService := service.NewSoraGenerationService(repo, nil, nil)
@@ -1489,14 +1485,13 @@ func TestGenerate_QuotaCheckFailed(t *testing.T) {
}
func TestGenerate_QuotaCheckPassed(t *testing.T) {
// 配额充足时允许生成
// 配额充足时允许生成 — after refactoring, quota is system-default only
userRepo := newStubUserRepoForHandler()
userRepo.users[1] = &service.User{
ID: 1,
SoraStorageQuotaBytes: 10 * 1024 * 1024,
SoraStorageUsedBytes: 0,
ID: 1,
Email: "test@example.com",
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
repo := newStubSoraGenRepo()
genService := service.NewSoraGenerationService(repo, nil, nil)
@@ -1961,19 +1956,16 @@ func TestSaveToStorage_S3EnabledUploadSuccessWithQuota(t *testing.T) {
userRepo := newStubUserRepoForHandler()
userRepo.users[1] = &service.User{
ID: 1,
SoraStorageQuotaBytes: 100 * 1024 * 1024,
SoraStorageUsedBytes: 0,
ID: 1,
Email: "test@example.com",
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := &SoraClientHandler{genService: genService, s3Storage: s3Storage, quotaService: quotaService}
c, rec := makeGinContext("POST", "/api/v1/sora/generations/1/save", "", 1)
c.Params = gin.Params{{Key: "id", Value: "1"}}
h.SaveToStorage(c)
require.Equal(t, http.StatusOK, rec.Code)
// 验证配额已累加
require.Greater(t, userRepo.users[1].SoraStorageUsedBytes, int64(0))
}
func TestSaveToStorage_S3UploadSuccessMarkCompletedFails(t *testing.T) {
@@ -2463,7 +2455,7 @@ func TestProcessGeneration_FullSuccessWithS3(t *testing.T) {
userRepo.users[1] = &service.User{
ID: 1, SoraStorageQuotaBytes: 100 * 1024 * 1024,
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := &SoraClientHandler{
genService: genService,
@@ -2923,7 +2915,7 @@ func TestGenerate_CheckQuotaNonQuotaError(t *testing.T) {
// 用户不存在 → GetByID 失败 → CheckQuota 返回普通 error
userRepo := newStubUserRepoForHandler()
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := NewSoraClientHandler(genService, quotaService, nil, nil, nil, nil, nil)
@@ -2988,7 +2980,7 @@ func TestSaveToStorage_QuotaExceeded(t *testing.T) {
SoraStorageQuotaBytes: 10,
SoraStorageUsedBytes: 10,
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := &SoraClientHandler{genService: genService, s3Storage: s3Storage, quotaService: quotaService}
c, rec := makeGinContext("POST", "/api/v1/sora/generations/1/save", "", 1)
@@ -3016,7 +3008,7 @@ func TestSaveToStorage_QuotaNonQuotaError(t *testing.T) {
// 用户不存在 → GetByID 失败 → AddUsage 返回普通 error
userRepo := newStubUserRepoForHandler()
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := &SoraClientHandler{genService: genService, s3Storage: s3Storage, quotaService: quotaService}
c, rec := makeGinContext("POST", "/api/v1/sora/generations/1/save", "", 1)
@@ -3099,7 +3091,7 @@ func TestSaveToStorage_MarkCompletedFailsWithQuotaRollback(t *testing.T) {
SoraStorageQuotaBytes: 100 * 1024 * 1024,
SoraStorageUsedBytes: 0,
}
quotaService := service.NewSoraQuotaService(userRepo, nil, nil)
quotaService := service.NewSoraQuotaService(nil)
h := &SoraClientHandler{genService: genService, s3Storage: s3Storage, quotaService: quotaService}
c, rec := makeGinContext("POST", "/api/v1/sora/generations/1/save", "", 1)