github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/services/filesstore/filesstore_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package filesstore 5 6 import ( 7 "bytes" 8 "fmt" 9 "io/ioutil" 10 "math/rand" 11 "os" 12 "testing" 13 "time" 14 15 "github.com/stretchr/testify/require" 16 "github.com/stretchr/testify/suite" 17 "github.com/xtgo/uuid" 18 19 "github.com/mattermost/mattermost-server/v5/mlog" 20 ) 21 22 func randomString() string { 23 return uuid.NewRandom().String() 24 } 25 26 type FileBackendTestSuite struct { 27 suite.Suite 28 29 settings FileBackendSettings 30 backend FileBackend 31 } 32 33 func TestLocalFileBackendTestSuite(t *testing.T) { 34 // Setup a global logger to catch tests logging outside of app context 35 // The global logger will be stomped by apps initializing but that's fine for testing. Ideally this won't happen. 36 mlog.InitGlobalLogger(mlog.NewLogger(&mlog.LoggerConfiguration{ 37 EnableConsole: true, 38 ConsoleJson: true, 39 ConsoleLevel: "error", 40 EnableFile: false, 41 })) 42 43 dir, err := ioutil.TempDir("", "") 44 require.NoError(t, err) 45 defer os.RemoveAll(dir) 46 47 suite.Run(t, &FileBackendTestSuite{ 48 settings: FileBackendSettings{ 49 DriverName: driverLocal, 50 Directory: dir, 51 }, 52 }) 53 } 54 55 func TestS3FileBackendTestSuite(t *testing.T) { 56 runBackendTest(t, false) 57 } 58 59 func TestS3FileBackendTestSuiteWithEncryption(t *testing.T) { 60 runBackendTest(t, true) 61 } 62 63 func runBackendTest(t *testing.T, encrypt bool) { 64 s3Host := os.Getenv("CI_MINIO_HOST") 65 if s3Host == "" { 66 s3Host = "localhost" 67 } 68 69 s3Port := os.Getenv("CI_MINIO_PORT") 70 if s3Port == "" { 71 s3Port = "9000" 72 } 73 74 s3Endpoint := fmt.Sprintf("%s:%s", s3Host, s3Port) 75 76 suite.Run(t, &FileBackendTestSuite{ 77 settings: FileBackendSettings{ 78 DriverName: driverS3, 79 AmazonS3AccessKeyId: "minioaccesskey", 80 AmazonS3SecretAccessKey: "miniosecretkey", 81 AmazonS3Bucket: "mattermost-test", 82 AmazonS3Region: "", 83 AmazonS3Endpoint: s3Endpoint, 84 AmazonS3PathPrefix: "", 85 AmazonS3SSL: false, 86 AmazonS3SSE: encrypt, 87 }, 88 }) 89 } 90 91 func (s *FileBackendTestSuite) SetupTest() { 92 backend, err := NewFileBackend(s.settings) 93 require.NoError(s.T(), err) 94 s.backend = backend 95 96 // This is needed to create the bucket if it doesn't exist. 97 s.Nil(s.backend.TestConnection()) 98 } 99 100 func (s *FileBackendTestSuite) TestConnection() { 101 s.Nil(s.backend.TestConnection()) 102 } 103 104 func (s *FileBackendTestSuite) TestReadWriteFile() { 105 b := []byte("test") 106 path := "tests/" + randomString() 107 108 written, err := s.backend.WriteFile(bytes.NewReader(b), path) 109 s.Nil(err) 110 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 111 defer s.backend.RemoveFile(path) 112 113 read, err := s.backend.ReadFile(path) 114 s.Nil(err) 115 116 readString := string(read) 117 s.EqualValues(readString, "test") 118 } 119 120 func (s *FileBackendTestSuite) TestReadWriteFileImage() { 121 b := []byte("testimage") 122 path := "tests/" + randomString() + ".png" 123 124 written, err := s.backend.WriteFile(bytes.NewReader(b), path) 125 s.Nil(err) 126 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 127 defer s.backend.RemoveFile(path) 128 129 read, err := s.backend.ReadFile(path) 130 s.Nil(err) 131 132 readString := string(read) 133 s.EqualValues(readString, "testimage") 134 } 135 136 func (s *FileBackendTestSuite) TestFileExists() { 137 b := []byte("testimage") 138 path := "tests/" + randomString() + ".png" 139 140 _, err := s.backend.WriteFile(bytes.NewReader(b), path) 141 s.Nil(err) 142 defer s.backend.RemoveFile(path) 143 144 res, err := s.backend.FileExists(path) 145 s.Nil(err) 146 s.True(res) 147 148 res, err = s.backend.FileExists("tests/idontexist.png") 149 s.Nil(err) 150 s.False(res) 151 } 152 153 func (s *FileBackendTestSuite) TestCopyFile() { 154 b := []byte("test") 155 path1 := "tests/" + randomString() 156 path2 := "tests/" + randomString() 157 158 written, err := s.backend.WriteFile(bytes.NewReader(b), path1) 159 s.Nil(err) 160 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 161 defer s.backend.RemoveFile(path1) 162 163 err = s.backend.CopyFile(path1, path2) 164 s.Nil(err) 165 defer s.backend.RemoveFile(path2) 166 167 data1, err := s.backend.ReadFile(path1) 168 s.Nil(err) 169 170 data2, err := s.backend.ReadFile(path2) 171 s.Nil(err) 172 173 s.Equal(b, data1) 174 s.Equal(b, data2) 175 } 176 177 func (s *FileBackendTestSuite) TestCopyFileToDirectoryThatDoesntExist() { 178 b := []byte("test") 179 path1 := "tests/" + randomString() 180 path2 := "tests/newdirectory/" + randomString() 181 182 written, err := s.backend.WriteFile(bytes.NewReader(b), path1) 183 s.Nil(err) 184 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 185 defer s.backend.RemoveFile(path1) 186 187 err = s.backend.CopyFile(path1, path2) 188 s.Nil(err) 189 defer s.backend.RemoveFile(path2) 190 191 _, err = s.backend.ReadFile(path1) 192 s.Nil(err) 193 194 _, err = s.backend.ReadFile(path2) 195 s.Nil(err) 196 } 197 198 func (s *FileBackendTestSuite) TestMoveFile() { 199 b := []byte("test") 200 path1 := "tests/" + randomString() 201 path2 := "tests/" + randomString() 202 203 written, err := s.backend.WriteFile(bytes.NewReader(b), path1) 204 s.Nil(err) 205 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 206 defer s.backend.RemoveFile(path1) 207 208 s.Nil(s.backend.MoveFile(path1, path2)) 209 defer s.backend.RemoveFile(path2) 210 211 _, err = s.backend.ReadFile(path1) 212 s.Error(err) 213 214 data, err := s.backend.ReadFile(path2) 215 s.Nil(err) 216 217 s.Equal(b, data) 218 } 219 220 func (s *FileBackendTestSuite) TestRemoveFile() { 221 b := []byte("test") 222 path := "tests/" + randomString() 223 224 written, err := s.backend.WriteFile(bytes.NewReader(b), path) 225 s.Nil(err) 226 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 227 s.Nil(s.backend.RemoveFile(path)) 228 229 _, err = s.backend.ReadFile(path) 230 s.Error(err) 231 232 written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/foo") 233 s.Nil(err) 234 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 235 236 written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/bar") 237 s.Nil(err) 238 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 239 240 written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/asdf") 241 s.Nil(err) 242 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 243 244 s.Nil(s.backend.RemoveDirectory("tests2")) 245 } 246 247 func (s *FileBackendTestSuite) TestListDirectory() { 248 b := []byte("test") 249 path1 := "19700101/" + randomString() 250 path2 := "19800101/" + randomString() 251 252 paths, err := s.backend.ListDirectory("19700101") 253 s.Nil(err) 254 s.Len(paths, 0) 255 256 written, err := s.backend.WriteFile(bytes.NewReader(b), path1) 257 s.Nil(err) 258 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 259 260 written, err = s.backend.WriteFile(bytes.NewReader(b), path2) 261 s.Nil(err) 262 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 263 264 paths, err = s.backend.ListDirectory("19700101") 265 s.Nil(err) 266 s.Len(paths, 1) 267 s.Equal(path1, (paths)[0]) 268 269 paths, err = s.backend.ListDirectory("19700101/") 270 s.Nil(err) 271 s.Len(paths, 1) 272 s.Equal(path1, (paths)[0]) 273 274 paths, err = s.backend.ListDirectory("") 275 s.Nil(err) 276 277 found1 := false 278 found2 := false 279 for _, path := range paths { 280 if path == "19700101" { 281 found1 = true 282 } else if path == "19800101" { 283 found2 = true 284 } 285 } 286 s.True(found1) 287 s.True(found2) 288 289 s.backend.RemoveFile(path1) 290 s.backend.RemoveFile(path2) 291 } 292 293 func (s *FileBackendTestSuite) TestRemoveDirectory() { 294 b := []byte("test") 295 296 written, err := s.backend.WriteFile(bytes.NewReader(b), "tests2/foo") 297 s.Nil(err) 298 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 299 300 written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/bar") 301 s.Nil(err) 302 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 303 304 written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/aaa") 305 s.Nil(err) 306 s.EqualValues(len(b), written, "expected given number of bytes to have been written") 307 308 s.Nil(s.backend.RemoveDirectory("tests2")) 309 310 _, err = s.backend.ReadFile("tests2/foo") 311 s.Error(err) 312 _, err = s.backend.ReadFile("tests2/bar") 313 s.Error(err) 314 _, err = s.backend.ReadFile("tests2/asdf") 315 s.Error(err) 316 } 317 318 func (s *FileBackendTestSuite) TestAppendFile() { 319 s.Run("should fail if target file is missing", func() { 320 path := "tests/" + randomString() 321 b := make([]byte, 1024) 322 written, err := s.backend.AppendFile(bytes.NewReader(b), path) 323 s.Error(err) 324 s.Zero(written) 325 }) 326 327 s.Run("should correctly append the data", func() { 328 // First part needs to be at least 5MB for the S3 implementation to work. 329 size := 5 * 1024 * 1024 330 b := make([]byte, size) 331 for i := range b { 332 b[i] = 'A' 333 } 334 path := "tests/" + randomString() 335 336 written, err := s.backend.WriteFile(bytes.NewReader(b), path) 337 s.Nil(err) 338 s.EqualValues(len(b), written) 339 defer s.backend.RemoveFile(path) 340 341 b2 := make([]byte, 1024) 342 for i := range b2 { 343 b2[i] = 'B' 344 } 345 346 written, err = s.backend.AppendFile(bytes.NewReader(b2), path) 347 s.Nil(err) 348 s.EqualValues(int64(len(b2)), written) 349 350 read, err := s.backend.ReadFile(path) 351 s.Nil(err) 352 s.EqualValues(len(b)+len(b2), len(read)) 353 s.EqualValues(append(b, b2...), read) 354 355 b3 := make([]byte, 1024) 356 for i := range b3 { 357 b3[i] = 'C' 358 } 359 360 written, err = s.backend.AppendFile(bytes.NewReader(b3), path) 361 s.Nil(err) 362 s.EqualValues(int64(len(b3)), written) 363 364 read, err = s.backend.ReadFile(path) 365 s.Nil(err) 366 s.EqualValues(len(b)+len(b2)+len(b3), len(read)) 367 s.EqualValues(append(append(b, b2...), b3...), read) 368 }) 369 } 370 371 func (s *FileBackendTestSuite) TestFileSize() { 372 s.Run("nonexistent file", func() { 373 size, err := s.backend.FileSize("tests/nonexistentfile") 374 s.NotNil(err) 375 s.Zero(size) 376 }) 377 378 s.Run("valid file", func() { 379 data := make([]byte, rand.Intn(1024*1024)+1) 380 path := "tests/" + randomString() 381 382 written, err := s.backend.WriteFile(bytes.NewReader(data), path) 383 s.Nil(err) 384 s.EqualValues(len(data), written) 385 defer s.backend.RemoveFile(path) 386 387 size, err := s.backend.FileSize(path) 388 s.Nil(err) 389 s.Equal(int64(len(data)), size) 390 }) 391 } 392 393 func (s *FileBackendTestSuite) TestFileModTime() { 394 s.Run("nonexistent file", func() { 395 modTime, err := s.backend.FileModTime("tests/nonexistentfile") 396 s.NotNil(err) 397 s.Empty(modTime) 398 }) 399 400 s.Run("valid file", func() { 401 path := "tests/" + randomString() 402 data := []byte("some data") 403 404 written, err := s.backend.WriteFile(bytes.NewReader(data), path) 405 s.Nil(err) 406 s.EqualValues(len(data), written) 407 defer s.backend.RemoveFile(path) 408 409 modTime, err := s.backend.FileModTime(path) 410 s.Nil(err) 411 s.NotEmpty(modTime) 412 413 // We wait 1 second so that the times will differ enough to be testable. 414 time.Sleep(1 * time.Second) 415 416 path2 := "tests/" + randomString() 417 written, err = s.backend.WriteFile(bytes.NewReader(data), path2) 418 s.Nil(err) 419 s.EqualValues(len(data), written) 420 defer s.backend.RemoveFile(path2) 421 422 modTime2, err := s.backend.FileModTime(path2) 423 s.Nil(err) 424 s.NotEmpty(modTime2) 425 s.True(modTime2.After(modTime)) 426 }) 427 } 428 429 func BenchmarkS3WriteFile(b *testing.B) { 430 settings := FileBackendSettings{ 431 DriverName: driverS3, 432 AmazonS3AccessKeyId: "minioaccesskey", 433 AmazonS3SecretAccessKey: "miniosecretkey", 434 AmazonS3Bucket: "mattermost-test", 435 AmazonS3Region: "", 436 AmazonS3Endpoint: "localhost:9000", 437 AmazonS3PathPrefix: "", 438 AmazonS3SSL: false, 439 AmazonS3SSE: false, 440 } 441 442 backend, err := NewFileBackend(settings) 443 require.NoError(b, err) 444 445 // This is needed to create the bucket if it doesn't exist. 446 require.NoError(b, backend.TestConnection()) 447 448 path := "tests/" + randomString() 449 size := 1 * 1024 * 1024 450 data := make([]byte, size) 451 452 b.ResetTimer() 453 454 for i := 0; i < b.N; i++ { 455 written, err := backend.WriteFile(bytes.NewReader(data), path) 456 defer backend.RemoveFile(path) 457 require.NoError(b, err) 458 require.Equal(b, len(data), int(written)) 459 } 460 461 b.StopTimer() 462 }