package model import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/mysql" "gorm.io/gorm" ) // setupFileTestDB 创建测试数据库(使用MySQL) func setupFileTestDB(t *testing.T) *gorm.DB { t.Helper() // 使用 MySQL 进行测试 dsn := "root:dev123456@tcp(219.159.132.177:17173)/base?charset=utf8mb4&parseTime=true&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) require.NoError(t, err) err = db.AutoMigrate(&File{}) require.NoError(t, err) // 清理所有测试数据(TRUNCATE) db.Exec("SET FOREIGN_KEY_CHECKS = 0") db.Exec("TRUNCATE TABLE file") db.Exec("SET FOREIGN_KEY_CHECKS = 1") return db } // createTestFile 创建测试文件 func createTestFile(t *testing.T, db *gorm.DB) *File { t.Helper() now := time.Now() file := &File{ Name: "test-file.pdf", Key: "uploads/2026/02/test-file.pdf", Size: 1024000, MimeType: "application/pdf", Category: "document", IsPublic: false, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now, } err := db.Create(file).Error require.NoError(t, err) return file } // TestFileInsert 测试插入文件 func TestFileInsert(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() file := &File{ Name: "new-file.jpg", Key: "uploads/2026/02/new-file.jpg", Size: 2048000, MimeType: "image/jpeg", Category: "image", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, } id, err := FileInsert(ctx, db, file) require.NoError(t, err) assert.Greater(t, id, int64(0)) assert.Equal(t, id, file.Id) // 验证所有字段已保存 saved, err := FileFindOne(ctx, db, id) require.NoError(t, err) assert.Equal(t, "new-file.jpg", saved.Name) assert.Equal(t, "uploads/2026/02/new-file.jpg", saved.Key) assert.Equal(t, int64(2048000), saved.Size) assert.Equal(t, "image/jpeg", saved.MimeType) assert.Equal(t, "image", saved.Category) assert.True(t, saved.IsPublic) assert.Equal(t, int64(1), saved.UserId) assert.Equal(t, "local", saved.StorageType) assert.Equal(t, 1, saved.Status) assert.NotZero(t, saved.CreatedAt) assert.NotZero(t, saved.UpdatedAt) } // TestFileFindOne 测试根据ID查询文件 func TestFileFindOne(t *testing.T) { db := setupFileTestDB(t) // 创建测试文件 file := createTestFile(t, db) ctx := context.Background() // 查询文件 found, err := FileFindOne(ctx, db, file.Id) require.NoError(t, err) require.NotNil(t, found) assert.Equal(t, file.Id, found.Id) assert.Equal(t, "test-file.pdf", found.Name) assert.Equal(t, "uploads/2026/02/test-file.pdf", found.Key) assert.Equal(t, int64(1024000), found.Size) assert.Equal(t, "application/pdf", found.MimeType) assert.Equal(t, "document", found.Category) assert.False(t, found.IsPublic) assert.Equal(t, int64(1), found.UserId) } // TestFileFindOne_NotFound 测试查询不存在的文件 func TestFileFindOne_NotFound(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() found, err := FileFindOne(ctx, db, 99999) require.Error(t, err) require.Nil(t, found) assert.Equal(t, ErrNotFound, err) } // TestFileFindList_Pagination 测试分页查询 func TestFileFindList_Pagination(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() // 创建5个测试文件 now := time.Now() files := []File{ {Name: "file1.pdf", Key: "uploads/file1.pdf", Size: 1000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "file2.pdf", Key: "uploads/file2.pdf", Size: 2000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "file3.pdf", Key: "uploads/file3.pdf", Size: 3000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "file4.pdf", Key: "uploads/file4.pdf", Size: 4000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "file5.pdf", Key: "uploads/file5.pdf", Size: 5000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, } for _, f := range files { err := db.Create(&f).Error require.NoError(t, err) } // 测试分页查询(第1页,每页2条) list, total, err := FileFindList(ctx, db, 1, 2, "", "", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(5), total) assert.Len(t, list, 2) } // TestFileFindList_KeywordFilter 测试关键词筛选 func TestFileFindList_KeywordFilter(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() // 创建不同名称的文件 now := time.Now() files := []File{ {Name: "report-2026.pdf", Key: "uploads/report-2026.pdf", Size: 1000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "invoice-january.pdf", Key: "uploads/invoice-january.pdf", Size: 2000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "report-2025.pdf", Key: "uploads/report-2025.pdf", Size: 3000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, } for _, f := range files { err := db.Create(&f).Error require.NoError(t, err) } // 搜索包含 "report" 的文件 list, total, err := FileFindList(ctx, db, 1, 10, "report", "", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, list, 2) // 搜索包含 "invoice" 的文件 list, total, err = FileFindList(ctx, db, 1, 10, "invoice", "", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, list, 1) assert.Equal(t, "invoice-january.pdf", list[0].Name) } // TestFileFindList_CategoryFilter 测试分类筛选 func TestFileFindList_CategoryFilter(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() // 创建不同分类的文件 now := time.Now() files := []File{ {Name: "photo1.jpg", Key: "uploads/photo1.jpg", Size: 1000, MimeType: "image/jpeg", Category: "image", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "photo2.jpg", Key: "uploads/photo2.jpg", Size: 2000, MimeType: "image/jpeg", Category: "image", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "report.pdf", Key: "uploads/report.pdf", Size: 3000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "video.mp4", Key: "uploads/video.mp4", Size: 4000, MimeType: "video/mp4", Category: "video", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, } for _, f := range files { err := db.Create(&f).Error require.NoError(t, err) } // 筛选 image 分类 list, total, err := FileFindList(ctx, db, 1, 10, "", "image", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, list, 2) // 筛选 document 分类 list, total, err = FileFindList(ctx, db, 1, 10, "", "document", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, list, 1) assert.Equal(t, "report.pdf", list[0].Name) // 筛选 video 分类 list, total, err = FileFindList(ctx, db, 1, 10, "", "video", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, list, 1) assert.Equal(t, "video.mp4", list[0].Name) } // TestFileFindList_PermissionFilter 测试权限筛选 func TestFileFindList_PermissionFilter(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() // 创建不同用户的文件(公开和私有) now := time.Now() files := []File{ // 用户1的私有文件 {Name: "user1-private.pdf", Key: "uploads/user1-private.pdf", Size: 1000, MimeType: "application/pdf", Category: "document", IsPublic: false, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, // 用户1的公开文件 {Name: "user1-public.pdf", Key: "uploads/user1-public.pdf", Size: 2000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, // 用户2的私有文件 {Name: "user2-private.pdf", Key: "uploads/user2-private.pdf", Size: 3000, MimeType: "application/pdf", Category: "document", IsPublic: false, UserId: 2, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, // 用户2的公开文件 {Name: "user2-public.pdf", Key: "uploads/user2-public.pdf", Size: 4000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 2, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, } for _, f := range files { err := db.Create(&f).Error require.NoError(t, err) } // 测试1:admin 角色可以看到所有文件 list, total, err := FileFindList(ctx, db, 1, 10, "", "", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(4), total) assert.Len(t, list, 4) // 测试2:super_admin 角色也可以看到所有文件 list, total, err = FileFindList(ctx, db, 1, 10, "", "", "", 1, RoleSuperAdmin) require.NoError(t, err) assert.Equal(t, int64(4), total) assert.Len(t, list, 4) // 测试3:普通用户(user1)只能看到自己的文件 + 所有公开文件 list, total, err = FileFindList(ctx, db, 1, 10, "", "", "", 1, RoleUser) require.NoError(t, err) assert.Equal(t, int64(3), total) // user1的2个文件 + user2的1个公开文件 assert.Len(t, list, 3) // 验证返回的文件:user1-private, user1-public, user2-public fileNames := make(map[string]bool) for _, f := range list { fileNames[f.Name] = true } assert.True(t, fileNames["user1-private.pdf"]) assert.True(t, fileNames["user1-public.pdf"]) assert.True(t, fileNames["user2-public.pdf"]) assert.False(t, fileNames["user2-private.pdf"]) // 不应该包含 // 测试4:普通用户(user2)只能看到自己的文件 + 所有公开文件 list, total, err = FileFindList(ctx, db, 1, 10, "", "", "", 2, RoleUser) require.NoError(t, err) assert.Equal(t, int64(3), total) // user2的2个文件 + user1的1个公开文件 assert.Len(t, list, 3) // 验证返回的文件:user2-private, user2-public, user1-public fileNames = make(map[string]bool) for _, f := range list { fileNames[f.Name] = true } assert.True(t, fileNames["user2-private.pdf"]) assert.True(t, fileNames["user2-public.pdf"]) assert.True(t, fileNames["user1-public.pdf"]) assert.False(t, fileNames["user1-private.pdf"]) // 不应该包含 } // TestFileUpdate 测试更新文件 func TestFileUpdate(t *testing.T) { db := setupFileTestDB(t) // 创建测试文件 file := createTestFile(t, db) ctx := context.Background() // 修改文件数据 file.Name = "updated-file.pdf" file.Category = "report" file.IsPublic = true // 更新 err := FileUpdate(ctx, db, file) require.NoError(t, err) // 验证更新结果 updated, err := FileFindOne(ctx, db, file.Id) require.NoError(t, err) assert.Equal(t, "updated-file.pdf", updated.Name) assert.Equal(t, "report", updated.Category) assert.True(t, updated.IsPublic) // 验证其他字段未改变 assert.Equal(t, "uploads/2026/02/test-file.pdf", updated.Key) assert.Equal(t, int64(1024000), updated.Size) } // TestFileDelete 测试删除文件(软删除) func TestFileDelete(t *testing.T) { db := setupFileTestDB(t) // 创建测试文件 file := createTestFile(t, db) fileId := file.Id ctx := context.Background() // 删除文件 err := FileDelete(ctx, db, fileId) require.NoError(t, err) // 验证文件已被软删除(FileFindOne 应该返回 ErrNotFound,因为它过滤 status=1) _, err = FileFindOne(ctx, db, fileId) require.Error(t, err) assert.Equal(t, ErrNotFound, err) // 验证数据库中记录仍然存在但 status=0 var deletedFile File err = db.WithContext(ctx).Where("id = ?", fileId).First(&deletedFile).Error require.NoError(t, err) assert.Equal(t, 0, deletedFile.Status) } // TestFileFindList_EmptyResult 测试查询空列表 func TestFileFindList_EmptyResult(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() list, total, err := FileFindList(ctx, db, 1, 10, "", "", "", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Empty(t, list) } // TestFileFindList_MimeTypeFilter 测试 MIME 类型筛选 func TestFileFindList_MimeTypeFilter(t *testing.T) { db := setupFileTestDB(t) ctx := context.Background() // 创建不同 MIME 类型的文件 now := time.Now() files := []File{ {Name: "photo1.jpg", Key: "uploads/photo1.jpg", Size: 1000, MimeType: "image/jpeg", Category: "image", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "photo2.png", Key: "uploads/photo2.png", Size: 2000, MimeType: "image/png", Category: "image", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "report.pdf", Key: "uploads/report.pdf", Size: 3000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "video.mp4", Key: "uploads/video.mp4", Size: 4000, MimeType: "video/mp4", Category: "video", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now}, } for _, f := range files { err := db.Create(&f).Error require.NoError(t, err) } // 筛选 image/* 类型(前缀匹配) list, total, err := FileFindList(ctx, db, 1, 10, "", "", "image", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, list, 2) // 筛选 application/* 类型 list, total, err = FileFindList(ctx, db, 1, 10, "", "", "application", 1, RoleAdmin) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, list, 1) assert.Equal(t, "report.pdf", list[0].Name) } // BenchmarkFileInsert 性能测试 func BenchmarkFileInsert(b *testing.B) { db := setupFileTestDB(&testing.T{}) ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { file := &File{ Name: "benchmark-file.pdf", Key: "uploads/benchmark-file.pdf", Size: 1024000, MimeType: "application/pdf", Category: "document", IsPublic: false, UserId: 1, StorageType: "local", Status: 1, } _, _ = FileInsert(ctx, db, file) } } // BenchmarkFileFindOne 性能测试 func BenchmarkFileFindOne(b *testing.B) { db := setupFileTestDB(&testing.T{}) ctx := context.Background() // 创建测试文件 now := time.Now() file := &File{ Name: "benchmark-file.pdf", Key: "uploads/benchmark-file.pdf", Size: 1024000, MimeType: "application/pdf", Category: "document", IsPublic: false, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now, } err := db.Create(file).Error if err != nil { b.Fatal(err) } b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = FileFindOne(ctx, db, file.Id) } } // BenchmarkFileFindList 性能测试 func BenchmarkFileFindList(b *testing.B) { db := setupFileTestDB(&testing.T{}) ctx := context.Background() // 创建100个测试文件 now := time.Now() for i := 0; i < 100; i++ { file := &File{ Name: "benchmark-file.pdf", Key: "uploads/benchmark-file.pdf", Size: 1024000, MimeType: "application/pdf", Category: "document", IsPublic: true, UserId: 1, StorageType: "local", Status: 1, CreatedAt: now, UpdatedAt: now, } err := db.Create(file).Error if err != nil { b.Fatal(err) } } b.ResetTimer() for i := 0; i < b.N; i++ { _, _, _ = FileFindList(ctx, db, 1, 10, "", "", "", 1, RoleAdmin) } }