github.com/anuvu/zot@v1.3.4/pkg/storage/storage_fs_test.go (about) 1 package storage_test 2 3 import ( 4 "bytes" 5 _ "crypto/sha256" 6 "encoding/json" 7 "io/ioutil" 8 "math/rand" 9 "os" 10 "os/exec" 11 "path" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/anuvu/zot/errors" 17 "github.com/anuvu/zot/pkg/extensions/monitoring" 18 "github.com/anuvu/zot/pkg/log" 19 "github.com/anuvu/zot/pkg/storage" 20 godigest "github.com/opencontainers/go-digest" 21 ispec "github.com/opencontainers/image-spec/specs-go/v1" 22 "github.com/rs/zerolog" 23 . "github.com/smartystreets/goconvey/convey" 24 ) 25 26 func TestStorageFSAPIs(t *testing.T) { 27 dir, err := ioutil.TempDir("", "oci-repo-test") 28 if err != nil { 29 panic(err) 30 } 31 32 defer os.RemoveAll(dir) 33 34 log := log.Logger{Logger: zerolog.New(os.Stdout)} 35 metrics := monitoring.NewMetricsServer(false, log) 36 il := storage.NewImageStore(dir, true, true, log, metrics) 37 38 Convey("Repo layout", t, func(c C) { 39 repoName := "test" 40 41 Convey("Bad image manifest", func() { 42 v, err := il.NewBlobUpload("test") 43 So(err, ShouldBeNil) 44 So(v, ShouldNotBeEmpty) 45 46 content := []byte("test-data1") 47 buf := bytes.NewBuffer(content) 48 l := buf.Len() 49 d := godigest.FromBytes(content) 50 51 b, err := il.PutBlobChunk(repoName, v, 0, int64(l), buf) 52 So(err, ShouldBeNil) 53 So(b, ShouldEqual, l) 54 55 err = il.FinishBlobUpload("test", v, buf, d.String()) 56 So(err, ShouldBeNil) 57 58 annotationsMap := make(map[string]string) 59 annotationsMap[ispec.AnnotationRefName] = "1.0" 60 m := ispec.Manifest{ 61 Config: ispec.Descriptor{ 62 Digest: d, 63 Size: int64(l), 64 }, 65 Layers: []ispec.Descriptor{ 66 { 67 MediaType: "application/vnd.oci.image.layer.v1.tar", 68 Digest: d, 69 Size: int64(l), 70 }, 71 }, 72 Annotations: annotationsMap, 73 } 74 75 m.SchemaVersion = 2 76 mb, _ := json.Marshal(m) 77 d = godigest.FromBytes(mb) 78 79 err = os.Chmod(path.Join(il.RootDir(), repoName, "index.json"), 0000) 80 if err != nil { 81 panic(err) 82 } 83 84 _, err = il.PutImageManifest(repoName, "1.0", ispec.MediaTypeImageManifest, mb) 85 So(err, ShouldNotBeNil) 86 87 err = os.Chmod(path.Join(il.RootDir(), repoName, "index.json"), 0755) 88 if err != nil { 89 panic(err) 90 } 91 92 _, err = il.PutImageManifest(repoName, "1.0", ispec.MediaTypeImageManifest, mb) 93 So(err, ShouldBeNil) 94 95 manifestPath := path.Join(il.RootDir(), repoName, "blobs", d.Algorithm().String(), d.Encoded()) 96 97 err = os.Chmod(manifestPath, 0000) 98 if err != nil { 99 panic(err) 100 } 101 102 _, _, _, err = il.GetImageManifest(repoName, d.String()) 103 So(err, ShouldNotBeNil) 104 105 err = os.Remove(manifestPath) 106 if err != nil { 107 panic(err) 108 } 109 110 _, _, _, err = il.GetImageManifest(repoName, d.String()) 111 So(err, ShouldNotBeNil) 112 113 err = os.Chmod(path.Join(il.RootDir(), repoName), 0000) 114 if err != nil { 115 panic(err) 116 } 117 118 _, err = il.PutImageManifest(repoName, "2.0", ispec.MediaTypeImageManifest, mb) 119 So(err, ShouldNotBeNil) 120 err = os.Chmod(path.Join(il.RootDir(), repoName), 0755) 121 if err != nil { 122 panic(err) 123 } 124 125 // invalid GetReferrers 126 _, err = il.GetReferrers("invalid", "invalid", "invalid") 127 So(err, ShouldNotBeNil) 128 129 _, err = il.GetReferrers(repoName, "invalid", "invalid") 130 So(err, ShouldNotBeNil) 131 132 _, err = il.GetReferrers(repoName, d.String(), "invalid") 133 So(err, ShouldNotBeNil) 134 135 // invalid DeleteImageManifest 136 indexPath := path.Join(il.RootDir(), repoName, "index.json") 137 err = os.Chmod(indexPath, 0000) 138 if err != nil { 139 panic(err) 140 } 141 142 err = il.DeleteImageManifest(repoName, d.String()) 143 So(err, ShouldNotBeNil) 144 145 err = os.RemoveAll(path.Join(il.RootDir(), repoName)) 146 if err != nil { 147 panic(err) 148 } 149 }) 150 }) 151 } 152 153 func TestDedupeLinks(t *testing.T) { 154 dir, err := ioutil.TempDir("", "oci-repo-test") 155 if err != nil { 156 panic(err) 157 } 158 159 defer os.RemoveAll(dir) 160 161 log := log.Logger{Logger: zerolog.New(os.Stdout)} 162 metrics := monitoring.NewMetricsServer(false, log) 163 il := storage.NewImageStore(dir, true, true, log, metrics) 164 165 Convey("Dedupe", t, func(c C) { 166 blobDigest1 := "" 167 blobDigest2 := "" 168 169 // manifest1 170 v, err := il.NewBlobUpload("dedupe1") 171 So(err, ShouldBeNil) 172 So(v, ShouldNotBeEmpty) 173 174 content := []byte("test-data3") 175 buf := bytes.NewBuffer(content) 176 l := buf.Len() 177 d := godigest.FromBytes(content) 178 b, err := il.PutBlobChunkStreamed("dedupe1", v, buf) 179 So(err, ShouldBeNil) 180 So(b, ShouldEqual, l) 181 blobDigest1 = strings.Split(d.String(), ":")[1] 182 So(blobDigest1, ShouldNotBeEmpty) 183 184 err = il.FinishBlobUpload("dedupe1", v, buf, d.String()) 185 So(err, ShouldBeNil) 186 So(b, ShouldEqual, l) 187 188 _, _, err = il.CheckBlob("dedupe1", d.String()) 189 So(err, ShouldBeNil) 190 191 _, _, err = il.GetBlob("dedupe1", d.String(), "application/vnd.oci.image.layer.v1.tar+gzip") 192 So(err, ShouldBeNil) 193 194 m := ispec.Manifest{} 195 m.SchemaVersion = 2 196 m = ispec.Manifest{ 197 Config: ispec.Descriptor{ 198 Digest: d, 199 Size: int64(l), 200 }, 201 Layers: []ispec.Descriptor{ 202 { 203 MediaType: "application/vnd.oci.image.layer.v1.tar", 204 Digest: d, 205 Size: int64(l), 206 }, 207 }, 208 } 209 m.SchemaVersion = 2 210 mb, _ := json.Marshal(m) 211 d = godigest.FromBytes(mb) 212 _, err = il.PutImageManifest("dedupe1", d.String(), ispec.MediaTypeImageManifest, mb) 213 So(err, ShouldBeNil) 214 215 _, _, _, err = il.GetImageManifest("dedupe1", d.String()) 216 So(err, ShouldBeNil) 217 218 // manifest2 219 v, err = il.NewBlobUpload("dedupe2") 220 So(err, ShouldBeNil) 221 So(v, ShouldNotBeEmpty) 222 223 content = []byte("test-data3") 224 buf = bytes.NewBuffer(content) 225 l = buf.Len() 226 d = godigest.FromBytes(content) 227 b, err = il.PutBlobChunkStreamed("dedupe2", v, buf) 228 So(err, ShouldBeNil) 229 So(b, ShouldEqual, l) 230 blobDigest2 = strings.Split(d.String(), ":")[1] 231 So(blobDigest2, ShouldNotBeEmpty) 232 233 err = il.FinishBlobUpload("dedupe2", v, buf, d.String()) 234 So(err, ShouldBeNil) 235 So(b, ShouldEqual, l) 236 237 _, _, err = il.CheckBlob("dedupe2", d.String()) 238 So(err, ShouldBeNil) 239 240 _, _, err = il.GetBlob("dedupe2", d.String(), "application/vnd.oci.image.layer.v1.tar+gzip") 241 So(err, ShouldBeNil) 242 243 m = ispec.Manifest{} 244 m.SchemaVersion = 2 245 m = ispec.Manifest{ 246 Config: ispec.Descriptor{ 247 Digest: d, 248 Size: int64(l), 249 }, 250 Layers: []ispec.Descriptor{ 251 { 252 MediaType: "application/vnd.oci.image.layer.v1.tar", 253 Digest: d, 254 Size: int64(l), 255 }, 256 }, 257 } 258 m.SchemaVersion = 2 259 mb, _ = json.Marshal(m) 260 d = godigest.FromBytes(mb) 261 _, err = il.PutImageManifest("dedupe2", "1.0", ispec.MediaTypeImageManifest, mb) 262 So(err, ShouldBeNil) 263 264 _, _, _, err = il.GetImageManifest("dedupe2", d.String()) 265 So(err, ShouldBeNil) 266 267 // verify that dedupe with hard links happened 268 fi1, err := os.Stat(path.Join(dir, "dedupe2", "blobs", "sha256", blobDigest1)) 269 So(err, ShouldBeNil) 270 fi2, err := os.Stat(path.Join(dir, "dedupe2", "blobs", "sha256", blobDigest2)) 271 So(err, ShouldBeNil) 272 So(os.SameFile(fi1, fi2), ShouldBeTrue) 273 }) 274 } 275 276 func TestDedupe(t *testing.T) { 277 Convey("Dedupe", t, func(c C) { 278 Convey("Nil ImageStore", func() { 279 var is storage.ImageStore 280 So(func() { _ = is.DedupeBlob("", "", "") }, ShouldPanic) 281 }) 282 283 Convey("Valid ImageStore", func() { 284 dir, err := ioutil.TempDir("", "oci-repo-test") 285 if err != nil { 286 panic(err) 287 } 288 defer os.RemoveAll(dir) 289 290 log := log.Logger{Logger: zerolog.New(os.Stdout)} 291 metrics := monitoring.NewMetricsServer(false, log) 292 il := storage.NewImageStore(dir, true, true, log, metrics) 293 294 So(il.DedupeBlob("", "", ""), ShouldNotBeNil) 295 }) 296 }) 297 } 298 299 // nolint: gocyclo 300 func TestNegativeCases(t *testing.T) { 301 Convey("Invalid root dir", t, func(c C) { 302 dir, err := ioutil.TempDir("", "oci-repo-test") 303 if err != nil { 304 panic(err) 305 } 306 os.RemoveAll(dir) 307 308 log := log.Logger{Logger: zerolog.New(os.Stdout)} 309 metrics := monitoring.NewMetricsServer(false, log) 310 311 So(storage.NewImageStore(dir, true, true, log, metrics), ShouldNotBeNil) 312 if os.Geteuid() != 0 { 313 So(storage.NewImageStore("/deadBEEF", true, true, log, metrics), ShouldBeNil) 314 } 315 }) 316 317 Convey("Invalid init repo", t, func(c C) { 318 dir, err := ioutil.TempDir("", "oci-repo-test") 319 if err != nil { 320 panic(err) 321 } 322 defer os.RemoveAll(dir) 323 324 log := log.Logger{Logger: zerolog.New(os.Stdout)} 325 metrics := monitoring.NewMetricsServer(false, log) 326 il := storage.NewImageStore(dir, true, true, log, metrics) 327 328 err = os.Chmod(dir, 0000) // remove all perms 329 if err != nil { 330 panic(err) 331 } 332 333 if os.Geteuid() != 0 { 334 err = il.InitRepo("test") 335 So(err, ShouldNotBeNil) 336 } 337 338 err = os.Chmod(dir, 0755) 339 if err != nil { 340 panic(err) 341 } 342 343 // Init repo should fail if repo is a file. 344 err = ioutil.WriteFile(path.Join(dir, "file-test"), []byte("this is test file"), 0755) // nolint:gosec 345 So(err, ShouldBeNil) 346 err = il.InitRepo("file-test") 347 So(err, ShouldNotBeNil) 348 349 err = os.Mkdir(path.Join(dir, "test-dir"), 0755) 350 So(err, ShouldBeNil) 351 352 err = il.InitRepo("test-dir") 353 So(err, ShouldBeNil) 354 }) 355 356 Convey("Invalid validate repo", t, func(c C) { 357 dir, err := ioutil.TempDir("", "oci-repo-test") 358 if err != nil { 359 panic(err) 360 } 361 defer os.RemoveAll(dir) 362 363 log := log.Logger{Logger: zerolog.New(os.Stdout)} 364 metrics := monitoring.NewMetricsServer(false, log) 365 il := storage.NewImageStore(dir, true, true, log, metrics) 366 367 So(il, ShouldNotBeNil) 368 So(il.InitRepo("test"), ShouldBeNil) 369 370 err = os.MkdirAll(path.Join(dir, "invalid-test"), 0755) 371 So(err, ShouldBeNil) 372 373 err = os.Chmod(path.Join(dir, "invalid-test"), 0000) // remove all perms 374 if err != nil { 375 panic(err) 376 } 377 _, err = il.ValidateRepo("invalid-test") 378 So(err, ShouldNotBeNil) 379 So(err, ShouldEqual, errors.ErrRepoNotFound) 380 381 err = os.Chmod(path.Join(dir, "invalid-test"), 0755) // remove all perms 382 if err != nil { 383 panic(err) 384 } 385 386 err = ioutil.WriteFile(path.Join(dir, "invalid-test", "blobs"), []byte{}, 0755) // nolint: gosec 387 if err != nil { 388 panic(err) 389 } 390 391 err = ioutil.WriteFile(path.Join(dir, "invalid-test", "index.json"), []byte{}, 0755) // nolint: gosec 392 if err != nil { 393 panic(err) 394 } 395 396 err = ioutil.WriteFile(path.Join(dir, "invalid-test", ispec.ImageLayoutFile), []byte{}, 0755) // nolint: gosec 397 if err != nil { 398 panic(err) 399 } 400 401 isValid, err := il.ValidateRepo("invalid-test") 402 So(err, ShouldBeNil) 403 So(isValid, ShouldEqual, false) 404 405 err = os.Remove(path.Join(dir, "invalid-test", "blobs")) 406 if err != nil { 407 panic(err) 408 } 409 err = os.Mkdir(path.Join(dir, "invalid-test", "blobs"), 0755) 410 if err != nil { 411 panic(err) 412 } 413 isValid, err = il.ValidateRepo("invalid-test") 414 So(err, ShouldNotBeNil) 415 So(isValid, ShouldEqual, false) 416 417 err = ioutil.WriteFile(path.Join(dir, "invalid-test", ispec.ImageLayoutFile), []byte("{}"), 0755) // nolint: gosec 418 if err != nil { 419 panic(err) 420 } 421 422 isValid, err = il.ValidateRepo("invalid-test") 423 So(err, ShouldNotBeNil) 424 So(err, ShouldEqual, errors.ErrRepoBadVersion) 425 So(isValid, ShouldEqual, false) 426 427 files, err := ioutil.ReadDir(path.Join(dir, "test")) 428 if err != nil { 429 panic(err) 430 } 431 432 for _, f := range files { 433 os.Remove(path.Join(dir, "test", f.Name())) 434 } 435 436 _, err = il.ValidateRepo("test") 437 So(err, ShouldNotBeNil) 438 439 err = os.RemoveAll(path.Join(dir, "test")) 440 if err != nil { 441 panic(err) 442 } 443 444 _, err = il.ValidateRepo("test") 445 So(err, ShouldNotBeNil) 446 447 err = os.Chmod(dir, 0000) // remove all perms 448 if err != nil { 449 panic(err) 450 } 451 452 if os.Geteuid() != 0 { 453 So(func() { _, _ = il.ValidateRepo("test") }, ShouldPanic) 454 } 455 456 err = os.Chmod(dir, 0755) // remove all perms 457 if err != nil { 458 panic(err) 459 } 460 461 err = os.RemoveAll(dir) 462 if err != nil { 463 panic(err) 464 } 465 466 _, err = il.GetRepositories() 467 So(err, ShouldNotBeNil) 468 }) 469 470 Convey("Invalid get image tags", t, func(c C) { 471 var ilfs storage.ImageStoreFS 472 _, err := ilfs.GetImageTags("test") 473 So(err, ShouldNotBeNil) 474 475 dir, err := ioutil.TempDir("", "oci-repo-test") 476 if err != nil { 477 panic(err) 478 } 479 defer os.RemoveAll(dir) 480 481 log := log.Logger{Logger: zerolog.New(os.Stdout)} 482 metrics := monitoring.NewMetricsServer(false, log) 483 il := storage.NewImageStore(dir, true, true, log, metrics) 484 485 So(il, ShouldNotBeNil) 486 So(il.InitRepo("test"), ShouldBeNil) 487 So(os.Remove(path.Join(dir, "test", "index.json")), ShouldBeNil) 488 _, err = il.GetImageTags("test") 489 So(err, ShouldNotBeNil) 490 So(os.RemoveAll(path.Join(dir, "test")), ShouldBeNil) 491 So(il.InitRepo("test"), ShouldBeNil) 492 So(ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0600), ShouldBeNil) 493 _, err = il.GetImageTags("test") 494 So(err, ShouldNotBeNil) 495 }) 496 497 Convey("Invalid get image manifest", t, func(c C) { 498 var ilfs storage.ImageStoreFS 499 _, _, _, err := ilfs.GetImageManifest("test", "") 500 So(err, ShouldNotBeNil) 501 502 dir, err := ioutil.TempDir("", "oci-repo-test") 503 if err != nil { 504 panic(err) 505 } 506 defer os.RemoveAll(dir) 507 508 log := log.Logger{Logger: zerolog.New(os.Stdout)} 509 metrics := monitoring.NewMetricsServer(false, log) 510 il := storage.NewImageStore(dir, true, true, log, metrics) 511 512 So(il, ShouldNotBeNil) 513 So(il.InitRepo("test"), ShouldBeNil) 514 515 err = os.Chmod(path.Join(dir, "test", "index.json"), 0000) 516 if err != nil { 517 panic(err) 518 } 519 520 _, _, _, err = il.GetImageManifest("test", "") 521 So(err, ShouldNotBeNil) 522 523 err = os.Remove(path.Join(dir, "test", "index.json")) 524 if err != nil { 525 panic(err) 526 } 527 528 _, _, _, err = il.GetImageManifest("test", "") 529 So(err, ShouldNotBeNil) 530 531 err = os.RemoveAll(path.Join(dir, "test")) 532 if err != nil { 533 panic(err) 534 } 535 536 So(il.InitRepo("test"), ShouldBeNil) 537 538 err = ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0600) 539 if err != nil { 540 panic(err) 541 } 542 _, _, _, err = il.GetImageManifest("test", "") 543 So(err, ShouldNotBeNil) 544 }) 545 546 Convey("Invalid new blob upload", t, func(c C) { 547 dir, err := ioutil.TempDir("", "oci-repo-test") 548 if err != nil { 549 panic(err) 550 } 551 defer os.RemoveAll(dir) 552 553 log := log.Logger{Logger: zerolog.New(os.Stdout)} 554 metrics := monitoring.NewMetricsServer(false, log) 555 il := storage.NewImageStore(dir, true, true, log, metrics) 556 557 So(il, ShouldNotBeNil) 558 So(il.InitRepo("test"), ShouldBeNil) 559 560 err = os.Chmod(path.Join(dir, "test", ".uploads"), 0000) 561 if err != nil { 562 panic(err) 563 } 564 _, err = il.NewBlobUpload("test") 565 So(err, ShouldNotBeNil) 566 567 err = os.Chmod(path.Join(dir, "test"), 0000) 568 if err != nil { 569 panic(err) 570 } 571 572 _, err = il.NewBlobUpload("test") 573 So(err, ShouldNotBeNil) 574 575 err = os.Chmod(path.Join(dir, "test"), 0755) 576 if err != nil { 577 panic(err) 578 } 579 580 So(il.InitRepo("test"), ShouldBeNil) 581 582 _, err = il.NewBlobUpload("test") 583 So(err, ShouldNotBeNil) 584 585 err = os.Chmod(path.Join(dir, "test", ".uploads"), 0755) 586 if err != nil { 587 panic(err) 588 } 589 590 v, err := il.NewBlobUpload("test") 591 So(err, ShouldBeNil) 592 593 err = os.Chmod(path.Join(dir, "test", ".uploads"), 0000) 594 if err != nil { 595 panic(err) 596 } 597 598 content := []byte("test-data3") 599 buf := bytes.NewBuffer(content) 600 l := buf.Len() 601 _, err = il.PutBlobChunkStreamed("test", v, buf) 602 So(err, ShouldNotBeNil) 603 604 _, err = il.PutBlobChunk("test", v, 0, int64(l), buf) 605 So(err, ShouldNotBeNil) 606 }) 607 608 Convey("Invalid dedupe scenarios", t, func() { 609 dir, err := ioutil.TempDir("", "oci-repo-test") 610 if err != nil { 611 panic(err) 612 } 613 defer os.RemoveAll(dir) 614 615 log := log.Logger{Logger: zerolog.New(os.Stdout)} 616 metrics := monitoring.NewMetricsServer(false, log) 617 il := storage.NewImageStore(dir, true, true, log, metrics) 618 619 v, err := il.NewBlobUpload("dedupe1") 620 So(err, ShouldBeNil) 621 So(v, ShouldNotBeEmpty) 622 623 content := []byte("test-data3") 624 buf := bytes.NewBuffer(content) 625 l := buf.Len() 626 d := godigest.FromBytes(content) 627 b, err := il.PutBlobChunkStreamed("dedupe1", v, buf) 628 So(err, ShouldBeNil) 629 So(b, ShouldEqual, l) 630 631 blobDigest1 := strings.Split(d.String(), ":")[1] 632 So(blobDigest1, ShouldNotBeEmpty) 633 634 err = il.FinishBlobUpload("dedupe1", v, buf, d.String()) 635 So(err, ShouldBeNil) 636 So(b, ShouldEqual, l) 637 638 // Create a file at the same place where FinishBlobUpload will create 639 err = il.InitRepo("dedupe2") 640 So(err, ShouldBeNil) 641 642 err = os.MkdirAll(path.Join(dir, "dedupe2", "blobs/sha256"), 0755) 643 if err != nil { 644 panic(err) 645 } 646 647 err = ioutil.WriteFile(path.Join(dir, "dedupe2", "blobs/sha256", blobDigest1), content, 0755) // nolint: gosec 648 if err != nil { 649 panic(err) 650 } 651 652 v, err = il.NewBlobUpload("dedupe2") 653 So(err, ShouldBeNil) 654 So(v, ShouldNotBeEmpty) 655 656 content = []byte("test-data3") 657 buf = bytes.NewBuffer(content) 658 l = buf.Len() 659 d = godigest.FromBytes(content) 660 b, err = il.PutBlobChunkStreamed("dedupe2", v, buf) 661 So(err, ShouldBeNil) 662 So(b, ShouldEqual, l) 663 664 cmd := exec.Command("sudo", "chattr", "+i", path.Join(dir, "dedupe2", "blobs/sha256", blobDigest1)) // nolint: gosec 665 _, err = cmd.Output() 666 if err != nil { 667 panic(err) 668 } 669 670 err = il.FinishBlobUpload("dedupe2", v, buf, d.String()) 671 So(err, ShouldNotBeNil) 672 So(b, ShouldEqual, l) 673 674 cmd = exec.Command("sudo", "chattr", "-i", path.Join(dir, "dedupe2", "blobs/sha256", blobDigest1)) // nolint: gosec 675 _, err = cmd.Output() 676 if err != nil { 677 panic(err) 678 } 679 680 err = il.FinishBlobUpload("dedupe2", v, buf, d.String()) 681 So(err, ShouldBeNil) 682 So(b, ShouldEqual, l) 683 }) 684 685 Convey("DirExists call with a filename as argument", t, func(c C) { 686 dir, err := ioutil.TempDir("", "oci-repo-test") 687 if err != nil { 688 panic(err) 689 } 690 defer os.RemoveAll(dir) 691 692 filePath := path.Join(dir, "file.txt") 693 err = ioutil.WriteFile(filePath, []byte("some dummy file content"), 0644) //nolint: gosec 694 if err != nil { 695 panic(err) 696 } 697 698 ok := storage.DirExists(filePath) 699 So(ok, ShouldBeFalse) 700 }) 701 } 702 703 func TestHardLink(t *testing.T) { 704 Convey("Test that ValidateHardLink creates rootDir if it does not exist", t, func() { 705 var randomDir string 706 707 rand.Seed(time.Now().UnixNano()) 708 for { 709 randomLen := rand.Intn(100) 710 randomDir = "/tmp/" + randSeq(randomLen) 711 712 if _, err := os.Stat(randomDir); os.IsNotExist(err) { 713 break 714 } 715 } 716 defer os.RemoveAll(randomDir) 717 718 err := storage.ValidateHardLink(randomDir) 719 So(err, ShouldBeNil) 720 }) 721 Convey("Test that ValidateHardLink returns error if rootDir is a file", t, func() { 722 dir, err := ioutil.TempDir("", "storage-hard-test") 723 if err != nil { 724 panic(err) 725 } 726 defer os.RemoveAll(dir) 727 728 filePath := path.Join(dir, "file.txt") 729 err = ioutil.WriteFile(filePath, []byte("some dummy file content"), 0644) //nolint: gosec 730 if err != nil { 731 panic(err) 732 } 733 734 err = storage.ValidateHardLink(filePath) 735 So(err, ShouldNotBeNil) 736 }) 737 Convey("Test if filesystem supports hardlink", t, func() { 738 dir, err := ioutil.TempDir("", "storage-hard-test") 739 if err != nil { 740 panic(err) 741 } 742 defer os.RemoveAll(dir) 743 744 err = storage.ValidateHardLink(dir) 745 So(err, ShouldBeNil) 746 747 err = ioutil.WriteFile(path.Join(dir, "hardtest.txt"), []byte("testing hard link code"), 0644) //nolint: gosec 748 if err != nil { 749 panic(err) 750 } 751 752 err = os.Chmod(dir, 0400) 753 if err != nil { 754 panic(err) 755 } 756 757 err = os.Link(path.Join(dir, "hardtest.txt"), path.Join(dir, "duphardtest.txt")) 758 So(err, ShouldNotBeNil) 759 760 err = os.Chmod(dir, 0644) 761 if err != nil { 762 panic(err) 763 } 764 }) 765 } 766 767 func randSeq(n int) string { 768 var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 769 770 b := make([]rune, n) 771 for i := range b { 772 b[i] = letters[rand.Intn(len(letters))] 773 } 774 775 return string(b) 776 }