github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/filesystem/archive_test.go (about) 1 package filesystem 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "github.com/cloudreve/Cloudreve/v3/pkg/util" 8 testMock "github.com/stretchr/testify/mock" 9 "io" 10 "os" 11 "path/filepath" 12 "runtime" 13 "strings" 14 "testing" 15 16 "github.com/DATA-DOG/go-sqlmock" 17 model "github.com/cloudreve/Cloudreve/v3/models" 18 "github.com/cloudreve/Cloudreve/v3/pkg/cache" 19 "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" 20 "github.com/jinzhu/gorm" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestFileSystem_Compress(t *testing.T) { 25 asserts := assert.New(t) 26 ctx := context.Background() 27 fs := FileSystem{ 28 User: &model.User{Model: gorm.Model{ID: 1}}, 29 } 30 31 // 成功 32 { 33 // 查找压缩父目录 34 mock.ExpectQuery("SELECT(.+)folders(.+)"). 35 WithArgs(1, 1). 36 WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "parent")) 37 // 查找顶级待压缩文件 38 mock.ExpectQuery("SELECT(.+)files(.+)"). 39 WithArgs(1, 1). 40 WillReturnRows( 41 sqlmock.NewRows( 42 []string{"id", "name", "source_name", "policy_id"}). 43 AddRow(1, "1.txt", "tests/file1.txt", 1), 44 ) 45 asserts.NoError(cache.Set("setting_temp_path", "tests", -1)) 46 // 查找父目录子文件 47 mock.ExpectQuery("SELECT(.+)files(.+)"). 48 WithArgs(1). 49 WillReturnRows(sqlmock.NewRows([]string{"id", "name", "source_name", "policy_id"})) 50 // 查找子目录 51 mock.ExpectQuery("SELECT(.+)folders(.+)"). 52 WithArgs(1). 53 WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(2, "sub")) 54 // 查找子目录子文件 55 mock.ExpectQuery("SELECT(.+)files(.+)"). 56 WithArgs(2). 57 WillReturnRows( 58 sqlmock.NewRows([]string{"id", "name", "source_name", "policy_id"}). 59 AddRow(2, "2.txt", "tests/file2.txt", 1), 60 ) 61 // 查找上传策略 62 asserts.NoError(cache.Set("policy_1", model.Policy{Type: "local"}, -1)) 63 w := &bytes.Buffer{} 64 65 err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true) 66 asserts.NoError(err) 67 asserts.NotEmpty(w.Len()) 68 } 69 70 // 上下文取消 71 { 72 ctx, cancel := context.WithCancel(context.Background()) 73 cancel() 74 // 查找压缩父目录 75 mock.ExpectQuery("SELECT(.+)folders(.+)"). 76 WithArgs(1, 1). 77 WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "parent")) 78 // 查找顶级待压缩文件 79 mock.ExpectQuery("SELECT(.+)files(.+)"). 80 WithArgs(1, 1). 81 WillReturnRows( 82 sqlmock.NewRows( 83 []string{"id", "name", "source_name", "policy_id"}). 84 AddRow(1, "1.txt", "tests/file1.txt", 1), 85 ) 86 asserts.NoError(cache.Set("setting_temp_path", "tests", -1)) 87 88 w := &bytes.Buffer{} 89 err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true) 90 asserts.Error(err) 91 asserts.NotEmpty(w.Len()) 92 } 93 94 // 限制父目录 95 { 96 ctx := context.WithValue(context.Background(), fsctx.LimitParentCtx, &model.Folder{ 97 Model: gorm.Model{ID: 3}, 98 }) 99 // 查找压缩父目录 100 mock.ExpectQuery("SELECT(.+)folders(.+)"). 101 WithArgs(1, 1). 102 WillReturnRows(sqlmock.NewRows([]string{"id", "name", "parent_id"}).AddRow(1, "parent", 3)) 103 // 查找顶级待压缩文件 104 mock.ExpectQuery("SELECT(.+)files(.+)"). 105 WithArgs(1, 1). 106 WillReturnRows( 107 sqlmock.NewRows( 108 []string{"id", "name", "source_name", "policy_id"}). 109 AddRow(1, "1.txt", "tests/file1.txt", 1), 110 ) 111 asserts.NoError(cache.Set("setting_temp_path", "tests", -1)) 112 113 w := &bytes.Buffer{} 114 err := fs.Compress(ctx, w, []uint{1}, []uint{1}, true) 115 asserts.Error(err) 116 asserts.Equal(ErrObjectNotExist, err) 117 asserts.Empty(w.Len()) 118 } 119 120 } 121 122 type MockNopRSC string 123 124 func (m MockNopRSC) Read(b []byte) (int, error) { 125 return 0, errors.New("read error") 126 } 127 128 func (m MockNopRSC) Seek(n int64, offset int) (int64, error) { 129 return 0, errors.New("read error") 130 } 131 132 func (m MockNopRSC) Close() error { 133 return errors.New("read error") 134 } 135 136 type MockRSC struct { 137 rs io.ReadSeeker 138 } 139 140 func (m MockRSC) Read(b []byte) (int, error) { 141 return m.rs.Read(b) 142 } 143 144 func (m MockRSC) Seek(n int64, offset int) (int64, error) { 145 return m.rs.Seek(n, offset) 146 } 147 148 func (m MockRSC) Close() error { 149 return nil 150 } 151 152 var basepath string 153 154 func init() { 155 _, currentFile, _, _ := runtime.Caller(0) 156 basepath = filepath.Dir(currentFile) 157 } 158 159 func Path(rel string) string { 160 return filepath.Join(basepath, rel) 161 } 162 163 func TestFileSystem_Decompress(t *testing.T) { 164 asserts := assert.New(t) 165 ctx := context.Background() 166 fs := FileSystem{ 167 User: &model.User{Model: gorm.Model{ID: 1}}, 168 } 169 os.RemoveAll(util.RelativePath("tests/decompress")) 170 171 // 压缩文件不存在 172 { 173 // 查找根目录 174 mock.ExpectQuery("SELECT(.+)folders(.+)"). 175 WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "/")) 176 // 查找压缩文件,未找到 177 mock.ExpectQuery("SELECT(.+)files(.+)"). 178 WillReturnRows(sqlmock.NewRows([]string{"id", "name"})) 179 err := fs.Decompress(ctx, "/1.zip", "/", "") 180 asserts.NoError(mock.ExpectationsWereMet()) 181 asserts.Error(err) 182 } 183 184 // 无法下载压缩文件 185 { 186 fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}} 187 fs.FileTarget[0].Policy.ID = 1 188 testHandler := new(FileHeaderMock) 189 testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{}, errors.New("error")) 190 fs.Handler = testHandler 191 err := fs.Decompress(ctx, "/1.zip", "/", "") 192 asserts.NoError(mock.ExpectationsWereMet()) 193 asserts.Error(err) 194 asserts.EqualError(err, "error") 195 } 196 197 // 无法创建临时压缩文件 198 { 199 cache.Set("setting_temp_path", "/tests:", 0) 200 fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}} 201 fs.FileTarget[0].Policy.ID = 1 202 testHandler := new(FileHeaderMock) 203 testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{}, nil) 204 fs.Handler = testHandler 205 err := fs.Decompress(ctx, "/1.zip", "/", "") 206 asserts.NoError(mock.ExpectationsWereMet()) 207 asserts.Error(err) 208 } 209 210 // 无法写入压缩文件 211 { 212 cache.Set("setting_temp_path", "tests", 0) 213 fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}} 214 fs.FileTarget[0].Policy.ID = 1 215 testHandler := new(FileHeaderMock) 216 testHandler.On("Get", testMock.Anything, "1.zip").Return(MockNopRSC("1"), nil) 217 fs.Handler = testHandler 218 err := fs.Decompress(ctx, "/1.zip", "/", "") 219 asserts.NoError(mock.ExpectationsWereMet()) 220 asserts.Error(err) 221 asserts.Contains(err.Error(), "read error") 222 } 223 224 // 无法重设上传策略 225 { 226 cache.Set("setting_temp_path", "tests", 0) 227 fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}} 228 fs.FileTarget[0].Policy.ID = 1 229 testHandler := new(FileHeaderMock) 230 testHandler.On("Get", testMock.Anything, "1.zip").Return(MockRSC{rs: strings.NewReader("read")}, nil) 231 fs.Handler = testHandler 232 err := fs.Decompress(ctx, "/1.zip", "/", "") 233 asserts.NoError(mock.ExpectationsWereMet()) 234 asserts.Error(err) 235 asserts.True(util.IsEmpty(util.RelativePath("tests/decompress"))) 236 } 237 238 // 无法上传,容量不足 239 { 240 cache.Set("setting_max_parallel_transfer", "1", 0) 241 zipFile, _ := os.Open(Path("tests/test.zip")) 242 fs.FileTarget = []model.File{{SourceName: "1.zip", Policy: model.Policy{Type: "mock"}}} 243 fs.FileTarget[0].Policy.ID = 1 244 fs.User.Policy.Type = "mock" 245 testHandler := new(FileHeaderMock) 246 testHandler.On("Get", testMock.Anything, "1.zip").Return(zipFile, nil) 247 fs.Handler = testHandler 248 249 fs.Decompress(ctx, "/1.zip", "/", "") 250 251 zipFile.Close() 252 253 asserts.NoError(mock.ExpectationsWereMet()) 254 testHandler.AssertExpectations(t) 255 } 256 }