diff --git a/models/defaults.go b/models/defaults.go index ecb8428..16a798b 100644 --- a/models/defaults.go +++ b/models/defaults.go @@ -31,7 +31,6 @@ var defaultSettings = []Setting{ {Name: "download_timeout", Value: `60`, Type: "timeout"}, {Name: "preview_timeout", Value: `60`, Type: "timeout"}, {Name: "doc_preview_timeout", Value: `60`, Type: "timeout"}, - {Name: "upload_credential_timeout", Value: `1800`, Type: "timeout"}, {Name: "upload_session_timeout", Value: `86400`, Type: "timeout"}, {Name: "slave_api_timeout", Value: `60`, Type: "timeout"}, {Name: "slave_node_retry", Value: `3`, Type: "slave"}, diff --git a/pkg/conf/conf.go b/pkg/conf/conf.go index 4988ef3..35ed8b6 100644 --- a/pkg/conf/conf.go +++ b/pkg/conf/conf.go @@ -65,6 +65,7 @@ type cors struct { var cfg *ini.File const defaultConf = `[System] +Debug = false Mode = master Listen = :5212 SessionSecret = {SessionSecret} diff --git a/pkg/filesystem/chunk/chunk_test.go b/pkg/filesystem/chunk/chunk_test.go index c6af9d9..4bdcd06 100644 --- a/pkg/filesystem/chunk/chunk_test.go +++ b/pkg/filesystem/chunk/chunk_test.go @@ -245,6 +245,6 @@ func TestChunkGroup_Process(t *testing.T) { return errors.New("error") })) a.False(c.Next()) - a.Equal(1, count) + a.Equal(4, count) } } diff --git a/pkg/filesystem/driver/local/handler_test.go b/pkg/filesystem/driver/local/handler_test.go index 9ce5fe7..9167e82 100644 --- a/pkg/filesystem/driver/local/handler_test.go +++ b/pkg/filesystem/driver/local/handler_test.go @@ -81,12 +81,12 @@ func TestHandler_Delete(t *testing.T) { asserts := assert.New(t) handler := Driver{} ctx := context.Background() - filePath := util.RelativePath("test.file") + filePath := util.RelativePath("TestHandler_Delete.file") file, err := os.Create(filePath) asserts.NoError(err) _ = file.Close() - list, err := handler.Delete(ctx, []string{"test.file"}) + list, err := handler.Delete(ctx, []string{"TestHandler_Delete.file"}) asserts.Equal([]string{}, list) asserts.NoError(err) @@ -94,7 +94,7 @@ func TestHandler_Delete(t *testing.T) { _ = file.Close() file, _ = os.OpenFile(filePath, os.O_RDWR, os.FileMode(0)) asserts.NoError(err) - list, err = handler.Delete(ctx, []string{"test.file", "test.notexist"}) + list, err = handler.Delete(ctx, []string{"TestHandler_Delete.file", "test.notexist"}) file.Close() asserts.Equal([]string{}, list) asserts.NoError(err) @@ -105,7 +105,7 @@ func TestHandler_Delete(t *testing.T) { file, err = os.Create(filePath) asserts.NoError(err) - list, err = handler.Delete(ctx, []string{"test.file"}) + list, err = handler.Delete(ctx, []string{"TestHandler_Delete.file"}) _ = file.Close() asserts.Equal([]string{}, list) asserts.NoError(err) diff --git a/pkg/filesystem/driver/oss/handler.go b/pkg/filesystem/driver/oss/handler.go index c7eadc2..b0b55d2 100644 --- a/pkg/filesystem/driver/oss/handler.go +++ b/pkg/filesystem/driver/oss/handler.go @@ -229,7 +229,7 @@ func (handler *Driver) Put(ctx context.Context, file fsctx.FileHeader) error { fileInfo := file.Info() // 凭证有效期 - credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600) + credentialTTL := model.GetIntSetting("upload_session_timeout", 3600) // 是否允许覆盖 overwrite := fileInfo.Mode&fsctx.Overwrite == fsctx.Overwrite diff --git a/pkg/filesystem/driver/qiniu/handler.go b/pkg/filesystem/driver/qiniu/handler.go index a47b8da..22a97d0 100644 --- a/pkg/filesystem/driver/qiniu/handler.go +++ b/pkg/filesystem/driver/qiniu/handler.go @@ -156,7 +156,7 @@ func (handler *Driver) Put(ctx context.Context, file fsctx.FileHeader) error { defer file.Close() // 凭证有效期 - credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600) + credentialTTL := model.GetIntSetting("upload_session_timeout", 3600) // 生成上传策略 fileInfo := file.Info() diff --git a/pkg/filesystem/image_test.go b/pkg/filesystem/image_test.go index 42c7f45..cc33b19 100644 --- a/pkg/filesystem/image_test.go +++ b/pkg/filesystem/image_test.go @@ -1,38 +1,45 @@ package filesystem import ( + "context" + "errors" + model "github.com/cloudreve/Cloudreve/v3/models" + "github.com/cloudreve/Cloudreve/v3/pkg/cache" + "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response" + "github.com/cloudreve/Cloudreve/v3/pkg/request" + testMock "github.com/stretchr/testify/mock" "testing" "github.com/stretchr/testify/assert" ) -//func TestFileSystem_GetThumb(t *testing.T) { -// asserts := assert.New(t) -// fs := &FileSystem{User: &model.User{}} -// -// // 非图像文件 -// { -// fs.SetTargetFile(&[]model.File{{}}) -// _, err := fs.GetThumb(context.Background(), 1) -// asserts.Equal(err, ErrObjectNotExist) -// } -// -// // 成功 -// { -// cache.Set("setting_thumb_width", "10", 0) -// cache.Set("setting_thumb_height", "10", 0) -// cache.Set("setting_preview_timeout", "50", 0) -// testHandller2 := new(FileHeaderMock) -// testHandller2.On("Thumb", testMock.Anything, "").Return(&response.ContentResponse{}, nil) -// fs.CleanTargets() -// fs.SetTargetFile(&[]model.File{{PicInfo: "1,1", Policy: model.Policy{Type: "mock"}}}) -// fs.FileTarget[0].Policy.ID = 1 -// fs.Handler = testHandller2 -// res, err := fs.GetThumb(context.Background(), 1) -// asserts.NoError(err) -// asserts.EqualValues(50, res.MaxAge) -// } -//} +func TestFileSystem_GetThumb(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{}} + + // 非图像文件 + { + fs.SetTargetFile(&[]model.File{{}}) + _, err := fs.GetThumb(context.Background(), 1) + asserts.Equal(err, ErrObjectNotExist) + } + + // 成功 + { + cache.Set("setting_thumb_width", "10", 0) + cache.Set("setting_thumb_height", "10", 0) + cache.Set("setting_preview_timeout", "50", 0) + testHandller2 := new(FileHeaderMock) + testHandller2.On("Thumb", testMock.Anything, "").Return(&response.ContentResponse{}, nil) + fs.CleanTargets() + fs.SetTargetFile(&[]model.File{{PicInfo: "1,1", Policy: model.Policy{Type: "mock"}}}) + fs.FileTarget[0].Policy.ID = 1 + fs.Handler = testHandller2 + res, err := fs.GetThumb(context.Background(), 1) + asserts.NoError(err) + asserts.EqualValues(50, res.MaxAge) + } +} func TestFileSystem_ThumbWorker(t *testing.T) { asserts := assert.New(t) @@ -42,3 +49,22 @@ func TestFileSystem_ThumbWorker(t *testing.T) { getThumbWorker().releaseWorker() }) } + +func TestFileSystem_GenerateThumbnail(t *testing.T) { + fs := &FileSystem{User: &model.User{}} + + // 无法生成缩略图 + { + fs.SetTargetFile(&[]model.File{{}}) + fs.GenerateThumbnail(context.Background(), &model.File{}) + } + + // 无法获取文件数据 + { + testHandller := new(FileHeaderMock) + testHandller.On("Get", testMock.Anything, "").Return(request.NopRSCloser{}, errors.New("error")) + fs.Handler = testHandller + fs.GenerateThumbnail(context.Background(), &model.File{Name: "test.png"}) + testHandller.AssertExpectations(t) + } +} diff --git a/pkg/filesystem/manage_test.go b/pkg/filesystem/manage_test.go index 7357371..da91691 100644 --- a/pkg/filesystem/manage_test.go +++ b/pkg/filesystem/manage_test.go @@ -3,6 +3,8 @@ package filesystem import ( "context" "errors" + "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response" + testMock "github.com/stretchr/testify/mock" "os" "testing" @@ -17,51 +19,51 @@ import ( "github.com/stretchr/testify/assert" ) -//func TestFileSystem_ListPhysical(t *testing.T) { -// asserts := assert.New(t) -// fs := &FileSystem{ -// User: &model.User{ -// Model: gorm.Model{ -// ID: 1, -// }, -// }, -// Policy: &model.Policy{Type: "mock"}, -// } -// ctx := context.Background() -// -// // 未知存储策略 -// { -// fs.Policy.Type = "unknown" -// res, err := fs.ListPhysical(ctx, "/") -// asserts.Equal(ErrUnknownPolicyType, err) -// asserts.Empty(res) -// fs.Policy.Type = "mock" -// } -// -// // 无法列取目录 -// { -// testHandler := new(FileHeaderMock) -// testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return([]response.Object{}, errors.New("error")) -// fs.Handler = testHandler -// res, err := fs.ListPhysical(ctx, "/") -// asserts.EqualError(err, "error") -// asserts.Empty(res) -// } -// -// // 成功 -// { -// testHandler := new(FileHeaderMock) -// testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return( -// []response.Object{{IsDir: true, Name: "1"}, {IsDir: false, Name: "2"}}, -// nil, -// ) -// fs.Handler = testHandler -// res, err := fs.ListPhysical(ctx, "/") -// asserts.NoError(err) -// asserts.Len(res, 1) -// asserts.Equal("1", res[0].Name) -// } -//} +func TestFileSystem_ListPhysical(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{ + User: &model.User{ + Model: gorm.Model{ + ID: 1, + }, + }, + Policy: &model.Policy{Type: "mock"}, + } + ctx := context.Background() + + // 未知存储策略 + { + fs.Policy.Type = "unknown" + res, err := fs.ListPhysical(ctx, "/") + asserts.Equal(ErrUnknownPolicyType, err) + asserts.Empty(res) + fs.Policy.Type = "mock" + } + + // 无法列取目录 + { + testHandler := new(FileHeaderMock) + testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return([]response.Object{}, errors.New("error")) + fs.Handler = testHandler + res, err := fs.ListPhysical(ctx, "/") + asserts.EqualError(err, "error") + asserts.Empty(res) + } + + // 成功 + { + testHandler := new(FileHeaderMock) + testHandler.On("List", testMock.Anything, "/", testMock.Anything).Return( + []response.Object{{IsDir: true, Name: "1"}, {IsDir: false, Name: "2"}}, + nil, + ) + fs.Handler = testHandler + res, err := fs.ListPhysical(ctx, "/") + asserts.NoError(err) + asserts.Len(res, 1) + asserts.Equal("1", res[0].Name) + } +} func TestFileSystem_List(t *testing.T) { asserts := assert.New(t) @@ -294,12 +296,12 @@ func TestFileSystem_ListDeleteDirs(t *testing.T) { { mock.ExpectQuery("SELECT(.+)"). WillReturnRows( - sqlmock.NewRows([]string{"id"}). - AddRow(1). - AddRow(2). - AddRow(3), + sqlmock.NewRows([]string{"id", "parent_id"}). + AddRow(1, 0). + AddRow(2, 0). + AddRow(3, 0), ) - mock.ExpectQuery("SELECT(.+)"). + mock.ExpectQuery("SELECT(.+)files(.+)"). WithArgs(1, 2, 3). WillReturnRows( sqlmock.NewRows([]string{"id", "name"}). @@ -314,21 +316,47 @@ func TestFileSystem_ListDeleteDirs(t *testing.T) { asserts.NoError(mock.ExpectationsWereMet()) } + // 成功,忽略根目录 + { + mock.ExpectQuery("SELECT(.+)"). + WillReturnRows( + sqlmock.NewRows([]string{"id", "parent_id"}). + AddRow(1, 0). + AddRow(2, nil). + AddRow(3, 0), + ) + mock.ExpectQuery("SELECT(.+)files(.+)"). + WithArgs(1, 3). + WillReturnRows( + sqlmock.NewRows([]string{"id", "name"}). + AddRow(4, "1.txt"). + AddRow(5, "2.txt"). + AddRow(6, "3.txt"), + ) + fs.CleanTargets() + err := fs.ListDeleteDirs(context.Background(), []uint{1}) + asserts.NoError(err) + asserts.Len(fs.FileTarget, 3) + asserts.Len(fs.DirTarget, 2) + asserts.NoError(mock.ExpectationsWereMet()) + } + // 检索文件发生错误 { mock.ExpectQuery("SELECT(.+)"). WillReturnRows( - sqlmock.NewRows([]string{"id"}). - AddRow(1). - AddRow(2). - AddRow(3), + sqlmock.NewRows([]string{"id", "parent_id"}). + AddRow(1, 0). + AddRow(2, 0). + AddRow(3, 0), ) mock.ExpectQuery("SELECT(.+)"). WithArgs(1, 2, 3). WillReturnError(errors.New("error")) + fs.CleanTargets() err := fs.ListDeleteDirs(context.Background(), []uint{1}) asserts.Error(err) - asserts.Len(fs.DirTarget, 6) + asserts.Len(fs.DirTarget, 3) asserts.NoError(mock.ExpectationsWereMet()) } // 检索目录发生错误 @@ -347,7 +375,7 @@ func TestFileSystem_Delete(t *testing.T) { cache.Set("pack_size_1", uint64(0), 0) fs := &FileSystem{User: &model.User{ Model: gorm.Model{ - ID: 1, + ID: 0, }, Storage: 3, Group: model.Group{MaxStorage: 3}, @@ -359,10 +387,10 @@ func TestFileSystem_Delete(t *testing.T) { fs.CleanTargets() mock.ExpectQuery("SELECT(.+)"). WillReturnRows( - sqlmock.NewRows([]string{"id"}). - AddRow(1). - AddRow(2). - AddRow(3), + sqlmock.NewRows([]string{"id", "parent_id"}). + AddRow(1, 0). + AddRow(2, 0). + AddRow(3, 0), ) mock.ExpectQuery("SELECT(.+)"). WithArgs(1, 2, 3). @@ -378,18 +406,16 @@ func TestFileSystem_Delete(t *testing.T) { // 删除文件记录 mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). - WillReturnResult(sqlmock.NewResult(0, 3)) + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectExec("DELETE(.+)"). + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectExec("UPDATE(.+)users(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // 删除对应分享 mock.ExpectBegin() mock.ExpectExec("UPDATE(.+)shares"). WillReturnResult(sqlmock.NewResult(0, 3)) mock.ExpectCommit() - // 归还容量 - mock.ExpectBegin() - mock.ExpectExec("UPDATE(.+)"). - WillReturnResult(sqlmock.NewResult(0, 3)) - mock.ExpectCommit() // 删除目录 mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). @@ -405,7 +431,6 @@ func TestFileSystem_Delete(t *testing.T) { fs.DirTarget = []model.Folder{} err := fs.Delete(ctx, []uint{1}, []uint{1}, true) asserts.NoError(err) - asserts.Equal(uint64(0), fs.User.Storage) } //全部成功 { @@ -417,10 +442,10 @@ func TestFileSystem_Delete(t *testing.T) { asserts.NoError(err) mock.ExpectQuery("SELECT(.+)"). WillReturnRows( - sqlmock.NewRows([]string{"id"}). - AddRow(1). - AddRow(2). - AddRow(3), + sqlmock.NewRows([]string{"id", "parent_id"}). + AddRow(1, 0). + AddRow(2, 0). + AddRow(3, 0), ) mock.ExpectQuery("SELECT(.+)"). WithArgs(1, 2, 3). @@ -436,18 +461,16 @@ func TestFileSystem_Delete(t *testing.T) { // 删除文件记录 mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). - WillReturnResult(sqlmock.NewResult(0, 3)) + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectExec("DELETE(.+)"). + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectExec("UPDATE(.+)users(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // 删除对应分享 mock.ExpectBegin() mock.ExpectExec("UPDATE(.+)shares"). WillReturnResult(sqlmock.NewResult(0, 3)) mock.ExpectCommit() - // 归还容量 - mock.ExpectBegin() - mock.ExpectExec("UPDATE(.+)"). - WillReturnResult(sqlmock.NewResult(0, 3)) - mock.ExpectCommit() // 删除目录 mock.ExpectBegin() mock.ExpectExec("DELETE(.+)"). @@ -463,7 +486,6 @@ func TestFileSystem_Delete(t *testing.T) { fs.DirTarget = []model.Folder{} err = fs.Delete(ctx, []uint{1}, []uint{1}, false) asserts.NoError(err) - asserts.Equal(uint64(0), fs.User.Storage) } } @@ -571,7 +593,9 @@ func TestFileSystem_Rename(t *testing.T) { Model: gorm.Model{ ID: 1, }, - }} + }, + Policy: &model.Policy{}, + } ctx := context.Background() // 重命名文件 成功 @@ -681,7 +705,7 @@ func TestFileSystem_Rename(t *testing.T) { // 新名字是文件,扩展名不合法 { - fs.User.Policy.OptionsSerialized.FileType = []string{"txt"} + fs.Policy.OptionsSerialized.FileType = []string{"txt"} err := fs.Rename(ctx, []uint{}, []uint{10}, "1.jpg") asserts.Error(err) asserts.Equal(ErrIllegalObjectName, err) @@ -689,7 +713,7 @@ func TestFileSystem_Rename(t *testing.T) { // 新名字是目录,不应该检测扩展名 { - fs.User.Policy.OptionsSerialized.FileType = []string{"txt"} + fs.Policy.OptionsSerialized.FileType = []string{"txt"} mock.ExpectQuery("SELECT(.+)folders(.+)"). WithArgs(10, 1). WillReturnRows(sqlmock.NewRows([]string{"id", "name"})) diff --git a/pkg/filesystem/upload_test.go b/pkg/filesystem/upload_test.go index 1f1b963..30f24cc 100644 --- a/pkg/filesystem/upload_test.go +++ b/pkg/filesystem/upload_test.go @@ -2,11 +2,23 @@ package filesystem import ( "context" + "errors" + "github.com/DATA-DOG/go-sqlmock" + model "github.com/cloudreve/Cloudreve/v3/models" + "github.com/cloudreve/Cloudreve/v3/pkg/cache" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response" "github.com/cloudreve/Cloudreve/v3/pkg/serializer" + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" testMock "github.com/stretchr/testify/mock" + "io/ioutil" + "net/http" + "net/http/httptest" "net/url" + "strings" + "testing" ) type FileHeaderMock struct { @@ -53,177 +65,200 @@ func (m FileHeaderMock) Source(ctx context.Context, path string, url url.URL, ex return args.Get(0).(string), args.Error(1) } -//func TestFileSystem_Upload(t *testing.T) { -// asserts := assert.New(t) -// -// // 正常 -// testHandler := new(FileHeaderMock) -// testHandler.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil) -// fs := &FileSystem{ -// Handler: testHandler, -// 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) -// cancel() -// file := fsctx.FileStream{ -// Size: 5, -// VirtualPath: "/", -// Name: "1.txt", -// } -// err := fs.Upload(ctx, file) -// asserts.NoError(err) -// -// // 正常,上下文已指定源文件 -// testHandler = new(FileHeaderMock) -// testHandler.On("Put", testMock.Anything, testMock.Anything, "123/123.txt").Return(nil) -// fs = &FileSystem{ -// Handler: testHandler, -// 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 = fsctx.FileStream{ -// Size: 5, -// VirtualPath: "/", -// Name: "1.txt", -// File: ioutil.NopCloser(strings.NewReader("")), -// } -// err = fs.Upload(ctx, file) -// asserts.NoError(err) -// -// // BeforeUpload 返回错误 -// fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem) error { -// return errors.New("error") -// }) -// err = fs.Upload(ctx, file) -// asserts.Error(err) -// fs.Hooks["BeforeUpload"] = nil -// testHandler.AssertExpectations(t) -// -// // 上传文件失败 -// testHandler2 := new(FileHeaderMock) -// testHandler2.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(errors.New("error")) -// fs.Handler = testHandler2 -// err = fs.Upload(ctx, file) -// asserts.Error(err) -// testHandler2.AssertExpectations(t) -// -// // AfterUpload失败 -// testHandler3 := new(FileHeaderMock) -// testHandler3.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil) -// fs.Handler = testHandler3 -// fs.Use("AfterUpload", func(ctx context.Context, fs *FileSystem) error { -// return errors.New("error") -// }) -// fs.Use("AfterValidateFailed", func(ctx context.Context, fs *FileSystem) error { -// return errors.New("error") -// }) -// err = fs.Upload(ctx, file) -// asserts.Error(err) -// testHandler2.AssertExpectations(t) -// -//} -// -//func TestFileSystem_GenerateSavePath_Anonymous(t *testing.T) { -// asserts := assert.New(t) -// fs := FileSystem{User: &model.User{}} -// ctx := context.WithValue( -// context.Background(), -// fsctx.UploadPolicyCtx, -// serializer.UploadPolicy{ -// SavePath: "{randomkey16}", -// AutoRename: false, -// }, -// ) -// -// savePath := fs.GenerateSavePath(ctx, fsctx.FileStream{ -// Name: "test.test", -// }) -// asserts.Len(savePath, 26) -// asserts.Contains(savePath, "test.test") -//} -// -//func TestFileSystem_GetUploadToken(t *testing.T) { -// asserts := assert.New(t) -// fs := FileSystem{User: &model.User{Model: gorm.Model{ID: 1}}} -// ctx := context.Background() -// -// // 成功 -// { -// cache.SetSettings(map[string]string{ -// "upload_credential_timeout": "10", -// "upload_session_timeout": "10", -// }, "setting_") -// testHandler := new(FileHeaderMock) -// testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything).Return(serializer.UploadCredential{Token: "test"}, nil) -// fs.Handler = testHandler -// res, err := fs.CreateUploadSession(ctx, "/", 10, "123") -// testHandler.AssertExpectations(t) -// asserts.NoError(err) -// asserts.Equal("test", res.Token) -// } -// -// // 无法获取上传凭证 -// { -// cache.SetSettings(map[string]string{ -// "upload_credential_timeout": "10", -// "upload_session_timeout": "10", -// }, "setting_") -// testHandler := new(FileHeaderMock) -// testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything).Return(serializer.UploadCredential{}, errors.New("error")) -// fs.Handler = testHandler -// _, err := fs.CreateUploadSession(ctx, "/", 10, "123") -// testHandler.AssertExpectations(t) -// asserts.Error(err) -// } -//} -// -//func TestFileSystem_UploadFromStream(t *testing.T) { -// asserts := assert.New(t) -// fs := FileSystem{User: &model.User{Model: gorm.Model{ID: 1}}} -// ctx := context.Background() -// -// err := fs.UploadFromStream(ctx, ioutil.NopCloser(strings.NewReader("123")), "/1.txt", 1) -// asserts.Error(err) -//} -// -//func TestFileSystem_UploadFromPath(t *testing.T) { -// asserts := assert.New(t) -// fs := FileSystem{User: &model.User{Policy: model.Policy{Type: "mock"}, Model: gorm.Model{ID: 1}}} -// ctx := context.Background() -// -// // 文件不存在 -// { -// err := fs.UploadFromPath(ctx, "test/not_exist", "/", true) -// asserts.Error(err) -// } -// -// // 文存在,上传失败 -// { -// err := fs.UploadFromPath(ctx, "tests/test.zip", "/", true) -// asserts.Error(err) -// } -//} +func TestFileSystem_Upload(t *testing.T) { + asserts := assert.New(t) + + // 正常 + testHandler := new(FileHeaderMock) + testHandler.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil) + fs := &FileSystem{ + Handler: testHandler, + 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) + cancel() + file := &fsctx.FileStream{ + Size: 5, + VirtualPath: "/", + Name: "1.txt", + } + err := fs.Upload(ctx, file) + asserts.NoError(err) + + // 正常,上下文已指定源文件 + testHandler = new(FileHeaderMock) + testHandler.On("Put", testMock.Anything, testMock.Anything).Return(nil) + fs = &FileSystem{ + Handler: testHandler, + 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 = &fsctx.FileStream{ + Size: 5, + VirtualPath: "/", + Name: "1.txt", + File: ioutil.NopCloser(strings.NewReader("")), + } + err = fs.Upload(ctx, file) + asserts.NoError(err) + + // BeforeUpload 返回错误 + fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { + return errors.New("error") + }) + err = fs.Upload(ctx, file) + asserts.Error(err) + fs.Hooks["BeforeUpload"] = nil + testHandler.AssertExpectations(t) + + // 上传文件失败 + testHandler2 := new(FileHeaderMock) + testHandler2.On("Put", testMock.Anything, testMock.Anything).Return(errors.New("error")) + fs.Handler = testHandler2 + err = fs.Upload(ctx, file) + asserts.Error(err) + testHandler2.AssertExpectations(t) + + // AfterUpload失败 + testHandler3 := new(FileHeaderMock) + testHandler3.On("Put", testMock.Anything, testMock.Anything).Return(nil) + fs.Handler = testHandler3 + fs.Use("AfterUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { + return errors.New("error") + }) + fs.Use("AfterValidateFailed", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { + return errors.New("error") + }) + err = fs.Upload(ctx, file) + asserts.Error(err) + testHandler2.AssertExpectations(t) + +} + +func TestFileSystem_GetUploadToken(t *testing.T) { + asserts := assert.New(t) + fs := FileSystem{ + User: &model.User{Model: gorm.Model{ID: 1}}, + Policy: &model.Policy{}, + } + ctx := context.Background() + + // 成功 + { + cache.SetSettings(map[string]string{ + "upload_session_timeout": "10", + }, "setting_") + testHandler := new(FileHeaderMock) + testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{Credential: "test"}, nil) + fs.Handler = testHandler + mock.ExpectQuery("SELECT(.+)"). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1)) + mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + res, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{ + Size: 0, + Name: "file", + VirtualPath: "/", + }) + asserts.NoError(mock.ExpectationsWereMet()) + testHandler.AssertExpectations(t) + asserts.NoError(err) + asserts.Equal("test", res.Credential) + } + + // 无法获取上传凭证 + { + cache.SetSettings(map[string]string{ + "upload_credential_timeout": "10", + "upload_session_timeout": "10", + }, "setting_") + testHandler := new(FileHeaderMock) + testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{}, errors.New("error")) + fs.Handler = testHandler + mock.ExpectQuery("SELECT(.+)"). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1)) + mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + _, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{ + Size: 0, + Name: "file", + VirtualPath: "/", + }) + asserts.NoError(mock.ExpectationsWereMet()) + testHandler.AssertExpectations(t) + asserts.Error(err) + } +} + +func TestFileSystem_UploadFromStream(t *testing.T) { + asserts := assert.New(t) + fs := FileSystem{ + User: &model.User{ + Model: gorm.Model{ID: 1}, + Policy: model.Policy{Type: "mock"}, + }, + Policy: &model.Policy{Type: "mock"}, + } + ctx := context.Background() + + err := fs.UploadFromStream(ctx, &fsctx.FileStream{ + File: ioutil.NopCloser(strings.NewReader("123")), + }, true) + asserts.Error(err) +} + +func TestFileSystem_UploadFromPath(t *testing.T) { + asserts := assert.New(t) + fs := FileSystem{ + User: &model.User{ + Model: gorm.Model{ID: 1}, + Policy: model.Policy{Type: "mock"}, + }, + Policy: &model.Policy{Type: "mock"}, + } + ctx := context.Background() + + // 文件不存在 + { + err := fs.UploadFromPath(ctx, "test/not_exist", "/", fsctx.Overwrite) + asserts.Error(err) + } + + // 文存在,上传失败 + { + err := fs.UploadFromPath(ctx, "tests/test.zip", "/", fsctx.Overwrite) + asserts.Error(err) + } +} diff --git a/pkg/filesystem/validator_test.go b/pkg/filesystem/validator_test.go index 8a39ae2..8f685f2 100644 --- a/pkg/filesystem/validator_test.go +++ b/pkg/filesystem/validator_test.go @@ -68,10 +68,9 @@ func TestFileSystem_ValidateFileSize(t *testing.T) { asserts := assert.New(t) ctx := context.Background() fs := FileSystem{ - User: &model.User{ - Policy: model.Policy{ - MaxSize: 10, - }, + User: &model.User{}, + Policy: &model.Policy{ + MaxSize: 10, }, } @@ -80,7 +79,7 @@ func TestFileSystem_ValidateFileSize(t *testing.T) { asserts.False(fs.ValidateFileSize(ctx, 11)) // 无限制 - fs.User.Policy.MaxSize = 0 + fs.Policy.MaxSize = 0 asserts.True(fs.ValidateFileSize(ctx, 11)) } @@ -88,11 +87,10 @@ func TestFileSystem_ValidateExtension(t *testing.T) { asserts := assert.New(t) ctx := context.Background() fs := FileSystem{ - User: &model.User{ - Policy: model.Policy{ - OptionsSerialized: model.PolicyOption{ - FileType: nil, - }, + User: &model.User{}, + Policy: &model.Policy{ + OptionsSerialized: model.PolicyOption{ + FileType: nil, }, }, } @@ -100,11 +98,11 @@ func TestFileSystem_ValidateExtension(t *testing.T) { asserts.True(fs.ValidateExtension(ctx, "1")) asserts.True(fs.ValidateExtension(ctx, "1.txt")) - fs.User.Policy.OptionsSerialized.FileType = []string{} + fs.Policy.OptionsSerialized.FileType = []string{} asserts.True(fs.ValidateExtension(ctx, "1")) asserts.True(fs.ValidateExtension(ctx, "1.txt")) - fs.User.Policy.OptionsSerialized.FileType = []string{"txt", "jpg"} + fs.Policy.OptionsSerialized.FileType = []string{"txt", "jpg"} asserts.False(fs.ValidateExtension(ctx, "1")) asserts.False(fs.ValidateExtension(ctx, "1.jpg.png")) asserts.True(fs.ValidateExtension(ctx, "1.txt"))