github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/storage/zz_storage_test.go (about) 1 package storage_test 2 3 import ( 4 "bytes" 5 "io" 6 "os" 7 "reflect" 8 "runtime" 9 "strconv" 10 "testing" 11 "time" 12 13 "github.com/agiledragon/gomonkey/v2" 14 "github.com/aws/aws-sdk-go/aws" 15 "github.com/aws/aws-sdk-go/aws/session" 16 "github.com/aws/aws-sdk-go/service/s3" 17 "github.com/golang/mock/gomock" 18 . "github.com/onsi/gomega" 19 "github.com/pkg/errors" 20 "github.com/shirou/gopsutil/v3/disk" 21 22 "github.com/machinefi/w3bstream/pkg/depends/base/consts" 23 "github.com/machinefi/w3bstream/pkg/depends/base/types" 24 "github.com/machinefi/w3bstream/pkg/depends/conf/storage" 25 mock_conf_storage "github.com/machinefi/w3bstream/pkg/test/mock_depends_conf_storage" 26 ) 27 28 func TestStorage(t *testing.T) { 29 c := gomock.NewController(t) 30 defer c.Finish() 31 32 t.Run("IsZero", func(t *testing.T) { 33 s := &storage.Storage{Typ: storage.STORAGE_TYPE_UNKNOWN} 34 NewWithT(t).Expect(s.IsZero()).To(BeTrue()) 35 36 s = &storage.Storage{ 37 Typ: storage.STORAGE_TYPE__S3, 38 S3: &storage.S3{}, 39 } 40 NewWithT(t).Expect(s.IsZero()).To(BeFalse()) 41 }) 42 43 t.Run("SetDefault", func(t *testing.T) { 44 s := &storage.Storage{Typ: storage.STORAGE_TYPE_UNKNOWN} 45 s.SetDefault() 46 NewWithT(t).Expect(s.Typ).To(Equal(storage.STORAGE_TYPE__FILESYSTEM)) 47 48 s = &storage.Storage{} 49 s.SetDefault() 50 NewWithT(t).Expect(s.FilesizeLimit).To(Equal(int64(1024 * 1024))) 51 NewWithT(t).Expect(s.DiskReserve).To(Equal(int64(20 * 1024 * 1024))) 52 53 s = &storage.Storage{ 54 FilesizeLimit: 100, 55 DiskReserve: 100, 56 } 57 s.SetDefault() 58 NewWithT(t).Expect(s.FilesizeLimit).To(Equal(int64(100))) 59 NewWithT(t).Expect(s.DiskReserve).To(Equal(int64(100))) 60 }) 61 62 t.Run("Init", func(t *testing.T) { 63 t.Run("#InitTempDir", func(t *testing.T) { 64 s := &storage.Storage{LocalFs: &storage.LocalFs{}} 65 cases := []*struct { 66 preFn func() 67 expect string 68 }{ 69 { 70 preFn: func() { 71 _ = os.Unsetenv("TMPDIR") 72 _ = os.Unsetenv(consts.EnvProjectName) 73 }, 74 expect: "/tmp/service", 75 }, 76 { 77 preFn: func() { 78 _ = os.Setenv("TMPDIR", "/test_tmp") 79 _ = os.Setenv(consts.EnvProjectName, "test_storage") 80 }, 81 expect: "/test_tmp/test_storage", 82 }, 83 } 84 85 for _, cc := range cases { 86 cc.preFn() 87 err := s.Init() 88 NewWithT(t).Expect(err).To(BeNil()) 89 NewWithT(t).Expect(s.TempDir).To(Equal(os.Getenv("TMPDIR"))) 90 _ = os.Unsetenv(consts.EnvProjectName) 91 } 92 }) 93 94 t.Run("#InitTypeAndOp", func(t *testing.T) { 95 cases := []*struct { 96 conf *storage.Storage 97 expect error 98 }{{ 99 conf: &storage.Storage{}, 100 expect: storage.ErrMissingConfigFS, 101 }, { 102 conf: &storage.Storage{LocalFs: &storage.LocalFs{}}, 103 expect: nil, 104 }, { 105 conf: &storage.Storage{Typ: storage.STORAGE_TYPE__S3}, 106 expect: storage.ErrMissingConfigS3, 107 }, { 108 conf: &storage.Storage{ 109 Typ: storage.STORAGE_TYPE__S3, 110 S3: &storage.S3{ 111 Endpoint: "http://demo.s3.org", 112 Region: "us", 113 AccessKeyID: "1", 114 SecretAccessKey: "1", 115 BucketName: "test_bucket", 116 }, 117 }, 118 expect: nil, 119 }, { 120 conf: &storage.Storage{Typ: storage.STORAGE_TYPE__IPFS}, 121 expect: storage.ErrMissingConfigIPFS, 122 }, { 123 conf: &storage.Storage{Typ: storage.StorageType(100)}, 124 expect: storage.ErrUnsupprtedStorageType, 125 }} 126 127 for idx, cc := range cases { 128 t.Run("#"+strconv.Itoa(idx), func(t *testing.T) { 129 err := cc.conf.Init() 130 if cc.expect == nil { 131 NewWithT(t).Expect(err).To(BeNil()) 132 } else { 133 NewWithT(t).Expect(err).To(Equal(cc.expect)) 134 } 135 }) 136 } 137 }) 138 }) 139 140 t.Run("#Upload", func(t *testing.T) { 141 cc := &storage.Storage{TempDir: "/tmp"} 142 143 t.Run("#Success", func(t *testing.T) { 144 op := mock_conf_storage.NewMockStorageOperations(c) 145 op.EXPECT().Upload(gomock.Any(), gomock.Any()).Return(nil).MaxTimes(1) 146 cc.WithOperation(op) 147 148 err := cc.Upload("any", []byte("any")) 149 NewWithT(t).Expect(err).To(BeNil()) 150 }) 151 152 t.Run("#Failed", func(t *testing.T) { 153 t.Run("#EmptyContent", func(t *testing.T) { 154 err := cc.Upload("any", []byte("")) 155 NewWithT(t).Expect(err).To(Equal(storage.ErrEmptyContent)) 156 }) 157 t.Run("#FileSizeLimit", func(t *testing.T) { 158 cc.FilesizeLimit = 4 159 err := cc.Upload("any", []byte("12345")) 160 NewWithT(t).Expect(err).To(Equal(storage.ErrContentSizeExceeded)) 161 }) 162 t.Run("#DiskReserve", func(t *testing.T) { 163 op := mock_conf_storage.NewMockStorageOperations(c) 164 165 op.EXPECT().Upload(gomock.Any(), gomock.Any()).Return(nil).MaxTimes(1) 166 op.EXPECT().Type().Return(storage.STORAGE_TYPE__FILESYSTEM).MaxTimes(1) 167 cc.WithOperation(op) 168 169 stat, err := disk.Usage(cc.TempDir) 170 NewWithT(t).Expect(err).To(BeNil()) 171 172 cc.DiskReserve = int64(stat.Free + 1024*1024*1024) 173 cc.FilesizeLimit = 0 174 175 err = cc.Upload("any", []byte("any")) 176 NewWithT(t).Expect(err).To(Equal(storage.ErrDiskReservationLimit)) 177 }) 178 t.Run("#OpUploadFailed", func(t *testing.T) { 179 op := mock_conf_storage.NewMockStorageOperations(c) 180 181 op.EXPECT().Upload(gomock.Any(), gomock.Any()).Return(errors.New("mock error")).MaxTimes(1) 182 cc.WithOperation(op) 183 184 cc.DiskReserve = 0 185 cc.FilesizeLimit = 0 186 187 err := cc.Upload("any", []byte("any")) 188 NewWithT(t).Expect(err).NotTo(BeNil()) 189 }) 190 }) 191 }) 192 193 t.Run("#Read", func(t *testing.T) { 194 cc := &storage.Storage{} 195 196 t.Run("#Success", func(t *testing.T) { 197 op := mock_conf_storage.NewMockStorageOperations(c) 198 op.EXPECT().Read(gomock.Any()).Return(nil, nil, nil).MaxTimes(1) 199 cc.WithOperation(op) 200 201 _, _, err := cc.Read("any") 202 NewWithT(t).Expect(err).To(BeNil()) 203 }) 204 t.Run("#Failed", func(t *testing.T) { 205 op := mock_conf_storage.NewMockStorageOperations(c) 206 op.EXPECT().Read(gomock.Any()).Return(nil, nil, errors.New("mock error")).MaxTimes(1) 207 cc.WithOperation(op) 208 209 _, _, err := cc.Read("any") 210 NewWithT(t).Expect(err).NotTo(BeNil()) 211 }) 212 }) 213 214 t.Run("#Type", func(t *testing.T) { 215 cc := &storage.Storage{} 216 expect := storage.STORAGE_TYPE__S3 217 218 op := mock_conf_storage.NewMockStorageOperations(c) 219 op.EXPECT().Type().Return(expect).MaxTimes(1) 220 cc.WithOperation(op) 221 222 NewWithT(t).Expect(cc.Type()).To(Equal(expect)) 223 }) 224 225 t.Run("#Validate", func(t *testing.T) { 226 cc := &storage.Storage{} 227 228 content := []byte("1234567") 229 md5sum := storage.HMAC_ALG_TYPE__MD5.HexSum(content) 230 sha1sum := storage.HMAC_ALG_TYPE__SHA1.HexSum(content) 231 sha256sum := storage.HMAC_ALG_TYPE__SHA256.HexSum(content) 232 233 NewWithT(t).Expect(cc.Validate(nil, "sum")).To(BeTrue()) 234 NewWithT(t).Expect(cc.Validate([]byte("xx"), "")).To(BeTrue()) 235 NewWithT(t).Expect(cc.Validate(content, md5sum)).To(BeTrue()) 236 NewWithT(t).Expect(cc.Validate(content, sha1sum, storage.HMAC_ALG_TYPE__SHA1)).To(BeTrue()) 237 NewWithT(t).Expect(cc.Validate(content, sha256sum, storage.HMAC_ALG_TYPE__SHA256)).To(BeTrue()) 238 }) 239 } 240 241 func TestS3(t *testing.T) { 242 t.Run("IsZero", func(t *testing.T) { 243 var ( 244 valued = &storage.S3{ 245 Endpoint: "s3://w3b-test", 246 Region: "us-east-2", 247 AccessKeyID: "xx", 248 SecretAccessKey: "xx", 249 BucketName: "w3b-test", 250 } 251 empty = &storage.S3{} 252 ) 253 NewWithT(t).Expect(valued.IsZero()).To(BeFalse()) 254 NewWithT(t).Expect(empty.IsZero()).To(BeTrue()) 255 }) 256 t.Run("SetDefault", func(t *testing.T) { 257 var ( 258 dftExpiration = types.Duration(10 * time.Minute) 259 conf = &storage.S3{UrlExpire: dftExpiration / 2} 260 ) 261 conf.UrlExpire = 0 262 conf.SetDefault() 263 NewWithT(t).Expect(conf.UrlExpire).To(Equal(dftExpiration)) 264 conf.UrlExpire = dftExpiration / 2 265 conf.SetDefault() 266 NewWithT(t).Expect(conf.UrlExpire).To(Equal(dftExpiration / 2)) 267 }) 268 t.Run("Init", func(t *testing.T) { 269 t.Run("#Success", func(t *testing.T) { 270 conf := &storage.S3{ 271 Endpoint: "", 272 Region: "us-east-2", 273 BucketName: "test", 274 } 275 err := conf.Init() 276 NewWithT(t).Expect(err).To(BeNil()) 277 }) 278 279 t.Run("#Failed", func(t *testing.T) { 280 t.Run("#NewSessionFailed", func(t *testing.T) { 281 if runtime.GOOS == `darwin` { 282 return 283 } 284 patcher := gomonkey.ApplyFunc( 285 session.NewSession, 286 func(...*aws.Config) (*session.Session, error) { 287 return nil, errors.New("") 288 }, 289 ) 290 defer patcher.Reset() 291 292 NewWithT(t).Expect((&storage.S3{}).Init()).NotTo(BeNil()) 293 }) 294 }) 295 }) 296 var ( 297 ep = &storage.S3{} 298 key = "unit_test_key" 299 data = []byte("unit_test_data") 300 ) 301 302 t.Run("Upload", func(t *testing.T) { 303 // NewWithT(t).Expect(ep.Init()).To(BeNil()) // if use real ep for e2e testing, enable this line 304 t.Run("#Success", func(t *testing.T) { 305 if runtime.GOOS == `darwin` { 306 return 307 } 308 patch := gomonkey.ApplyMethod( 309 reflect.TypeOf(&s3.S3{}), 310 "PutObject", 311 func(receiver *s3.S3, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) { 312 return nil, nil 313 }, 314 ) 315 defer patch.Reset() 316 317 t.Run("#WithoutSumCheck", func(t *testing.T) { 318 err := ep.Upload(key, data) 319 NewWithT(t).Expect(err).To(BeNil()) 320 }) 321 t.Run("#WithMd5SumCheck", func(t *testing.T) { 322 err := ep.Upload(key, data, storage.HMAC_ALG_TYPE__MD5) 323 NewWithT(t).Expect(err).To(BeNil()) 324 }) 325 t.Run("#WithSHA1SumCheck", func(t *testing.T) { 326 err := ep.Upload(key, data, storage.HMAC_ALG_TYPE__SHA1) 327 NewWithT(t).Expect(err).To(BeNil()) 328 }) 329 t.Run("#WithSHA256SumCheck", func(t *testing.T) { 330 err := ep.Upload(key, data, storage.HMAC_ALG_TYPE__SHA256) 331 NewWithT(t).Expect(err).To(BeNil()) 332 }) 333 }) 334 t.Run("#Failed", func(t *testing.T) { 335 if runtime.GOOS == `darwin` { 336 return 337 } 338 patch := gomonkey.ApplyMethod( 339 reflect.TypeOf(&s3.S3{}), 340 "PutObject", 341 func(receiver *s3.S3, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) { 342 return nil, errors.New("") 343 }, 344 ) 345 defer patch.Reset() 346 err := ep.Upload(key, data) 347 NewWithT(t).Expect(err).NotTo(BeNil()) 348 }) 349 }) 350 t.Run("Read", func(t *testing.T) { 351 t.Run("#Success", func(t *testing.T) { 352 if runtime.GOOS == `darwin` { 353 return 354 } 355 patch := gomonkey.ApplyMethod( 356 reflect.TypeOf(&s3.S3{}), 357 "GetObject", 358 func(_ *s3.S3, _ *s3.GetObjectInput) (*s3.GetObjectOutput, error) { 359 return &s3.GetObjectOutput{ 360 Body: io.NopCloser(bytes.NewBuffer(data)), 361 }, nil 362 }, 363 ) 364 defer patch.Reset() 365 366 cases := []*struct { 367 name string 368 chk []storage.HmacAlgType 369 sum []byte 370 }{ 371 {name: "#NoParam", chk: nil, sum: storage.HMAC_ALG_TYPE__MD5.Sum(data)}, 372 {name: "#HmacMD5", chk: []storage.HmacAlgType{storage.HMAC_ALG_TYPE__MD5}, sum: storage.HMAC_ALG_TYPE__MD5.Sum(data)}, 373 {name: "#HamcSHA1", chk: []storage.HmacAlgType{storage.HMAC_ALG_TYPE__SHA1}, sum: storage.HMAC_ALG_TYPE__SHA1.Sum(data)}, 374 {name: "#HamcSHA256", chk: []storage.HmacAlgType{storage.HMAC_ALG_TYPE__SHA256}, sum: storage.HMAC_ALG_TYPE__SHA256.Sum(data)}, 375 } 376 377 for _, c := range cases { 378 t.Run(c.name, func(t *testing.T) { 379 content, sum, err := ep.Read(key, c.chk...) 380 NewWithT(t).Expect(err).To(BeNil()) 381 NewWithT(t).Expect(bytes.Equal(content, data)).To(BeTrue()) 382 NewWithT(t).Expect(bytes.Equal(sum, c.sum)).To(BeTrue()) 383 }) 384 } 385 }) 386 t.Run("#Failed", func(t *testing.T) { 387 t.Run("#GetObjectFailed", func(t *testing.T) { 388 if runtime.GOOS == `darwin` { 389 return 390 } 391 patch := gomonkey.ApplyMethod( 392 reflect.TypeOf(&s3.S3{}), 393 "GetObject", 394 func(_ *s3.S3, _ *s3.GetObjectInput) (*s3.GetObjectOutput, error) { 395 return nil, errors.New("any") 396 }, 397 ) 398 defer patch.Reset() 399 _, _, err := ep.Read(key + "maybe_not_exists") 400 NewWithT(t).Expect(err).NotTo(BeNil()) 401 }) 402 t.Run("#ReadBodyFailed", func(t *testing.T) { 403 if runtime.GOOS == `darwin` { 404 return 405 } 406 patch1 := gomonkey.ApplyMethod( 407 reflect.TypeOf(&s3.S3{}), 408 "GetObject", 409 func(_ *s3.S3, _ *s3.GetObjectInput) (*s3.GetObjectOutput, error) { 410 return &s3.GetObjectOutput{ 411 Body: io.NopCloser(bytes.NewBuffer(data)), 412 }, nil 413 }, 414 ) 415 defer patch1.Reset() 416 patch2 := gomonkey.ApplyFunc( 417 io.ReadAll, 418 func(_ io.Reader) ([]byte, error) { 419 return nil, errors.New("any") 420 }, 421 ) 422 defer patch2.Reset() 423 424 _, _, err := ep.Read(key) 425 NewWithT(t).Expect(err).NotTo(BeNil()) 426 }) 427 }) 428 }) 429 t.Run("Delete", func(t *testing.T) { 430 t.Run("#Success", func(t *testing.T) { 431 if runtime.GOOS == `darwin` { 432 return 433 } 434 patch := gomonkey.ApplyMethod( 435 reflect.TypeOf(&s3.S3{}), 436 "DeleteObject", 437 func(_ *s3.S3, _ *s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error) { 438 return nil, nil 439 }, 440 ) 441 defer patch.Reset() 442 NewWithT(t).Expect(ep.Delete(key)).To(BeNil()) 443 }) 444 t.Run("#Failed", func(t *testing.T) { 445 if runtime.GOOS == `darwin` { 446 return 447 } 448 patch := gomonkey.ApplyMethod( 449 reflect.TypeOf(&s3.S3{}), 450 "DeleteObject", 451 func(_ *s3.S3, _ *s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error) { 452 return nil, errors.New("any") 453 }, 454 ) 455 defer patch.Reset() 456 NewWithT(t).Expect(ep.Delete("any")).NotTo(BeNil()) 457 }) 458 }) 459 } 460 461 func TestLocalFS(t *testing.T) { 462 t.Run("Init", func(t *testing.T) { 463 cases := []*struct { 464 name string 465 root string 466 tmpdir string 467 service string 468 expect string 469 }{ 470 {name: "#WithRoot", root: "/tmp/123", expect: "/tmp/123"}, 471 {name: "#WithoutRoot#WithTMPDIR", tmpdir: "/tmp/321", expect: "/tmp/321/service_tmp"}, 472 {name: "#WithoutRoot#WithServiceName", tmpdir: "/tmp/567", service: "test", expect: "/tmp/567/test"}, 473 } 474 475 for _, c := range cases { 476 t.Run(c.name, func(t *testing.T) { 477 _ = os.Unsetenv("TMPDIR") 478 _ = os.Unsetenv(consts.EnvProjectName) 479 480 if c.tmpdir != "" { 481 _ = os.Setenv("TMPDIR", c.tmpdir) 482 } 483 if c.service != "" { 484 _ = os.Setenv(consts.EnvProjectName, c.service) 485 } 486 487 conf := &storage.LocalFs{Root: c.root} 488 err := conf.Init() 489 NewWithT(t).Expect(err).To(BeNil()) 490 NewWithT(t).Expect(conf.Root).To(Equal(c.expect)) 491 }) 492 } 493 }) 494 t.Run("Type", func(t *testing.T) { 495 NewWithT(t).Expect((&storage.LocalFs{}).Type()).To(Equal(storage.STORAGE_TYPE__FILESYSTEM)) 496 }) 497 t.Run("Upload", func(t *testing.T) { 498 c := &storage.LocalFs{Root: "/tmp/test_storage"} 499 NewWithT(t).Expect(c.Init()).To(BeNil()) 500 501 data := []byte("any") 502 503 t.Run("#Success", func(t *testing.T) { 504 key := "any_success" 505 NewWithT(t).Expect(c.Upload(key, data)).To(BeNil()) 506 t.Run("#FileExists", func(t *testing.T) { 507 if runtime.GOOS == `darwin` { 508 return 509 } 510 patch := gomonkey.ApplyFunc( 511 storage.IsPathExists, 512 func(_ string) bool { 513 return true 514 }, 515 ) 516 defer patch.Reset() 517 key := "any_file_exists" 518 NewWithT(t).Expect(c.Upload(key, data)).To(BeNil()) 519 }) 520 }) 521 t.Run("#Failed", func(t *testing.T) { 522 t.Run("#OpenFileFaield", func(t *testing.T) { 523 if runtime.GOOS == `darwin` { 524 return 525 } 526 patch := gomonkey.ApplyFunc( 527 os.OpenFile, 528 func(_ string, _ int, _ os.FileMode) (*os.File, error) { 529 return nil, errors.New("any") 530 }, 531 ) 532 defer patch.Reset() 533 key := "any_open_file_failed" 534 NewWithT(t).Expect(c.Upload(key, data)).NotTo(BeNil()) 535 }) 536 t.Run("#WriteFileFailed", func(t *testing.T) { 537 if runtime.GOOS == `darwin` { 538 return 539 } 540 patch := gomonkey.ApplyMethod( 541 reflect.TypeOf(&os.File{}), 542 "Write", 543 func(_ *os.File, _ []byte) (int, error) { 544 return 0, errors.New("any") 545 }, 546 ) 547 defer patch.Reset() 548 key := "any_write_file_failed" 549 NewWithT(t).Expect(c.Upload(key, data)).NotTo(BeNil()) 550 }) 551 }) 552 _ = os.RemoveAll(c.Root) 553 }) 554 t.Run("Read", func(t *testing.T) { 555 c := &storage.LocalFs{Root: "/tmp/test_storage"} 556 NewWithT(t).Expect(c.Init()).To(BeNil()) 557 558 data := []byte("any") 559 t.Run("#Success", func(t *testing.T) { 560 key := "any_success" 561 NewWithT(t).Expect(c.Upload(key, data)).To(BeNil()) 562 563 content, sum, err := c.Read(key) 564 NewWithT(t).Expect(err).To(BeNil()) 565 NewWithT(t).Expect(bytes.Equal(content, data)).To(BeTrue()) 566 NewWithT(t).Expect(bytes.Equal(sum, storage.HMAC_ALG_TYPE__MD5.Sum(data))).To(BeTrue()) 567 }) 568 t.Run("#Failed", func(t *testing.T) { 569 key := "any_failed" 570 571 _, _, err := c.Read(key) 572 NewWithT(t).Expect(err).NotTo(BeNil()) 573 }) 574 _ = os.RemoveAll(c.Root) 575 }) 576 t.Run("Delete", func(t *testing.T) { 577 c := &storage.LocalFs{Root: "/tmp/test_storage"} 578 NewWithT(t).Expect(c.Delete("any_delete")).NotTo(BeNil()) 579 }) 580 } 581 582 func TestIsPathExists(t *testing.T) { 583 _, filename, _, _ := runtime.Caller(0) 584 NewWithT(t).Expect(filename).NotTo(Equal("")) 585 NewWithT(t).Expect(storage.IsPathExists(filename)).To(BeTrue()) 586 }