diff --git a/models/file_test.go b/models/file_test.go index 4f031ca..b47424d 100644 --- a/models/file_test.go +++ b/models/file_test.go @@ -322,3 +322,37 @@ func TestGetFilesByParentIDs(t *testing.T) { asserts.NoError(mock.ExpectationsWereMet()) asserts.Len(files, 3) } + +func TestFile_Updates(t *testing.T) { + asserts := assert.New(t) + file := File{Model: gorm.Model{ID: 1}} + // rename + { + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)").WithArgs("newName", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + err := file.Rename("newName") + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } + + // UpdatePicInfo + { + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)").WithArgs(10, sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + err := file.UpdateSize(10) + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } + + // UpdatePicInfo + { + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)").WithArgs("1,1", sqlmock.AnyArg(), 1).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + err := file.UpdatePicInfo("1,1") + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } +} diff --git a/pkg/filesystem/hooks.go b/pkg/filesystem/hooks.go index b1d3365..c5c8e86 100644 --- a/pkg/filesystem/hooks.go +++ b/pkg/filesystem/hooks.go @@ -75,7 +75,7 @@ func HookValidateFile(ctx context.Context, fs *FileSystem) error { } -// HookResetPolicy 重设存储策略为已有文件 +// HookResetPolicy 重设存储策略为上下文已有文件 func HookResetPolicy(ctx context.Context, fs *FileSystem) error { originFile, ok := ctx.Value(fsctx.FileModelCtx).(model.File) if !ok { @@ -170,13 +170,12 @@ func GenericAfterUpdate(ctx context.Context, fs *FileSystem) error { return err } - // 尝试清空原有缩略图 + // 尝试清空原有缩略图并重新生成 go func() { if originFile.PicInfo != "" { _, _ = fs.Handler.Delete(ctx, []string{originFile.SourceName + conf.ThumbConfig.FileSuffix}) fs.GenerateThumbnail(ctx, &originFile) } - }() return nil diff --git a/pkg/filesystem/hooks_test.go b/pkg/filesystem/hooks_test.go index f2e3096..65b7cd1 100644 --- a/pkg/filesystem/hooks_test.go +++ b/pkg/filesystem/hooks_test.go @@ -5,10 +5,12 @@ import ( "errors" "github.com/DATA-DOG/go-sqlmock" model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/cache" "github.com/HFO4/cloudreve/pkg/filesystem/fsctx" "github.com/HFO4/cloudreve/pkg/filesystem/local" "github.com/jinzhu/gorm" "github.com/stretchr/testify/assert" + testMock "github.com/stretchr/testify/mock" "os" "testing" ) @@ -274,3 +276,204 @@ func TestHookValidateCapacity(t *testing.T) { asserts.Error(err) } } + +func TestHookResetPolicy(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + }} + + // 成功 + { + file := model.File{PolicyID: 2} + cache.Deletes([]string{"2"}, "policy_") + mock.ExpectQuery("SELECT(.+)policies(.+)"). + WillReturnRows(sqlmock.NewRows([]string{"id", "type"}).AddRow(2, "local")) + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, file) + err := HookResetPolicy(ctx, fs) + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } + + // 上下文文件不存在 + { + cache.Deletes([]string{"2"}, "policy_") + ctx := context.Background() + err := HookResetPolicy(ctx, fs) + asserts.Error(err) + } +} + +func TestHookChangeCapacity(t *testing.T) { + asserts := assert.New(t) + + // 容量增加 失败 + { + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + }} + + newFile := local.FileStream{Size: 10} + oldFile := model.File{Size: 9} + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, oldFile) + ctx = context.WithValue(ctx, fsctx.FileHeaderCtx, newFile) + err := HookChangeCapacity(ctx, fs) + asserts.Equal(ErrInsufficientCapacity, err) + } + + // 容量增加 成功 + { + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + Group: model.Group{MaxStorage: 1}, + }} + + newFile := local.FileStream{Size: 10} + oldFile := model.File{Size: 9} + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, oldFile) + ctx = context.WithValue(ctx, fsctx.FileHeaderCtx, newFile) + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)").WithArgs(1, 1).WillReturnResult(sqlmock.NewResult(1, 1)) + err := HookChangeCapacity(ctx, fs) + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + asserts.Equal(uint64(1), fs.User.Storage) + } + + // 容量减少 + { + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + Storage: 1, + }} + + newFile := local.FileStream{Size: 9} + oldFile := model.File{Size: 10} + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, oldFile) + ctx = context.WithValue(ctx, fsctx.FileHeaderCtx, newFile) + err := HookChangeCapacity(ctx, fs) + asserts.NoError(err) + asserts.Equal(uint64(0), fs.User.Storage) + } +} + +func TestHookCleanFileContent(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + }} + + ctx := context.WithValue(context.Background(), fsctx.SavePathCtx, "123/123") + handlerMock := FileHeaderMock{} + handlerMock.On("Put", testMock.Anything, testMock.Anything, "123/123").Return(errors.New("error")) + fs.Handler = handlerMock + err := HookCleanFileContent(ctx, fs) + asserts.Error(err) + handlerMock.AssertExpectations(t) +} + +func TestHookClearFileSize(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + }} + + // 成功 + { + ctx := context.WithValue( + context.Background(), + fsctx.FileModelCtx, + model.File{Model: gorm.Model{ID: 1}}, + ) + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)"). + WithArgs(0, sqlmock.AnyArg(), 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + err := HookClearFileSize(ctx, fs) + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } + + // 上下文对象不存在 + { + ctx := context.Background() + err := HookClearFileSize(ctx, fs) + asserts.Error(err) + } + +} + +func TestGenericAfterUpdate(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ID: 1}, + }} + + // 成功 是图像文件 + { + originFile := model.File{ + Model: gorm.Model{ID: 1}, + PicInfo: "1,1", + } + newFile := local.FileStream{Size: 10} + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile) + ctx = context.WithValue(ctx, fsctx.FileHeaderCtx, newFile) + + handlerMock := FileHeaderMock{} + handlerMock.On("Delete", testMock.Anything, []string{"._thumb"}).Return([]string{}, nil) + fs.Handler = handlerMock + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)"). + WithArgs(10, sqlmock.AnyArg(), 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + err := GenericAfterUpdate(ctx, fs) + + asserts.NoError(mock.ExpectationsWereMet()) + asserts.NoError(err) + } + + // 新文件上下文不存在 + { + originFile := model.File{ + Model: gorm.Model{ID: 1}, + PicInfo: "1,1", + } + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile) + err := GenericAfterUpdate(ctx, fs) + asserts.Error(err) + } + + // 原始文件上下文不存在 + { + newFile := local.FileStream{Size: 10} + ctx := context.WithValue(context.Background(), fsctx.FileHeaderCtx, newFile) + err := GenericAfterUpdate(ctx, fs) + asserts.Error(err) + } + + // 无法更新数据库容量 + // 成功 是图像文件 + { + originFile := model.File{ + Model: gorm.Model{ID: 1}, + PicInfo: "1,1", + } + newFile := local.FileStream{Size: 10} + ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, originFile) + ctx = context.WithValue(ctx, fsctx.FileHeaderCtx, newFile) + + mock.ExpectBegin() + mock.ExpectExec("UPDATE(.+)"). + WithArgs(10, sqlmock.AnyArg(), 1). + WillReturnError(errors.New("error")) + mock.ExpectRollback() + + err := GenericAfterUpdate(ctx, fs) + + asserts.NoError(mock.ExpectationsWereMet()) + asserts.Error(err) + } +} diff --git a/pkg/filesystem/image.go b/pkg/filesystem/image.go index 53522fc..2cce0eb 100644 --- a/pkg/filesystem/image.go +++ b/pkg/filesystem/image.go @@ -36,6 +36,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR } // GenerateThumbnail 尝试为本地策略文件生成缩略图并获取图像原始大小 +// TODO 失败时,如果之前还有图像信息,则清除 func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) { // 判断是否可以生成缩略图 if !IsInExtensionList(HandledExtension, file.Name) { diff --git a/pkg/filesystem/upload_test.go b/pkg/filesystem/upload_test.go index 4a462ca..b90a483 100644 --- a/pkg/filesystem/upload_test.go +++ b/pkg/filesystem/upload_test.go @@ -82,6 +82,35 @@ func TestFileSystem_Upload(t *testing.T) { err := fs.Upload(ctx, file) asserts.NoError(err) + // 正常,上下文已指定源文件 + testHandller = new(FileHeaderMock) + testHandller.On("Put", testMock.Anything, testMock.Anything, "123/123.txt").Return(nil) + fs = &FileSystem{ + Handler: testHandller, + User: &model.User{ + Model: gorm.Model{ + ID: 1, + }, + Policy: model.Policy{ + AutoRename: false, + DirNameRule: "{path}", + }, + }, + } + ctx, cancel = context.WithCancel(context.Background()) + c, _ = gin.CreateTestContext(httptest.NewRecorder()) + c.Request, _ = http.NewRequest("POST", "/", nil) + ctx = context.WithValue(ctx, fsctx.GinCtx, c) + ctx = context.WithValue(ctx, fsctx.FileModelCtx, model.File{SourceName: "123/123.txt"}) + cancel() + file = local.FileStream{ + Size: 5, + VirtualPath: "/", + Name: "1.txt", + } + err = fs.Upload(ctx, file) + asserts.NoError(err) + // BeforeUpload 返回错误 fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem) error { return errors.New("error")