diff --git a/pkg/filesystem/filesystem_test.go b/pkg/filesystem/filesystem_test.go index c1964ff..3a9a4bb 100644 --- a/pkg/filesystem/filesystem_test.go +++ b/pkg/filesystem/filesystem_test.go @@ -3,6 +3,7 @@ package filesystem import ( model "github.com/HFO4/cloudreve/models" "github.com/stretchr/testify/assert" + "testing" ) diff --git a/pkg/filesystem/hooks_test.go b/pkg/filesystem/hooks_test.go index b7df387..03156f4 100644 --- a/pkg/filesystem/hooks_test.go +++ b/pkg/filesystem/hooks_test.go @@ -2,8 +2,11 @@ package filesystem import ( "context" + "errors" + "github.com/DATA-DOG/go-sqlmock" model "github.com/HFO4/cloudreve/models" "github.com/HFO4/cloudreve/pkg/filesystem/local" + "github.com/jinzhu/gorm" "github.com/stretchr/testify/assert" "os" "testing" @@ -82,13 +85,65 @@ func TestGenericAfterUploadCanceled(t *testing.T) { asserts.NoError(err) } -//func TestGenericAfterUpload(t *testing.T) { -// asserts := assert.New(t) -// testObj := FileSystem{} -// ctx := context.WithValue(context.Background(),FileHeaderCtx,local.FileStream{ -// VirtualPath: "/我的文件", -// Name: "test.txt", -// }) -// -// -//} +func TestGenericAfterUpload(t *testing.T) { + asserts := assert.New(t) + fs := FileSystem{ + User: &model.User{ + Model: gorm.Model{ + ID: 1, + }, + }, + } + + ctx := context.WithValue(context.Background(), FileHeaderCtx, local.FileStream{ + VirtualPath: "/我的文件", + Name: "test.txt", + }) + ctx = context.WithValue(ctx, SavePathCtx, "") + + // 正常 + mock.ExpectQuery("SELECT(.+)folders(.+)").WillReturnRows( + mock.NewRows([]string{"name"}).AddRow("我的文件"), + ) + mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + err := GenericAfterUpload(ctx, &fs) + asserts.NoError(err) + asserts.NoError(mock.ExpectationsWereMet()) + + // 路径不存在 + mock.ExpectQuery("SELECT(.+)folders(.+)").WillReturnRows( + mock.NewRows([]string{"name"}), + ) + err = GenericAfterUpload(ctx, &fs) + asserts.Equal(ErrPathNotExist, err) + asserts.NoError(mock.ExpectationsWereMet()) + + // 文件已存在 + mock.ExpectQuery("SELECT(.+)folders(.+)").WillReturnRows( + mock.NewRows([]string{"name"}).AddRow("我的文件"), + ) + mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnRows( + mock.NewRows([]string{"name"}).AddRow("test.txt"), + ) + err = GenericAfterUpload(ctx, &fs) + asserts.Equal(ErrFileExisted, err) + asserts.NoError(mock.ExpectationsWereMet()) + + // 插入失败 + mock.ExpectQuery("SELECT(.+)folders(.+)").WillReturnRows( + mock.NewRows([]string{"name"}).AddRow("我的文件"), + ) + mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) + mock.ExpectBegin() + mock.ExpectExec("INSERT(.+)files(.+)").WillReturnError(errors.New("error")) + mock.ExpectRollback() + + err = GenericAfterUpload(ctx, &fs) + asserts.Equal(ErrInsertFileRecord, err) + asserts.NoError(mock.ExpectationsWereMet()) + +} diff --git a/pkg/filesystem/path_test.go b/pkg/filesystem/path_test.go new file mode 100644 index 0000000..8e83f41 --- /dev/null +++ b/pkg/filesystem/path_test.go @@ -0,0 +1,60 @@ +package filesystem + +import ( + "github.com/DATA-DOG/go-sqlmock" + model "github.com/HFO4/cloudreve/models" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestFileSystem_IsFileExist(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ + ID: 1, + }, + }} + + // 存在 + mock.ExpectQuery("SELECT(.+)").WithArgs(uint(1), "/s", "1.txt").WillReturnRows( + sqlmock.NewRows([]string{"Name"}).AddRow("s"), + ) + testResult := fs.IsFileExist("/s/1.txt") + asserts.True(testResult) + asserts.NoError(mock.ExpectationsWereMet()) + + // 不存在 + mock.ExpectQuery("SELECT(.+)").WithArgs(uint(1), "/ss/dfsd", "1.txt").WillReturnRows( + sqlmock.NewRows([]string{"Name"}), + ) + testResult = fs.IsFileExist("/ss/dfsd/1.txt") + asserts.False(testResult) + asserts.NoError(mock.ExpectationsWereMet()) +} + +func TestFileSystem_IsPathExist(t *testing.T) { + asserts := assert.New(t) + fs := &FileSystem{User: &model.User{ + Model: gorm.Model{ + ID: 1, + }, + }} + + // 存在 + mock.ExpectQuery("SELECT(.+)").WithArgs(uint(1), "/s/sda").WillReturnRows( + sqlmock.NewRows([]string{"name"}).AddRow("sda"), + ) + testResult, folder := fs.IsPathExist("/s/sda") + asserts.True(testResult) + asserts.Equal("sda", folder.Name) + asserts.NoError(mock.ExpectationsWereMet()) + + // 不存在 + mock.ExpectQuery("SELECT(.+)").WithArgs(uint(1), "/s/sda").WillReturnRows( + sqlmock.NewRows([]string{"name"}), + ) + testResult, _ = fs.IsPathExist("/s/sda") + asserts.False(testResult) + asserts.NoError(mock.ExpectationsWereMet()) +} diff --git a/pkg/filesystem/upload.go b/pkg/filesystem/upload.go index 134ad4e..98cfb03 100644 --- a/pkg/filesystem/upload.go +++ b/pkg/filesystem/upload.go @@ -2,6 +2,7 @@ package filesystem import ( "context" + "fmt" "github.com/HFO4/cloudreve/pkg/util" "github.com/gin-gonic/gin" "path/filepath" @@ -79,8 +80,10 @@ func (fs *FileSystem) CancelUpload(ctx context.Context, path string, file FileHe select { case <-ctx.Done(): // 客户端正常关闭,不执行操作 + fmt.Println("正常") case <-ginCtx.Request.Context().Done(): // 客户端取消了上传 + fmt.Println("取消") if fs.AfterUploadCanceled == nil { return } diff --git a/pkg/filesystem/upload_test.go b/pkg/filesystem/upload_test.go new file mode 100644 index 0000000..8d47758 --- /dev/null +++ b/pkg/filesystem/upload_test.go @@ -0,0 +1,80 @@ +package filesystem + +import ( + "context" + "errors" + model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/filesystem/local" + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + testMock "github.com/stretchr/testify/mock" + "io" + "net/http" + "net/http/httptest" + "testing" +) + +type FileHeaderMock struct { + testMock.Mock +} + +func (m FileHeaderMock) Put(ctx context.Context, file io.ReadCloser, dst string) error { + args := m.Called(ctx, file, dst) + return args.Error(0) +} + +func (m FileHeaderMock) Delete(ctx context.Context, files []string) ([]string, error) { + args := m.Called(ctx, files) + return args.Get(0).([]string), args.Error(1) +} + +func TestFileSystem_Upload(t *testing.T) { + asserts := assert.New(t) + + // 正常 + testHandller := new(FileHeaderMock) + testHandller.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).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, GinCtx, c) + cancel() + file := local.FileStream{ + Size: 5, + VirtualPath: "/", + Name: "1.txt", + } + err := fs.Upload(ctx, file) + asserts.NoError(err) + + // BeforeUpload 返回错误 + fs.BeforeUpload = func(ctx context.Context, fs *FileSystem) error { + return errors.New("error") + } + err = fs.Upload(ctx, file) + asserts.Error(err) + fs.BeforeUpload = nil + testHandller.AssertExpectations(t) + + // 上传文件失败 + testHandller2 := new(FileHeaderMock) + testHandller2.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(errors.New("error")) + fs.Handler = testHandller2 + err = fs.Upload(ctx, file) + asserts.Error(err) + testHandller2.AssertExpectations(t) + +} diff --git a/routers/controllers/file.go b/routers/controllers/file.go index 422b0d1..132ca0e 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -7,34 +7,10 @@ import ( "github.com/HFO4/cloudreve/pkg/filesystem/local" "github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/util" - "github.com/HFO4/cloudreve/service/file" "github.com/gin-gonic/gin" "strconv" ) -// FileUpload 本地策略文件上传 -func FileUpload(c *gin.Context) { - - // 非本地策略时拒绝上传 - if user, ok := c.Get("user"); ok && user.(*model.User).Policy.Type != "local" { - c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前上传策略无法使用", nil)) - return - } - - // 建立上下文 - ctx, cancel := context.WithCancel(context.Background()) - - var service file.UploadService - defer cancel() - - if err := c.ShouldBind(&service); err == nil { - res := service.Upload(ctx, c) - c.JSON(200, res) - } else { - c.JSON(200, ErrorResponse(err)) - } -} - // FileUploadStream 本地策略流式上传 func FileUploadStream(c *gin.Context) { // 创建上下文 diff --git a/routers/router.go b/routers/router.go index f28946c..353f278 100644 --- a/routers/router.go +++ b/routers/router.go @@ -49,10 +49,8 @@ func InitRouter() *gin.Engine { // 文件 file := auth.Group("File") { - // 小文件上传 - file.POST("Upload", controllers.FileUpload) - // 小文件上传 - file.POST("UploadStream", controllers.FileUploadStream) + // 文件上传 + file.POST("Upload", controllers.FileUploadStream) } } diff --git a/service/file/upload.go b/service/file/upload.go deleted file mode 100644 index 053dfe3..0000000 --- a/service/file/upload.go +++ /dev/null @@ -1,55 +0,0 @@ -package file - -import ( - "context" - model "github.com/HFO4/cloudreve/models" - "github.com/HFO4/cloudreve/pkg/filesystem" - "github.com/HFO4/cloudreve/pkg/filesystem/local" - "github.com/HFO4/cloudreve/pkg/serializer" - "github.com/gin-gonic/gin" - "mime/multipart" -) - -// UploadService 本地策略文件上传服务 -type UploadService struct { - Name string `form:"name" binding:"required,lte=255"` - Path string `form:"path" binding:"lte=65536"` - File *multipart.FileHeader `form:"file" binding:"required"` -} - -// Upload 处理本地策略小文件上传 -func (service *UploadService) Upload(ctx context.Context, c *gin.Context) serializer.Response { - // TODO 检查文件大小是否小于分片最大大小 - file, err := service.File.Open() - if err != nil { - return serializer.Err(serializer.CodeIOFailed, "无法打开上传数据", err) - } - - fileData := local.FileData{ - MIMEType: service.File.Header.Get("Content-Type"), - File: file, - Size: uint64(service.File.Size), - Name: service.Name, - } - user, _ := c.Get("user") - - // 创建文件系统 - fs, err := filesystem.NewFileSystem(user.(*model.User)) - if err != nil { - return serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err) - } - - // 给文件系统分配钩子 - fs.BeforeUpload = filesystem.GenericBeforeUpload - - // 执行上传 - err = fs.Upload(ctx, fileData) - if err != nil { - return serializer.Err(serializer.CodeUploadFailed, err.Error(), err) - } - - return serializer.Response{ - Code: 0, - Msg: "Pong", - } -}