github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/filesystem/upload_test.go (about) 1 package filesystem 2 3 import ( 4 "context" 5 "errors" 6 "github.com/DATA-DOG/go-sqlmock" 7 model "github.com/cloudreve/Cloudreve/v3/models" 8 "github.com/cloudreve/Cloudreve/v3/pkg/cache" 9 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" 10 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response" 11 "github.com/cloudreve/Cloudreve/v3/pkg/serializer" 12 "github.com/gin-gonic/gin" 13 "github.com/jinzhu/gorm" 14 "github.com/stretchr/testify/assert" 15 testMock "github.com/stretchr/testify/mock" 16 "io/ioutil" 17 "net/http" 18 "net/http/httptest" 19 "strings" 20 "testing" 21 ) 22 23 type FileHeaderMock struct { 24 testMock.Mock 25 } 26 27 func (m FileHeaderMock) Put(ctx context.Context, file fsctx.FileHeader) error { 28 args := m.Called(ctx, file) 29 return args.Error(0) 30 } 31 32 func (m FileHeaderMock) Token(ctx context.Context, ttl int64, uploadSession *serializer.UploadSession, file fsctx.FileHeader) (*serializer.UploadCredential, error) { 33 args := m.Called(ctx, ttl, uploadSession, file) 34 return args.Get(0).(*serializer.UploadCredential), args.Error(1) 35 } 36 37 func (m FileHeaderMock) CancelToken(ctx context.Context, uploadSession *serializer.UploadSession) error { 38 args := m.Called(ctx, uploadSession) 39 return args.Error(0) 40 } 41 42 func (m FileHeaderMock) List(ctx context.Context, path string, recursive bool) ([]response.Object, error) { 43 args := m.Called(ctx, path, recursive) 44 return args.Get(0).([]response.Object), args.Error(1) 45 } 46 47 func (m FileHeaderMock) Get(ctx context.Context, path string) (response.RSCloser, error) { 48 args := m.Called(ctx, path) 49 return args.Get(0).(response.RSCloser), args.Error(1) 50 } 51 52 func (m FileHeaderMock) Delete(ctx context.Context, files []string) ([]string, error) { 53 args := m.Called(ctx, files) 54 return args.Get(0).([]string), args.Error(1) 55 } 56 57 func (m FileHeaderMock) Thumb(ctx context.Context, files *model.File) (*response.ContentResponse, error) { 58 args := m.Called(ctx, files) 59 return args.Get(0).(*response.ContentResponse), args.Error(1) 60 } 61 62 func (m FileHeaderMock) Source(ctx context.Context, path string, expires int64, isDownload bool, speed int) (string, error) { 63 args := m.Called(ctx, path, expires, isDownload, speed) 64 return args.Get(0).(string), args.Error(1) 65 } 66 67 func TestFileSystem_Upload(t *testing.T) { 68 asserts := assert.New(t) 69 70 // 正常 71 testHandler := new(FileHeaderMock) 72 testHandler.On("Put", testMock.Anything, testMock.Anything, testMock.Anything).Return(nil) 73 fs := &FileSystem{ 74 Handler: testHandler, 75 User: &model.User{ 76 Model: gorm.Model{ 77 ID: 1, 78 }, 79 }, 80 Policy: &model.Policy{ 81 AutoRename: false, 82 DirNameRule: "{path}", 83 }, 84 } 85 ctx, cancel := context.WithCancel(context.Background()) 86 c, _ := gin.CreateTestContext(httptest.NewRecorder()) 87 c.Request, _ = http.NewRequest("POST", "/", nil) 88 ctx = context.WithValue(ctx, fsctx.GinCtx, c) 89 cancel() 90 file := &fsctx.FileStream{ 91 Size: 5, 92 VirtualPath: "/", 93 Name: "1.txt", 94 } 95 err := fs.Upload(ctx, file) 96 asserts.NoError(err) 97 98 // 正常,上下文已指定源文件 99 testHandler = new(FileHeaderMock) 100 testHandler.On("Put", testMock.Anything, testMock.Anything).Return(nil) 101 fs = &FileSystem{ 102 Handler: testHandler, 103 User: &model.User{ 104 Model: gorm.Model{ 105 ID: 1, 106 }, 107 }, 108 Policy: &model.Policy{ 109 AutoRename: false, 110 DirNameRule: "{path}", 111 }, 112 } 113 ctx, cancel = context.WithCancel(context.Background()) 114 c, _ = gin.CreateTestContext(httptest.NewRecorder()) 115 c.Request, _ = http.NewRequest("POST", "/", nil) 116 ctx = context.WithValue(ctx, fsctx.GinCtx, c) 117 ctx = context.WithValue(ctx, fsctx.FileModelCtx, model.File{SourceName: "123/123.txt"}) 118 cancel() 119 file = &fsctx.FileStream{ 120 Size: 5, 121 VirtualPath: "/", 122 Name: "1.txt", 123 File: ioutil.NopCloser(strings.NewReader("")), 124 } 125 err = fs.Upload(ctx, file) 126 asserts.NoError(err) 127 128 // BeforeUpload 返回错误 129 fs.Use("BeforeUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { 130 return errors.New("error") 131 }) 132 err = fs.Upload(ctx, file) 133 asserts.Error(err) 134 fs.Hooks["BeforeUpload"] = nil 135 testHandler.AssertExpectations(t) 136 137 // 上传文件失败 138 testHandler2 := new(FileHeaderMock) 139 testHandler2.On("Put", testMock.Anything, testMock.Anything).Return(errors.New("error")) 140 fs.Handler = testHandler2 141 err = fs.Upload(ctx, file) 142 asserts.Error(err) 143 testHandler2.AssertExpectations(t) 144 145 // AfterUpload失败 146 testHandler3 := new(FileHeaderMock) 147 testHandler3.On("Put", testMock.Anything, testMock.Anything).Return(nil) 148 fs.Handler = testHandler3 149 fs.Use("AfterUpload", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { 150 return errors.New("error") 151 }) 152 fs.Use("AfterValidateFailed", func(ctx context.Context, fs *FileSystem, file fsctx.FileHeader) error { 153 return errors.New("error") 154 }) 155 err = fs.Upload(ctx, file) 156 asserts.Error(err) 157 testHandler2.AssertExpectations(t) 158 159 } 160 161 func TestFileSystem_GetUploadToken(t *testing.T) { 162 asserts := assert.New(t) 163 fs := FileSystem{ 164 User: &model.User{Model: gorm.Model{ID: 1}}, 165 Policy: &model.Policy{}, 166 } 167 ctx := context.Background() 168 169 // 成功 170 { 171 cache.SetSettings(map[string]string{ 172 "upload_session_timeout": "10", 173 }, "setting_") 174 testHandler := new(FileHeaderMock) 175 testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{Credential: "test"}, nil) 176 fs.Handler = testHandler 177 mock.ExpectQuery("SELECT(.+)"). 178 WithArgs(1). 179 WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1)) 180 mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) 181 mock.ExpectBegin() 182 mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) 183 mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) 184 mock.ExpectCommit() 185 res, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{ 186 Size: 0, 187 Name: "file", 188 VirtualPath: "/", 189 }) 190 asserts.NoError(mock.ExpectationsWereMet()) 191 testHandler.AssertExpectations(t) 192 asserts.NoError(err) 193 asserts.Equal("test", res.Credential) 194 } 195 196 // 无法获取上传凭证 197 { 198 cache.SetSettings(map[string]string{ 199 "upload_credential_timeout": "10", 200 "upload_session_timeout": "10", 201 }, "setting_") 202 testHandler := new(FileHeaderMock) 203 testHandler.On("Token", testMock.Anything, int64(10), testMock.Anything, testMock.Anything).Return(&serializer.UploadCredential{}, errors.New("error")) 204 fs.Handler = testHandler 205 mock.ExpectQuery("SELECT(.+)"). 206 WithArgs(1). 207 WillReturnRows(sqlmock.NewRows([]string{"id", "owner_id"}).AddRow(1, 1)) 208 mock.ExpectQuery("SELECT(.+)files(.+)").WillReturnError(errors.New("not found")) 209 mock.ExpectBegin() 210 mock.ExpectExec("INSERT(.+)files(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) 211 mock.ExpectExec("UPDATE(.+)storage(.+)").WillReturnResult(sqlmock.NewResult(1, 1)) 212 mock.ExpectCommit() 213 _, err := fs.CreateUploadSession(ctx, &fsctx.FileStream{ 214 Size: 0, 215 Name: "file", 216 VirtualPath: "/", 217 }) 218 asserts.NoError(mock.ExpectationsWereMet()) 219 testHandler.AssertExpectations(t) 220 asserts.Error(err) 221 } 222 } 223 224 func TestFileSystem_UploadFromStream(t *testing.T) { 225 asserts := assert.New(t) 226 fs := FileSystem{ 227 User: &model.User{ 228 Model: gorm.Model{ID: 1}, 229 Policy: model.Policy{Type: "mock"}, 230 }, 231 Policy: &model.Policy{Type: "mock"}, 232 } 233 ctx := context.Background() 234 235 err := fs.UploadFromStream(ctx, &fsctx.FileStream{ 236 File: ioutil.NopCloser(strings.NewReader("123")), 237 }, true) 238 asserts.Error(err) 239 } 240 241 func TestFileSystem_UploadFromPath(t *testing.T) { 242 asserts := assert.New(t) 243 fs := FileSystem{ 244 User: &model.User{ 245 Model: gorm.Model{ID: 1}, 246 Policy: model.Policy{Type: "mock"}, 247 }, 248 Policy: &model.Policy{Type: "mock"}, 249 } 250 ctx := context.Background() 251 252 // 文件不存在 253 { 254 err := fs.UploadFromPath(ctx, "test/not_exist", "/", fsctx.Overwrite) 255 asserts.Error(err) 256 } 257 258 // 文存在,上传失败 259 { 260 err := fs.UploadFromPath(ctx, "tests/test.zip", "/", fsctx.Overwrite) 261 asserts.Error(err) 262 } 263 }