Files
tokens-reef/backend/internal/handler/admin/sora_handler_test.go
User d1bf033f24 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.
2026-04-18 10:12:37 +08:00

292 lines
8.0 KiB
Go

package admin
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func TestSoraHandler_ListGenerations(t *testing.T) {
gin.SetMode(gin.TestMode)
handler := &SoraHandler{}
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodGet, "/admin/sora/generations", nil)
handler.ListGenerations(c)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "items")
}
func TestSoraHandler_ClearUserStorage_InvalidUserID(t *testing.T) {
gin.SetMode(gin.TestMode)
handler := &SoraHandler{}
testCases := []struct {
name string
userID string
expected int
}{
{"empty string", "", http.StatusBadRequest},
{"non-numeric", "abc", http.StatusBadRequest},
{"float", "1.5", http.StatusBadRequest},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodDelete, "/admin/sora/users/"+tc.userID+"/storage", nil)
c.Params = gin.Params{{Key: "id", Value: tc.userID}}
handler.ClearUserStorage(c)
assert.Equal(t, tc.expected, w.Code)
})
}
}
func TestSoraSystemStatsResponse_Fields(t *testing.T) {
resp := SoraSystemStatsResponse{
TotalUsers: 10,
TotalGenerations: 100,
TotalStorageBytes: 1024 * 1024 * 1024,
ActiveGenerations: 5,
ByStatus: map[string]int64{"completed": 80, "failed": 20},
ByModel: map[string]int64{"sora2": 50, "sora1": 50},
}
assert.Equal(t, int64(10), resp.TotalUsers)
assert.Equal(t, int64(100), resp.TotalGenerations)
assert.Equal(t, int64(1024*1024*1024), resp.TotalStorageBytes)
assert.Equal(t, int64(5), resp.ActiveGenerations)
assert.Equal(t, int64(80), resp.ByStatus["completed"])
assert.Equal(t, int64(50), resp.ByModel["sora2"])
}
func TestSoraUserStatsResponse_Fields(t *testing.T) {
resp := SoraUserStatsResponse{
UserID: 1,
Username: "testuser",
Email: "test@example.com",
QuotaBytes: 10 * 1024 * 1024 * 1024,
UsedBytes: 1 * 1024 * 1024 * 1024,
AvailableBytes: 9 * 1024 * 1024 * 1024,
QuotaSource: "user",
GenerationsCount: 10,
ActiveCount: 2,
TotalFileSizeBytes: 1 * 1024 * 1024 * 1024,
}
assert.Equal(t, int64(1), resp.UserID)
assert.Equal(t, "testuser", resp.Username)
assert.Equal(t, "test@example.com", resp.Email)
assert.Equal(t, int64(10*1024*1024*1024), resp.QuotaBytes)
assert.Equal(t, int64(1*1024*1024*1024), resp.UsedBytes)
assert.Equal(t, "user", resp.QuotaSource)
assert.Equal(t, int64(10), resp.GenerationsCount)
assert.Equal(t, int64(2), resp.ActiveCount)
}
func TestSoraGenerationAdminResponse_Fields(t *testing.T) {
completedAt := "2024-01-01T12:00:00Z"
resp := SoraGenerationAdminResponse{
ID: 1,
UserID: 100,
Username: "testuser",
Email: "test@example.com",
Model: "sora2",
Prompt: "A beautiful sunset",
MediaType: "video",
Status: "completed",
StorageType: "s3",
MediaURL: "https://example.com/video.mp4",
FileSizeBytes: 1024 * 1024 * 10,
ErrorMessage: "",
CreatedAt: "2024-01-01T10:00:00Z",
CompletedAt: &completedAt,
}
assert.Equal(t, int64(1), resp.ID)
assert.Equal(t, int64(100), resp.UserID)
assert.Equal(t, "testuser", resp.Username)
assert.Equal(t, "sora2", resp.Model)
assert.Equal(t, "video", resp.MediaType)
assert.Equal(t, "completed", resp.Status)
assert.Equal(t, "s3", resp.StorageType)
assert.Equal(t, int64(1024*1024*10), resp.FileSizeBytes)
assert.NotNil(t, resp.CompletedAt)
}
func TestSoraGenerationAdminResponse_NilCompletedAt(t *testing.T) {
resp := SoraGenerationAdminResponse{
ID: 1,
UserID: 100,
Username: "testuser",
Email: "test@example.com",
Model: "sora2",
Prompt: "A beautiful sunset",
MediaType: "video",
Status: "pending",
StorageType: "upstream",
CreatedAt: "2024-01-01T10:00:00Z",
CompletedAt: nil,
}
assert.Equal(t, "pending", resp.Status)
assert.Nil(t, resp.CompletedAt)
}
func TestNewSoraHandler(t *testing.T) {
handler := NewSoraHandler(nil, nil, nil)
assert.NotNil(t, handler)
assert.Nil(t, handler.soraGenService)
assert.Nil(t, handler.soraQuotaService)
assert.Nil(t, handler.userRepo)
}
func TestUser_SoraFields(t *testing.T) {
user := &service.User{
ID: 1,
Email: "test@example.com",
}
assert.Equal(t, int64(1), user.ID)
assert.Equal(t, "test@example.com", user.Email)
}
func TestQuotaInfo_Fields(t *testing.T) {
quota := &service.QuotaInfo{
QuotaBytes: 10 * 1024 * 1024 * 1024,
UsedBytes: 1 * 1024 * 1024 * 1024,
AvailableBytes: 9 * 1024 * 1024 * 1024,
QuotaSource: "user",
}
assert.Equal(t, int64(10*1024*1024*1024), quota.QuotaBytes)
assert.Equal(t, int64(1*1024*1024*1024), quota.UsedBytes)
assert.Equal(t, "user", quota.QuotaSource)
}
func TestSoraSystemStatsResponse_JSON(t *testing.T) {
resp := SoraSystemStatsResponse{
TotalUsers: 10,
TotalGenerations: 100,
TotalStorageBytes: 1024,
ActiveGenerations: 5,
ByStatus: map[string]int64{"completed": 80},
ByModel: map[string]int64{"sora2": 50},
}
// Verify JSON tags by checking field values
assert.Equal(t, int64(10), resp.TotalUsers)
assert.Equal(t, int64(100), resp.TotalGenerations)
assert.Equal(t, int64(1024), resp.TotalStorageBytes)
assert.Equal(t, int64(5), resp.ActiveGenerations)
}
func TestSoraUserStatsResponse_JSON(t *testing.T) {
resp := SoraUserStatsResponse{
UserID: 1,
Username: "testuser",
Email: "test@example.com",
QuotaBytes: 1024,
UsedBytes: 512,
AvailableBytes: 512,
QuotaSource: "user",
GenerationsCount: 10,
ActiveCount: 2,
TotalFileSizeBytes: 1024,
}
// Verify all fields
assert.Equal(t, int64(1), resp.UserID)
assert.Equal(t, "testuser", resp.Username)
assert.Equal(t, "test@example.com", resp.Email)
assert.Equal(t, int64(1024), resp.QuotaBytes)
assert.Equal(t, int64(512), resp.UsedBytes)
assert.Equal(t, int64(512), resp.AvailableBytes)
assert.Equal(t, "user", resp.QuotaSource)
assert.Equal(t, int64(10), resp.GenerationsCount)
assert.Equal(t, int64(2), resp.ActiveCount)
assert.Equal(t, int64(1024), resp.TotalFileSizeBytes)
}
func TestSoraSystemStatsResponse_EmptyMaps(t *testing.T) {
resp := SoraSystemStatsResponse{
TotalUsers: 0,
TotalGenerations: 0,
TotalStorageBytes: 0,
ActiveGenerations: 0,
ByStatus: map[string]int64{},
ByModel: map[string]int64{},
}
assert.Equal(t, int64(0), resp.TotalUsers)
assert.Equal(t, int64(0), resp.TotalGenerations)
assert.Equal(t, int64(0), resp.TotalStorageBytes)
assert.Equal(t, int64(0), resp.ActiveGenerations)
assert.NotNil(t, resp.ByStatus)
assert.NotNil(t, resp.ByModel)
}
func TestSoraUserStatsResponse_QuotaSources(t *testing.T) {
sources := []string{"user", "group", "system", "unlimited"}
for _, source := range sources {
resp := SoraUserStatsResponse{
UserID: 1,
QuotaSource: source,
}
assert.Equal(t, source, resp.QuotaSource)
}
}
func TestSoraGenerationAdminResponse_Statuses(t *testing.T) {
statuses := []string{"pending", "generating", "completed", "failed", "cancelled"}
for _, status := range statuses {
resp := SoraGenerationAdminResponse{
ID: 1,
Status: status,
}
assert.Equal(t, status, resp.Status)
}
}
func TestSoraGenerationAdminResponse_MediaTypes(t *testing.T) {
mediaTypes := []string{"video", "image"}
for _, mt := range mediaTypes {
resp := SoraGenerationAdminResponse{
ID: 1,
MediaType: mt,
}
assert.Equal(t, mt, resp.MediaType)
}
}
func TestSoraGenerationAdminResponse_StorageTypes(t *testing.T) {
storageTypes := []string{"s3", "upstream"}
for _, st := range storageTypes {
resp := SoraGenerationAdminResponse{
ID: 1,
StorageType: st,
}
assert.Equal(t, st, resp.StorageType)
}
}