diff --git a/models/file_test.go b/models/file_test.go index 7e53c49..0f97184 100644 --- a/models/file_test.go +++ b/models/file_test.go @@ -15,22 +15,62 @@ func TestFile_Create(t *testing.T) { Name: "123", } - mock.ExpectBegin() - mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(5, 1)) - mock.ExpectCommit() - fileID, err := file.Create() - asserts.NoError(err) - asserts.Equal(uint(5), fileID) - asserts.Equal(uint(5), file.ID) - asserts.NoError(mock.ExpectationsWereMet()) + // 无法插入文件记录 + { + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)").WillReturnError(errors.New("error")) + mock.ExpectRollback() + err := file.Create() + asserts.Error(err) + asserts.NoError(mock.ExpectationsWereMet()) + } - mock.ExpectBegin() - mock.ExpectExec("INSERT(.+)").WillReturnError(errors.New("error")) - mock.ExpectRollback() - fileID, err = file.Create() - asserts.Error(err) - asserts.NoError(mock.ExpectationsWereMet()) + // 无法更新用户容量 + { + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(5, 1)) + mock.ExpectExec("UPDATE(.+)").WillReturnError(errors.New("error")) + mock.ExpectRollback() + err := file.Create() + asserts.Error(err) + asserts.NoError(mock.ExpectationsWereMet()) + } + + // 成功 + { + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(5, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectCommit() + err := file.Create() + asserts.NoError(err) + asserts.Equal(uint(5), file.ID) + asserts.NoError(mock.ExpectationsWereMet()) + } +} + +func TestFile_AfterFind(t *testing.T) { + a := assert.New(t) + file := File{ + Name: "123", + Metadata: "{\"name\":\"123\"}", + } + + a.NoError(file.AfterFind()) + a.Equal("123", file.MetadataSerialized["name"]) +} + +func TestFile_BeforeSave(t *testing.T) { + a := assert.New(t) + file := File{ + Name: "123", + MetadataSerialized: map[string]string{ + "name": "123", + }, + } + a.NoError(file.BeforeSave()) + a.Equal("{\"name\":\"123\"}", file.Metadata) } func TestFolder_GetChildFile(t *testing.T) { @@ -175,6 +215,17 @@ func TestGetChildFilesOfFolders(t *testing.T) { } } +func TestGetUploadPlaceholderFiles(t *testing.T) { + a := assert.New(t) + + mock.ExpectQuery("SELECT(.+)upload_session_id(.+)"). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "1")) + files := GetUploadPlaceholderFiles(1) + a.NoError(mock.ExpectationsWereMet()) + a.Len(files, 1) +} + func TestFile_GetPolicy(t *testing.T) { asserts := assert.New(t) @@ -282,28 +333,50 @@ func TestRemoveFilesWithSoftLinks(t *testing.T) { } } -func TestDeleteFileByIDs(t *testing.T) { - asserts := assert.New(t) +func TestDeleteFiles(t *testing.T) { + a := assert.New(t) - // 出错 + // uid 不一致 + { + err := DeleteFiles([]*File{{}}, 1) + a.Contains("User id not consistent", err.Error()) + } + + // 删除失败 { mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). WillReturnError(errors.New("error")) mock.ExpectRollback() - err := DeleteFileByIDs([]uint{1, 2, 3}) - asserts.NoError(mock.ExpectationsWereMet()) - asserts.Error(err) + err := DeleteFiles([]*File{{}}, 0) + a.NoError(mock.ExpectationsWereMet()) + a.Error(err) } - // 成功 + + // 无法变更用户容量 { mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). - WillReturnResult(sqlmock.NewResult(0, 3)) + WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnError(errors.New("error")) + mock.ExpectRollback() + err := DeleteFiles([]*File{{}}, 0) + a.NoError(mock.ExpectationsWereMet()) + a.Error(err) + } + + // 成功,其中一个文件已经不存在 + { + mock.ExpectBegin() + mock.ExpectExec("DELETE(.+)"). + WillReturnResult(sqlmock.NewResult(1, 0)) + mock.ExpectExec("DELETE(.+)"). + WillReturnResult(sqlmock.NewResult(2, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)").WithArgs(uint64(2), sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() - err := DeleteFileByIDs([]uint{1, 2, 3}) - asserts.NoError(mock.ExpectationsWereMet()) - asserts.NoError(err) + err := DeleteFiles([]*File{{Size: 1}, {Size: 2}}, 0) + a.NoError(mock.ExpectationsWereMet()) + a.NoError(err) } } @@ -324,6 +397,19 @@ func TestGetFilesByParentIDs(t *testing.T) { asserts.Len(files, 3) } +func TestGetFilesByUploadSession(t *testing.T) { + a := assert.New(t) + + mock.ExpectQuery("SELECT(.+)"). + WithArgs(1, "sessionID"). + WillReturnRows( + sqlmock.NewRows([]string{"id", "name"}).AddRow(4, "4.txt")) + files, err := GetFilesByUploadSession("sessionID", 1) + a.NoError(err) + a.NoError(mock.ExpectationsWereMet()) + a.Equal("4.txt", files.Name) +} + func TestFile_Updates(t *testing.T) { asserts := assert.New(t) file := File{Model: gorm.Model{ID: 1}} @@ -340,24 +426,93 @@ func TestFile_Updates(t *testing.T) { // UpdatePicInfo { mock.ExpectBegin() - mock.ExpectExec("UPDATE(.+)").WithArgs(10, sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)").WithArgs("1,1", 1).WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() - err := file.UpdateSize(10) + err := file.UpdatePicInfo("1,1") asserts.NoError(mock.ExpectationsWereMet()) asserts.NoError(err) } - // UpdatePicInfo + // UpdateSourceName { mock.ExpectBegin() - mock.ExpectExec("UPDATE(.+)").WithArgs("1,1", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)").WithArgs("newName", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() - err := file.UpdatePicInfo("1,1") + err := file.UpdateSourceName("newName") asserts.NoError(mock.ExpectationsWereMet()) asserts.NoError(err) } } +func TestFile_UpdateSize(t *testing.T) { + a := assert.New(t) + + // 增加成功 + { + file := File{Size: 10} + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(11, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)+(.+)").WithArgs(uint64(1), sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + a.NoError(file.UpdateSize(11)) + a.NoError(mock.ExpectationsWereMet()) + } + + // 减少成功 + { + file := File{Size: 10} + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(8, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)-(.+)").WithArgs(uint64(2), sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + a.NoError(file.UpdateSize(8)) + a.NoError(mock.ExpectationsWereMet()) + } + + // 文件更新失败 + { + file := File{Size: 10} + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(8, sqlmock.AnyArg(), 10).WillReturnError(errors.New("error")) + mock.ExpectRollback() + + a.Error(file.UpdateSize(8)) + a.NoError(mock.ExpectationsWereMet()) + } + + // 用户容量更新失败 + { + file := File{Size: 10} + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)files(.+)").WithArgs(8, sqlmock.AnyArg(), 10).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)-(.+)").WithArgs(uint64(2), sqlmock.AnyArg()).WillReturnError(errors.New("error")) + mock.ExpectRollback() + + a.Error(file.UpdateSize(8)) + a.NoError(mock.ExpectationsWereMet()) + } +} + +func TestFile_PopChunkToFile(t *testing.T) { + a := assert.New(t) + timeNow := time.Now() + file := File{} + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + a.NoError(file.PopChunkToFile(&timeNow, "1,1")) +} + +func TestFile_CanCopy(t *testing.T) { + a := assert.New(t) + file := File{} + a.True(file.CanCopy()) + file.UploadSessionID = &file.Name + a.False(file.CanCopy()) +} + func TestFile_FileInfoInterface(t *testing.T) { asserts := assert.New(t) file := File{ diff --git a/models/folder_test.go b/models/folder_test.go index 7c74f48..8174708 100644 --- a/models/folder_test.go +++ b/models/folder_test.go @@ -212,12 +212,14 @@ func TestFolder_MoveOrCopyFileTo(t *testing.T) { WithArgs( 1, 2, + 3, 1, 1, ).WillReturnRows( - sqlmock.NewRows([]string{"id", "size"}). - AddRow(1, 10). - AddRow(2, 20), + sqlmock.NewRows([]string{"id", "size", "upload_session_id"}). + AddRow(1, 10, nil). + AddRow(2, 20, nil). + AddRow(2, 20, &folder.Name), ) mock.ExpectBegin() mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) @@ -226,7 +228,7 @@ func TestFolder_MoveOrCopyFileTo(t *testing.T) { mock.ExpectExec("INSERT(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() storage, err := folder.MoveOrCopyFileTo( - []uint{1, 2}, + []uint{1, 2, 3}, &dstFolder, true, ) @@ -335,7 +337,7 @@ func TestFolder_CopyFolderTo(t *testing.T) { // 测试复制目录结构 // test(2)(5) // 1(3)(6) 2.txt - // 3(4)(7) 4.txt + // 3(4)(7) 4.txt 5.txt(上传中) // 正常情况 成功 { @@ -360,9 +362,10 @@ func TestFolder_CopyFolderTo(t *testing.T) { mock.ExpectQuery("SELECT(.+)"). WithArgs(1, 2, 3, 4). WillReturnRows( - sqlmock.NewRows([]string{"id", "name", "folder_id", "size"}). - AddRow(1, "2.txt", 2, 10). - AddRow(2, "3.txt", 3, 20), + sqlmock.NewRows([]string{"id", "name", "folder_id", "size", "upload_session_id"}). + AddRow(1, "2.txt", 2, 10, nil). + AddRow(2, "3.txt", 3, 20, nil). + AddRow(3, "5.txt", 3, 20, &dstFolder.Name), ) // 复制子文件 diff --git a/models/policy.go b/models/policy.go index 4a827fb..a5f4826 100644 --- a/models/policy.go +++ b/models/policy.go @@ -179,27 +179,6 @@ func (policy *Policy) GenerateFileName(uid uint, origin string) string { return fileRule } -func (policy Policy) getOriginNameRule(origin string) string { - // 部分存储策略可以使用{origin}代表原始文件名 - if origin == "" { - // 如果上游未传回原始文件名,则使用占位符,让云存储端替换 - switch policy.Type { - case "qiniu": - // 七牛会将$(fname)自动替换为原始文件名 - return "$(fname)" - case "local", "remote": - return origin - case "oss", "cos": - // OSS会将${filename}自动替换为原始文件名 - return "${filename}" - case "upyun": - // Upyun会将{filename}{.suffix}自动替换为原始文件名 - return "{filename}{.suffix}" - } - } - return origin -} - // IsDirectlyPreview 返回此策略下文件是否可以直接预览(不需要重定向) func (policy *Policy) IsDirectlyPreview() bool { return policy.Type == "local" diff --git a/models/policy_test.go b/models/policy_test.go index 433d1ec..c888ada 100644 --- a/models/policy_test.go +++ b/models/policy_test.go @@ -104,7 +104,7 @@ func TestPolicy_GenerateFileName(t *testing.T) { asserts.Equal("123.txt", testPolicy.GenerateFileName(1, "123.txt")) testPolicy.Type = "oss" - asserts.Equal("${filename}", testPolicy.GenerateFileName(1, "")) + asserts.Equal("origin", testPolicy.GenerateFileName(1, "origin")) } // 重命名开启 @@ -145,19 +145,23 @@ func TestPolicy_GenerateFileName(t *testing.T) { testPolicy.Type = "oss" testPolicy.FileNameRule = "{uid}123{originname}" - asserts.Equal("1123${filename}", testPolicy.GenerateFileName(1, "")) + asserts.Equal("1123123321", testPolicy.GenerateFileName(1, "123321")) testPolicy.Type = "upyun" testPolicy.FileNameRule = "{uid}123{originname}" - asserts.Equal("1123{filename}{.suffix}", testPolicy.GenerateFileName(1, "")) + asserts.Equal("1123123321", testPolicy.GenerateFileName(1, "123321")) testPolicy.Type = "qiniu" testPolicy.FileNameRule = "{uid}123{originname}" - asserts.Equal("1123$(fname)", testPolicy.GenerateFileName(1, "")) + asserts.Equal("1123123321", testPolicy.GenerateFileName(1, "123321")) testPolicy.Type = "local" testPolicy.FileNameRule = "{uid}123{originname}" asserts.Equal("1123", testPolicy.GenerateFileName(1, "")) + + testPolicy.Type = "local" + testPolicy.FileNameRule = "{ext}123{uuid}" + asserts.Contains(testPolicy.GenerateFileName(1, "123.txt"), ".txt123") } } @@ -170,78 +174,6 @@ func TestPolicy_IsDirectlyPreview(t *testing.T) { asserts.False(policy.IsDirectlyPreview()) } -func TestPolicy_GetUploadURL(t *testing.T) { - asserts := assert.New(t) - - // 本地 - { - cache.Set("setting_siteURL", "http://127.0.0.1", 0) - policy := Policy{Type: "local", Server: "http://127.0.0.1"} - asserts.Equal("/api/v3/file/upload", policy.GetUploadURL()) - } - - // 远程 - { - policy := Policy{Type: "remote", Server: "http://127.0.0.1"} - asserts.Equal("http://127.0.0.1/api/v3/slave/upload", policy.GetUploadURL()) - } - - // OSS - { - policy := Policy{Type: "oss", BucketName: "base", Server: "127.0.0.1"} - asserts.Equal("https://base.127.0.0.1", policy.GetUploadURL()) - } - - // cos - { - policy := Policy{Type: "cos", BaseURL: "base", Server: "http://127.0.0.1"} - asserts.Equal("http://127.0.0.1", policy.GetUploadURL()) - } - - // upyun - { - policy := Policy{Type: "upyun", BucketName: "base", Server: "http://127.0.0.1"} - asserts.Equal("https://v0.api.upyun.com/base", policy.GetUploadURL()) - } - - // 未知 - { - policy := Policy{Type: "unknown", Server: "http://127.0.0.1"} - asserts.Equal("http://127.0.0.1", policy.GetUploadURL()) - } - - // S3 未填写自动生成 - { - policy := Policy{ - Type: "s3", - Server: "", - BucketName: "bucket", - OptionsSerialized: PolicyOption{Region: "us-east"}, - } - asserts.Equal("https://bucket.s3.us-east.amazonaws.com/", policy.GetUploadURL()) - } - - // s3 自己指定 - { - policy := Policy{ - Type: "s3", - Server: "https://s3.us-east.amazonaws.com/", - BucketName: "bucket", - OptionsSerialized: PolicyOption{Region: "us-east"}, - } - asserts.Equal("https://s3.us-east.amazonaws.com/bucket", policy.GetUploadURL()) - } - -} - -func TestPolicy_IsPathGenerateNeeded(t *testing.T) { - asserts := assert.New(t) - policy := Policy{Type: "qiniu"} - asserts.True(policy.IsPathGenerateNeeded()) - policy.Type = "remote" - asserts.False(policy.IsPathGenerateNeeded()) -} - func TestPolicy_ClearCache(t *testing.T) { asserts := assert.New(t) cache.Set("policy_202", 1, 0) @@ -266,15 +198,18 @@ func TestPolicy_UpdateAccessKey(t *testing.T) { func TestPolicy_Props(t *testing.T) { asserts := assert.New(t) policy := Policy{Type: "onedrive"} + policy.OptionsSerialized.PlaceholderWithSize = true asserts.False(policy.IsThumbGenerateNeeded()) - asserts.True(policy.IsPathGenerateNeeded()) - asserts.True(policy.IsTransitUpload(4)) + asserts.False(policy.IsTransitUpload(4)) asserts.False(policy.IsTransitUpload(5 * 1024 * 1024)) asserts.True(policy.CanStructureBeListed()) + asserts.True(policy.IsUploadPlaceholderWithSize()) policy.Type = "local" asserts.True(policy.IsThumbGenerateNeeded()) - asserts.True(policy.IsPathGenerateNeeded()) asserts.False(policy.CanStructureBeListed()) + asserts.False(policy.IsUploadPlaceholderWithSize()) + policy.Type = "remote" + asserts.True(policy.IsUploadPlaceholderWithSize()) } func TestPolicy_IsThumbExist(t *testing.T) { diff --git a/models/setting_test.go b/models/setting_test.go index d9bf962..96fc5e0 100644 --- a/models/setting_test.go +++ b/models/setting_test.go @@ -59,6 +59,15 @@ func TestGetSettingByType(t *testing.T) { asserts.Equal(map[string]string{}, settings) } +func TestGetSettingByNameWithDefault(t *testing.T) { + a := assert.New(t) + + rows := sqlmock.NewRows([]string{"name", "value", "type"}) + mock.ExpectQuery("^SELECT \\* FROM `(.+)` WHERE `(.+)`\\.`deleted_at` IS NULL AND(.+)$").WillReturnRows(rows) + settings := GetSettingByNameWithDefault("123", "123321") + a.Equal("123321", settings) +} + func TestGetSettingByNames(t *testing.T) { cache.Store = cache.NewMemoStore() asserts := assert.New(t) diff --git a/models/tag_test.go b/models/tag_test.go index 6063234..be8d3fb 100644 --- a/models/tag_test.go +++ b/models/tag_test.go @@ -56,8 +56,8 @@ func TestGetTagsByUID(t *testing.T) { func TestGetTagsByID(t *testing.T) { asserts := assert.New(t) mock.ExpectQuery("SELECT(.+)").WillReturnRows(sqlmock.NewRows([]string{"name"}).AddRow("tag")) - res, err := GetTagsByUID(1) + res, err := GetTagsByID(1, 1) asserts.NoError(mock.ExpectationsWereMet()) asserts.NoError(err) - asserts.EqualValues("tag", res[0].Name) + asserts.EqualValues("tag", res.Name) }