github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/core/lom_test.go (about) 1 //nolint:dupl // copy-paste benign and can wait 2 // Package core_test provides tests for cluster package 3 /* 4 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 5 */ 6 package core_test 7 8 import ( 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 "strconv" 14 "time" 15 16 "github.com/NVIDIA/aistore/api/apc" 17 "github.com/NVIDIA/aistore/cmn" 18 "github.com/NVIDIA/aistore/cmn/cos" 19 "github.com/NVIDIA/aistore/core" 20 "github.com/NVIDIA/aistore/core/meta" 21 "github.com/NVIDIA/aistore/core/mock" 22 "github.com/NVIDIA/aistore/fs" 23 "github.com/NVIDIA/aistore/tools/cryptorand" 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 ) 27 28 var _ = Describe("LOM", func() { 29 const ( 30 tmpDir = "/tmp/lom_test" 31 numMpaths = 3 32 33 bucketLocalA = "LOM_TEST_Local_A" 34 bucketLocalB = "LOM_TEST_Local_B" 35 bucketLocalC = "LOM_TEST_Local_C" 36 37 bucketCloudA = "LOM_TEST_Cloud_A" 38 bucketCloudB = "LOM_TEST_Cloud_B" 39 40 sameBucketName = "LOM_TEST_Local_and_Cloud" 41 ) 42 43 var ( 44 localBckA = cmn.Bck{Name: bucketLocalA, Provider: apc.AIS, Ns: cmn.NsGlobal} 45 localBckB = cmn.Bck{Name: bucketLocalB, Provider: apc.AIS, Ns: cmn.NsGlobal} 46 cloudBckA = cmn.Bck{Name: bucketCloudA, Provider: apc.AWS, Ns: cmn.NsGlobal} 47 ) 48 49 var ( 50 mpaths []string 51 mis []*fs.Mountpath 52 53 oldCloudProviders = cmn.GCO.Get().Backend.Providers 54 ) 55 56 for i := range numMpaths { 57 mpath := fmt.Sprintf("%s/mpath%d", tmpDir, i) 58 mpaths = append(mpaths, mpath) 59 mis = append(mis, &fs.Mountpath{Path: mpath}) 60 _ = cos.CreateDir(mpath) 61 } 62 63 config := cmn.GCO.BeginUpdate() 64 config.TestFSP.Count = 1 65 cmn.GCO.CommitUpdate(config) 66 67 fs.TestNew(nil) 68 for _, mpath := range mpaths { 69 _, _ = fs.Add(mpath, "daeID") 70 } 71 72 fs.CSM.Reg(fs.ObjectType, &fs.ObjectContentResolver{}, true) 73 fs.CSM.Reg(fs.WorkfileType, &fs.WorkfileContentResolver{}, true) 74 75 bmd := mock.NewBaseBownerMock( 76 meta.NewBck( 77 bucketLocalA, apc.AIS, cmn.NsGlobal, 78 &cmn.Bprops{Cksum: cmn.CksumConf{Type: cos.ChecksumNone}, BID: 1}, 79 ), 80 meta.NewBck( 81 bucketLocalB, apc.AIS, cmn.NsGlobal, 82 &cmn.Bprops{Cksum: cmn.CksumConf{Type: cos.ChecksumXXHash}, LRU: cmn.LRUConf{Enabled: true}, BID: 2}, 83 ), 84 meta.NewBck( 85 bucketLocalC, apc.AIS, cmn.NsGlobal, 86 &cmn.Bprops{ 87 Cksum: cmn.CksumConf{Type: cos.ChecksumXXHash}, 88 LRU: cmn.LRUConf{Enabled: true}, 89 Mirror: cmn.MirrorConf{Enabled: true, Copies: 2}, 90 BID: 3, 91 }, 92 ), 93 meta.NewBck(sameBucketName, apc.AIS, cmn.NsGlobal, &cmn.Bprops{BID: 4}), 94 meta.NewBck(bucketCloudA, apc.AWS, cmn.NsGlobal, &cmn.Bprops{BID: 5}), 95 meta.NewBck(bucketCloudB, apc.AWS, cmn.NsGlobal, &cmn.Bprops{BID: 6}), 96 meta.NewBck(sameBucketName, apc.AWS, cmn.NsGlobal, &cmn.Bprops{BID: 7}), 97 ) 98 99 BeforeEach(func() { 100 // Dummy backend provider for tests involving cloud buckets 101 config := cmn.GCO.BeginUpdate() 102 config.Backend.Providers = map[string]cmn.Ns{ 103 apc.AWS: cmn.NsGlobal, 104 } 105 106 cmn.GCO.CommitUpdate(config) 107 108 for _, mpath := range mpaths { 109 _, _ = fs.Add(mpath, "daeID") 110 } 111 _ = mock.NewTarget(bmd) 112 }) 113 114 AfterEach(func() { 115 _ = os.RemoveAll(tmpDir) 116 117 config := cmn.GCO.BeginUpdate() 118 config.Backend.Providers = oldCloudProviders 119 cmn.GCO.CommitUpdate(config) 120 }) 121 122 Describe("FQN Resolution", func() { 123 testObject := "foldr/test-obj.ext" 124 desiredLocalFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 125 126 When("run for an ais bucket", func() { 127 It("Should populate fields from Bucket and ObjName", func() { 128 fs.Disable(mpaths[1]) // Ensure that it matches desiredLocalFQN 129 fs.Disable(mpaths[2]) // Ensure that it matches desiredLocalFQN 130 131 lom := &core.LOM{ObjName: testObject} 132 err := lom.InitBck(&cmn.Bck{Name: bucketLocalA, Provider: apc.AIS}) 133 Expect(err).NotTo(HaveOccurred()) 134 Expect(lom.FQN).To(BeEquivalentTo(desiredLocalFQN)) 135 136 Expect(lom.Uname()).To(BeEquivalentTo(lom.Bck().MakeUname(testObject))) 137 Expect(lom.Bck().Provider).To(Equal(apc.AIS)) 138 139 // from lom.go: redundant in-part; tradeoff to speed-up workfile name gen, etc. 140 Expect(lom.Mountpath().Path).To(BeEquivalentTo(mpaths[0])) 141 expectEqualBck(lom.Bucket(), &localBckA) 142 Expect(lom.ObjName).To(BeEquivalentTo(testObject)) 143 144 fs.Enable(mpaths[1]) 145 fs.Enable(mpaths[2]) 146 }) 147 148 It("Should populate fields from a FQN", func() { 149 lom := &core.LOM{} 150 err := lom.InitFQN(desiredLocalFQN, nil) 151 Expect(err).NotTo(HaveOccurred()) 152 Expect(lom.Bck().Name).To(BeEquivalentTo(bucketLocalA)) 153 Expect(lom.ObjName).To(BeEquivalentTo(testObject)) 154 155 Expect(lom.Uname()).To(BeEquivalentTo(lom.Bck().MakeUname(testObject))) 156 Expect(lom.Bck().Provider).To(Equal(apc.AIS)) 157 158 // from lom.go: redundant in-part; tradeoff to speed-up workfile name gen, etc. 159 Expect(lom.Mountpath().Path).To(BeEquivalentTo(mpaths[0])) 160 expectEqualBck(lom.Bucket(), &localBckA) 161 Expect(lom.ObjName).To(BeEquivalentTo(testObject)) 162 }) 163 164 It("Should resolve work files", func() { 165 testPid := strconv.FormatInt(9876, 16) 166 testTieIndex := strconv.FormatInt(1355314332000000, 16)[5:] 167 workObject := "foldr/get.test-obj.ext" + "." + testTieIndex + "." + testPid 168 localFQN := mis[0].MakePathFQN(&cloudBckA, fs.WorkfileType, workObject) 169 170 var parsed fs.ParsedFQN 171 _, err := core.ResolveFQN(localFQN, &parsed) 172 Expect(err).NotTo(HaveOccurred()) 173 Expect(parsed.ContentType).To(BeEquivalentTo(fs.WorkfileType)) 174 }) 175 }) 176 177 When("run for a cloud bucket", func() { 178 testObject := "foldr/test-obj.ext" 179 desiredCloudFQN := mis[0].MakePathFQN(&cloudBckA, fs.ObjectType, testObject) 180 181 It("Should populate fields from Bucket and ObjName", func() { 182 // Ensure that it matches desiredCloudFQN 183 fs.Disable(mpaths[1]) 184 fs.Disable(mpaths[2]) 185 186 lom := &core.LOM{ObjName: testObject} 187 err := lom.InitBck(&cmn.Bck{Name: bucketCloudA, Provider: apc.AWS, Ns: cmn.NsGlobal}) 188 Expect(err).NotTo(HaveOccurred()) 189 Expect(lom.FQN).To(BeEquivalentTo(desiredCloudFQN)) 190 191 Expect(lom.Uname()).To(BeEquivalentTo(lom.Bck().MakeUname(testObject))) 192 Expect(lom.Bck().Provider).To(Equal(apc.AWS)) 193 194 // from lom.go: redundant in-part; tradeoff to speed-up workfile name gen, etc. 195 Expect(lom.Mountpath().Path).To(Equal(mpaths[0])) 196 expectEqualBck(lom.Bucket(), &cloudBckA) 197 Expect(lom.ObjName).To(Equal(testObject)) 198 199 fs.Enable(mpaths[2]) 200 fs.Enable(mpaths[1]) 201 }) 202 203 It("Should populate fields from a FQN", func() { 204 lom := &core.LOM{} 205 err := lom.InitFQN(desiredCloudFQN, nil) 206 Expect(err).NotTo(HaveOccurred()) 207 Expect(lom.Bck().Name).To(BeEquivalentTo(bucketCloudA)) 208 Expect(lom.ObjName).To(BeEquivalentTo(testObject)) 209 210 Expect(lom.Uname()).To(BeEquivalentTo(lom.Bck().MakeUname(testObject))) 211 Expect(lom.Bck().Provider).To(Equal(apc.AWS)) 212 213 // from lom.go: redundant in-part; tradeoff to speed-up workfile name gen, etc. 214 Expect(lom.Mountpath().Path).To(Equal(mpaths[0])) 215 expectEqualBck(lom.Bucket(), &cloudBckA) 216 Expect(lom.ObjName).To(Equal(testObject)) 217 }) 218 }) 219 220 When("run for invalid FQN", func() { 221 DescribeTable("should return error", 222 func(fqn string) { 223 lom := &core.LOM{} 224 err := lom.InitFQN(fqn, nil) 225 Expect(err).To(HaveOccurred()) 226 }, 227 Entry( 228 "invalid object name", 229 mis[0].MakePathFQN( 230 &cmn.Bck{Name: bucketCloudA, Provider: apc.AIS, Ns: cmn.NsGlobal}, 231 fs.ObjectType, 232 " ??? ", 233 ), 234 ), 235 Entry( 236 "invalid fqn", 237 "?/.,", 238 ), 239 Entry( 240 "missing content type", 241 mpaths[0], 242 ), 243 Entry( 244 "missing bucket type", 245 filepath.Join(mpaths[0], fs.ObjectType), 246 ), 247 Entry( 248 "missing bucket", 249 mis[0].MakePathBck( 250 &cmn.Bck{Name: "", Provider: apc.AIS, Ns: cmn.NsGlobal}, 251 ), 252 ), 253 Entry( 254 "missing object", 255 mis[0].MakePathCT( 256 &cmn.Bck{Name: bucketLocalA, Provider: apc.AIS, Ns: cmn.NsGlobal}, 257 fs.ObjectType, 258 ), 259 ), 260 ) 261 }) 262 }) 263 264 Describe("Load", func() { 265 Describe("Exists", func() { 266 testFileSize := 123 267 testObjectName := "fstat-foldr/test-obj.ext" 268 localFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObjectName) 269 270 It("should find out that object does not exist", func() { 271 os.Remove(localFQN) 272 lom := &core.LOM{} 273 err := lom.InitFQN(localFQN, nil) 274 Expect(err).NotTo(HaveOccurred()) 275 err = lom.Load(false, false) 276 Expect(cos.IsNotExist(err, 0)).To(BeTrue()) 277 }) 278 279 It("should find out that object exists", func() { 280 createTestFile(localFQN, testFileSize) 281 lom := &core.LOM{} 282 err := lom.InitFQN(localFQN, nil) 283 lom.SetSize(int64(testFileSize)) 284 Expect(err).NotTo(HaveOccurred()) 285 Expect(persist(lom)).NotTo(HaveOccurred()) 286 err = lom.Load(false, false) 287 Expect(err).NotTo(HaveOccurred()) 288 Expect(lom.SizeBytes()).To(BeEquivalentTo(testFileSize)) 289 }) 290 }) 291 292 Describe("Atime", func() { 293 desiredAtime := time.Unix(1500000000, 0) 294 testObjectName := "foldr/test-obj.ext" 295 296 It("should fetch atime for bucket with LRU disabled", func() { 297 localFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObjectName) 298 createTestFile(localFQN, 0) 299 Expect(os.Chtimes(localFQN, desiredAtime, desiredAtime)).ShouldNot(HaveOccurred()) 300 301 lom := &core.LOM{} 302 err := lom.InitFQN(localFQN, nil) 303 Expect(err).NotTo(HaveOccurred()) 304 lom.AcquireAtimefs() 305 Expect(lom.Persist()).NotTo(HaveOccurred()) 306 err = lom.Load(false, false) 307 Expect(err).NotTo(HaveOccurred()) 308 309 Expect(time.Unix(0, lom.AtimeUnix())).To(BeEquivalentTo(desiredAtime)) 310 }) 311 It("should fetch atime for bucket with LRU enabled", func() { 312 localFQN := mis[0].MakePathFQN(&localBckB, fs.ObjectType, testObjectName) 313 createTestFile(localFQN, 0) 314 Expect(os.Chtimes(localFQN, desiredAtime, desiredAtime)).ShouldNot(HaveOccurred()) 315 316 lom := &core.LOM{} 317 err := lom.InitFQN(localFQN, nil) 318 Expect(err).NotTo(HaveOccurred()) 319 lom.AcquireAtimefs() 320 Expect(lom.Persist()).NotTo(HaveOccurred()) 321 err = lom.Load(false, false) 322 Expect(err).NotTo(HaveOccurred()) 323 324 Expect(time.Unix(0, lom.AtimeUnix())).To(BeEquivalentTo(desiredAtime)) 325 }) 326 }) 327 328 Describe("checksum", func() { 329 testFileSize := 456 330 testObjectName := "cksum-foldr/test-obj.ext" 331 // Bucket needs to have checksum enabled 332 localFQN := mis[0].MakePathFQN(&localBckB, fs.ObjectType, testObjectName) 333 dummyCksm := cos.NewCksum(cos.ChecksumXXHash, "dummycksm") 334 335 Describe("ComputeCksumIfMissing", func() { 336 It("should ignore if bucket checksum is none", func() { 337 testObject := "foldr/test-obj.ext" 338 noneFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 339 340 lom := NewBasicLom(noneFQN) 341 cksum, err := lom.ComputeSetCksum() 342 Expect(err).NotTo(HaveOccurred()) 343 Expect(cksum).To(BeNil()) 344 }) 345 346 It("should not compute if not missing", func() { 347 lom := filePut(localFQN, testFileSize) 348 lom.SetCksum(dummyCksm) 349 cksum, err := lom.ComputeSetCksum() 350 Expect(err).NotTo(HaveOccurred()) 351 Expect(cksum).NotTo(BeEquivalentTo(dummyCksm)) 352 Expect(cksum.Value()).NotTo(BeEquivalentTo("")) 353 _, err = lom.ComputeSetCksum() 354 Expect(err).NotTo(HaveOccurred()) 355 Expect(lom.Checksum()).To(BeEquivalentTo(cksum)) 356 }) 357 358 It("should compute missing checksum", func() { 359 lom := filePut(localFQN, testFileSize) 360 expectedChecksum := getTestFileHash(localFQN) 361 362 cksum, err := lom.ComputeSetCksum() 363 Expect(err).NotTo(HaveOccurred()) 364 cksumType, cksumValue := cksum.Get() 365 Expect(cksumType).To(BeEquivalentTo(cos.ChecksumXXHash)) 366 Expect(cksumValue).To(BeEquivalentTo(expectedChecksum)) 367 Expect(lom.Checksum().Equal(cksum)).To(BeTrue()) 368 369 newLom := NewBasicLom(lom.FQN) 370 err = newLom.Load(false, false) 371 Expect(err).NotTo(HaveOccurred()) 372 cksumType, _ = newLom.Checksum().Get() 373 Expect(cksumType).To(BeEquivalentTo(cos.ChecksumNone)) 374 }) 375 }) 376 377 Describe("ValidateMetaChecksum", func() { 378 It("should ignore if bucket checksum is none", func() { 379 testObject := "foldr/test-obj.ext" 380 noneFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 381 382 lom := NewBasicLom(noneFQN) 383 err := lom.ValidateMetaChecksum() 384 Expect(err).NotTo(HaveOccurred()) 385 Expect(lom.Checksum()).To(BeNil()) 386 }) 387 388 It("should fill object with checksum if was not present", func() { 389 lom := filePut(localFQN, testFileSize) 390 expectedChecksum := getTestFileHash(localFQN) 391 392 fsLOM := NewBasicLom(localFQN) 393 err := fsLOM.Load(false, false) 394 Expect(err).NotTo(HaveOccurred()) 395 396 cksumType, _ := fsLOM.Checksum().Get() 397 Expect(cksumType).To(BeEquivalentTo(cos.ChecksumNone)) 398 399 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 400 lom.UncacheUnless() 401 402 Expect(lom.Checksum()).ToNot(BeNil()) 403 _, val := lom.Checksum().Get() 404 fsLOM = NewBasicLom(localFQN) 405 err = fsLOM.Load(false, false) 406 Expect(err).ShouldNot(HaveOccurred()) 407 _, fsVal := fsLOM.Checksum().Get() 408 Expect(fsVal).To(BeEquivalentTo(expectedChecksum)) 409 Expect(val).To(BeEquivalentTo(expectedChecksum)) 410 }) 411 412 It("should accept when filesystem and memory checksums match", func() { 413 lom := filePut(localFQN, testFileSize) 414 Expect(lom.ValidateMetaChecksum()).NotTo(HaveOccurred()) 415 }) 416 417 It("should accept when both filesystem and memory checksums are nil", func() { 418 lom := filePut(localFQN, testFileSize) 419 Expect(lom.ValidateMetaChecksum()).NotTo(HaveOccurred()) 420 }) 421 422 It("should not accept when memory has wrong checksum", func() { 423 lom := filePut(localFQN, testFileSize) 424 Expect(lom.ValidateMetaChecksum()).NotTo(HaveOccurred()) 425 426 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "wrong checksum")) 427 Expect(persist(lom)).NotTo(HaveOccurred()) 428 Expect(lom.ValidateContentChecksum()).To(HaveOccurred()) 429 }) 430 431 It("should not accept when object content has changed", func() { 432 lom := filePut(localFQN, testFileSize) 433 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 434 435 Expect(os.WriteFile(localFQN, []byte("wrong file"), cos.PermRWR)).To(BeNil()) 436 437 Expect(lom.ValidateContentChecksum()).To(HaveOccurred()) 438 }) 439 440 It("should not check object content when recompute false", func() { 441 lom := filePut(localFQN, testFileSize) 442 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 443 444 Expect(os.WriteFile(localFQN, []byte("wrong file"), cos.PermRWR)).To(BeNil()) 445 Expect(lom.ValidateMetaChecksum()).NotTo(HaveOccurred()) 446 }) 447 448 It("should not accept when xattr has wrong checksum", func() { 449 lom := filePut(localFQN, testFileSize) 450 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 451 452 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "wrong checksum")) 453 Expect(lom.ValidateMetaChecksum()).To(HaveOccurred()) 454 }) 455 }) 456 457 // copy-paste of some of ValidateMetaChecksum tests, however if there's no 458 // mocking solution, it's needed to have the same tests for both methods 459 Describe("ValidateContentChecksum", func() { 460 It("should ignore if bucket checksum is none", func() { 461 testObject := "foldr/test-obj.ext" 462 noneFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 463 464 lom := NewBasicLom(noneFQN) 465 err := lom.ValidateContentChecksum() 466 Expect(err).NotTo(HaveOccurred()) 467 Expect(lom.Checksum()).To(BeNil()) 468 }) 469 470 It("should fill object with checksum if was not present", func() { 471 lom := filePut(localFQN, testFileSize) 472 expectedChecksum := getTestFileHash(localFQN) 473 474 fsLOM := NewBasicLom(localFQN) 475 err := fsLOM.Load(false, false) 476 Expect(err).ShouldNot(HaveOccurred()) 477 478 cksumType, _ := fsLOM.Checksum().Get() 479 Expect(cksumType).To(BeEquivalentTo(cos.ChecksumNone)) 480 481 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 482 lom.UncacheUnless() 483 484 Expect(lom.Checksum()).ToNot(BeNil()) 485 _, cksumValue := lom.Checksum().Get() 486 487 fsLOM = NewBasicLom(localFQN) 488 err = fsLOM.Load(false, false) 489 Expect(err).ShouldNot(HaveOccurred()) 490 491 _, fsCksmVal := fsLOM.Checksum().Get() 492 Expect(fsCksmVal).To(BeEquivalentTo(expectedChecksum)) 493 Expect(cksumValue).To(BeEquivalentTo(expectedChecksum)) 494 }) 495 496 It("should accept when filesystem and memory checksums match", func() { 497 createTestFile(localFQN, testFileSize) 498 lom := NewBasicLom(localFQN) 499 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 500 }) 501 502 It("should accept when both filesystem and memory checksums are nil", func() { 503 createTestFile(localFQN, testFileSize) 504 lom := NewBasicLom(localFQN) 505 506 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 507 }) 508 509 It("should not accept when object content has changed", func() { 510 createTestFile(localFQN, testFileSize) 511 lom := NewBasicLom(localFQN) 512 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 513 514 err := os.WriteFile(localFQN, []byte("wrong file"), cos.PermRWR) 515 Expect(err).ShouldNot(HaveOccurred()) 516 517 Expect(lom.ValidateContentChecksum()).To(HaveOccurred()) 518 }) 519 }) 520 521 Describe("FromFS", func() { 522 It("should error if file does not exist", func() { 523 testObject := "foldr/test-obj-doesnt-exist.ext" 524 noneFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 525 lom := NewBasicLom(noneFQN) 526 527 Expect(lom.FromFS()).To(HaveOccurred()) 528 }) 529 530 It("should fill object with correct meta", func() { 531 startTime := time.Now() 532 time.Sleep(50 * time.Millisecond) 533 lom1 := filePut(localFQN, testFileSize) 534 lom2 := NewBasicLom(localFQN) 535 Expect(lom1.Persist()).NotTo(HaveOccurred()) 536 537 Expect(lom1.ValidateContentChecksum()).NotTo(HaveOccurred()) 538 Expect(lom1.Persist()).ToNot(HaveOccurred()) 539 540 Expect(lom2.Load(false, false)).ToNot(HaveOccurred()) // Calls `FromFS`. 541 Expect(lom2.Checksum()).To(BeEquivalentTo(lom1.Checksum())) 542 Expect(lom2.Version()).To(BeEquivalentTo(lom1.Version())) 543 Expect(lom2.SizeBytes()).To(BeEquivalentTo(testFileSize)) 544 Expect(time.Unix(0, lom2.AtimeUnix()).After(startTime)).To(BeTrue()) 545 }) 546 }) 547 }) 548 549 Describe("Version", func() { 550 testObject := "foldr/test-obj.ext" 551 desiredVersion := "9001" 552 localFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 553 554 It("should be able to get version", func() { 555 lom := filePut(localFQN, 0) 556 lom.SetVersion(desiredVersion) 557 Expect(persist(lom)).NotTo(HaveOccurred()) 558 559 err := lom.Load(false, false) 560 Expect(err).ToNot(HaveOccurred()) 561 Expect(lom.Version()).To(BeEquivalentTo(desiredVersion)) 562 }) 563 }) 564 565 Describe("CustomMD", func() { 566 testObject := "foldr/test-obj.ext" 567 localFQN := mis[0].MakePathFQN(&localBckA, fs.ObjectType, testObject) 568 569 It("should correctly set and get custom metadata", func() { 570 lom := filePut(localFQN, 0) 571 lom.SetCustomMD(cos.StrKVs{ 572 cmn.SourceObjMD: apc.GCP, 573 cmn.ETag: "etag", 574 cmn.CRC32CObjMD: "crc32", 575 }) 576 value, exists := lom.GetCustomKey(cmn.SourceObjMD) 577 Expect(exists).To(BeTrue()) 578 Expect(value).To(Equal(apc.GCP)) 579 _, exists = lom.GetCustomKey("unknown") 580 Expect(exists).To(BeFalse()) 581 }) 582 }) 583 }) 584 585 Describe("copy object methods", func() { 586 const ( 587 testObjectName = "foldr/test-obj.ext" 588 testFileSize = 101 589 desiredVersion = "9002" 590 ) 591 592 findMpath := func(objectName, bucket string, defaultLoc bool, ignoreFQNs ...string) string { 593 OuterLoop: 594 for _, mi := range mis { 595 bck := cmn.Bck{Name: bucket, Provider: apc.AIS, Ns: cmn.NsGlobal} 596 fqn := mi.MakePathFQN(&bck, fs.ObjectType, objectName) 597 for _, ignoreFQN := range ignoreFQNs { 598 if fqn == ignoreFQN { 599 continue OuterLoop 600 } 601 } 602 603 var parsed fs.ParsedFQN 604 hrw, _ := core.ResolveFQN(fqn, &parsed) 605 if defaultLoc && hrw == fqn { 606 return fqn 607 } else if !defaultLoc && hrw != fqn { 608 return fqn 609 } 610 } 611 cos.Assert(false) 612 return "" 613 } 614 615 mirrorFQNs := []string{ 616 // Bucket with redundancy 617 findMpath(testObjectName, bucketLocalC, true /*defaultLoc*/), 618 findMpath(testObjectName, bucketLocalC, false /*defaultLoc*/), 619 } 620 // Add another mirrorFQN but it must be different than the second one. 621 mirrorFQNs = append( 622 mirrorFQNs, 623 findMpath(testObjectName, bucketLocalC, false /*defaultLoc*/, mirrorFQNs[1]), 624 ) 625 // Object with different name as default one. 626 renamedObjFQN := findMpath("other.txt", bucketLocalC, true /*defaultLoc*/) 627 628 copyFQNs := []string{ 629 // Bucket with no redundancy 630 findMpath(testObjectName, bucketLocalB, true /*defaultLoc*/), 631 findMpath(testObjectName, bucketLocalB, false /*defaultLoc*/), 632 } 633 634 prepareLOM := func(fqn string) (lom *core.LOM) { 635 // Prepares a basic lom with a copy 636 createTestFile(fqn, testFileSize) 637 lom = &core.LOM{} 638 err := lom.InitFQN(fqn, nil) 639 640 lom.SetSize(int64(testFileSize)) 641 lom.SetVersion(desiredVersion) 642 Expect(persist(lom)).NotTo(HaveOccurred()) 643 lom.UncacheUnless() 644 Expect(err).NotTo(HaveOccurred()) 645 err = lom.Load(false, false) 646 Expect(err).NotTo(HaveOccurred()) 647 Expect(lom.ValidateContentChecksum()).NotTo(HaveOccurred()) 648 return 649 } 650 651 prepareCopy := func(lom *core.LOM, fqn string, locked ...bool) (dst *core.LOM) { 652 var ( 653 err error 654 bck = lom.Bck() 655 ) 656 if len(locked) == 0 { 657 lom.Lock(true) 658 defer lom.Unlock(true) 659 } 660 dst, err = lom.Copy2FQN(fqn, make([]byte, testFileSize)) 661 Expect(err).ShouldNot(HaveOccurred()) 662 Expect(dst.FQN).To(BeARegularFile()) 663 Expect(dst.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 664 665 hrwLom := &core.LOM{ObjName: lom.ObjName} 666 Expect(hrwLom.InitBck(bck.Bucket())).NotTo(HaveOccurred()) 667 hrwLom.UncacheUnless() 668 669 // Reload copy, to make sure it is fresh 670 dst = NewBasicLom(dst.FQN) 671 Expect(dst.Load(false, true)).NotTo(HaveOccurred()) 672 Expect(dst.ValidateContentChecksum()).NotTo(HaveOccurred()) 673 hrwLom.UncacheUnless() 674 return 675 } 676 677 checkCopies := func(defaultLOM *core.LOM, copiesFQNs ...string) { 678 expectedHash := getTestFileHash(defaultLOM.FQN) 679 680 for _, copyFQN := range copiesFQNs { 681 copyLOM := NewBasicLom(copyFQN) 682 Expect(copyLOM.Load(false, true)).NotTo(HaveOccurred()) 683 684 _, cksumValue := copyLOM.Checksum().Get() 685 Expect(cksumValue).To(Equal(expectedHash)) 686 Expect(copyLOM.Version()).To(Equal(desiredVersion)) 687 Expect(copyLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 688 689 Expect(copyLOM.IsCopy()).To(Equal(copyFQN != defaultLOM.FQN)) 690 Expect(copyLOM.HasCopies()).To(BeTrue()) 691 Expect(copyLOM.NumCopies()).To(Equal(len(copiesFQNs))) 692 for _, cfqn := range copiesFQNs { 693 Expect(copyLOM.GetCopies()).To(HaveKey(cfqn)) 694 } 695 696 // Check that the content of the copy is correct. 697 copyObjHash := getTestFileHash(copyFQN) 698 Expect(copyObjHash).To(BeEquivalentTo(expectedHash)) 699 } 700 } 701 702 Describe("CopyObject", func() { 703 It("should successfully copy the object", func() { 704 lom := prepareLOM(copyFQNs[0]) 705 copyLOM := prepareCopy(lom, copyFQNs[1]) 706 expectedHash := getTestFileHash(lom.FQN) 707 708 lom.Lock(false) 709 defer lom.Unlock(false) 710 // Check that no copies were added to metadata 711 Expect(lom.IsCopy()).To(BeFalse()) 712 Expect(lom.HasCopies()).To(BeFalse()) 713 Expect(lom.NumCopies()).To(Equal(1)) 714 Expect(lom.GetCopies()).To(BeNil()) 715 716 // Check copy created 717 Expect(copyLOM.FQN).NotTo(Equal(lom.FQN)) 718 _, cksumValue := copyLOM.Checksum().Get() 719 Expect(cksumValue).To(Equal(expectedHash)) 720 Expect(copyLOM.Version()).To(Equal(desiredVersion)) 721 Expect(copyLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 722 Expect(copyLOM.IsCopy()).To(BeFalse()) 723 Expect(copyLOM.HasCopies()).To(BeFalse()) 724 Expect(copyLOM.NumCopies()).To(Equal(1)) 725 Expect(copyLOM.GetCopies()).To(BeNil()) 726 727 // Check copy contents are correct 728 copyObjHash := getTestFileHash(copyFQNs[1]) 729 Expect(copyObjHash).To(BeEquivalentTo(expectedHash)) 730 }) 731 732 It("should successfully copy the object in case it is mirror copy", func() { 733 lom := prepareLOM(mirrorFQNs[0]) 734 copyLOM := prepareCopy(lom, mirrorFQNs[1]) 735 expectedHash := getTestFileHash(lom.FQN) 736 737 // Check that copies were added to metadata 738 lom.Lock(false) 739 defer lom.Unlock(false) 740 Expect(lom.IsCopy()).To(BeFalse()) 741 Expect(lom.HasCopies()).To(BeTrue()) 742 Expect(lom.NumCopies()).To(Equal(2)) 743 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 744 745 // Check copy created 746 Expect(copyLOM.FQN).NotTo(Equal(lom.FQN)) 747 _, cksumValue := copyLOM.Checksum().Get() 748 Expect(cksumValue).To(Equal(expectedHash)) 749 Expect(copyLOM.Version()).To(Equal(desiredVersion)) 750 Expect(copyLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 751 752 Expect(copyLOM.IsCopy()).To(BeTrue()) 753 Expect(copyLOM.HasCopies()).To(BeTrue()) 754 Expect(copyLOM.NumCopies()).To(Equal(lom.NumCopies())) 755 Expect(copyLOM.GetCopies()).To(Equal(lom.GetCopies())) 756 757 // Check that the content of the copy is correct. 758 copyObjHash := getTestFileHash(mirrorFQNs[1]) 759 Expect(copyObjHash).To(BeEquivalentTo(expectedHash)) 760 }) 761 762 It("should successfully copy the object and update metadata for other copies", func() { 763 lom := prepareLOM(mirrorFQNs[0]) 764 lom.Lock(true) 765 defer lom.Unlock(true) 766 _ = prepareCopy(lom, mirrorFQNs[1], true) 767 _ = prepareCopy(lom, mirrorFQNs[2], true) 768 769 // Check that copies were added to metadata. 770 Expect(lom.IsCopy()).To(BeFalse()) 771 Expect(lom.HasCopies()).To(BeTrue()) 772 Expect(lom.NumCopies()).To(Equal(3)) 773 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]), HaveKey(mirrorFQNs[2]))) 774 775 // Check metadata of created copies (it also checks default object). 776 checkCopies(lom, mirrorFQNs[0], mirrorFQNs[1], mirrorFQNs[2]) 777 }) 778 779 It("should check for missing copies during `syncMetaWithCopies`", func() { 780 lom := prepareLOM(mirrorFQNs[0]) 781 lom.Lock(true) 782 defer lom.Unlock(true) 783 _ = prepareCopy(lom, mirrorFQNs[1], true) 784 785 // Check that copies were added to metadata. 786 Expect(lom.IsCopy()).To(BeFalse()) 787 Expect(lom.HasCopies()).To(BeTrue()) 788 Expect(lom.NumCopies()).To(Equal(2)) 789 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 790 791 // Make one copy disappear. 792 cos.RemoveFile(mirrorFQNs[1]) 793 794 // Prepare another one (to trigger `syncMetaWithCopies`). 795 _ = prepareCopy(lom, mirrorFQNs[2], true) 796 797 // Check metadata of left copies (it also checks default object). 798 checkCopies(lom, mirrorFQNs[0], mirrorFQNs[2]) 799 }) 800 801 It("should copy object without adding it to copies if dst bucket does not support mirroring", func() { 802 lom := prepareLOM(mirrorFQNs[0]) 803 _ = prepareCopy(lom, mirrorFQNs[1]) 804 nonMirroredLOM := prepareCopy(lom, copyFQNs[0]) 805 expectedHash := getTestFileHash(lom.FQN) 806 807 // Check that copies were added to metadata. 808 lom.Lock(false) 809 defer lom.Unlock(false) 810 Expect(lom.IsCopy()).To(BeFalse()) 811 Expect(lom.HasCopies()).To(BeTrue()) 812 Expect(lom.NumCopies()).To(Equal(2)) 813 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 814 815 // Check that nothing has changed in the src. 816 Expect(lom.IsCopy()).To(BeFalse()) 817 Expect(lom.HasCopies()).To(BeTrue()) 818 Expect(lom.NumCopies()).To(Equal(2)) 819 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 820 821 // Check destination lom. 822 nonMirroredLOM.Lock(false) 823 defer nonMirroredLOM.Unlock(false) 824 Expect(nonMirroredLOM.FQN).NotTo(Equal(lom.FQN)) 825 _, cksumValue := nonMirroredLOM.Checksum().Get() 826 Expect(cksumValue).To(Equal(expectedHash)) 827 Expect(nonMirroredLOM.Version()).To(Equal("1")) 828 Expect(nonMirroredLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 829 830 Expect(nonMirroredLOM.IsCopy()).To(BeFalse()) 831 Expect(nonMirroredLOM.HasCopies()).To(BeFalse()) 832 Expect(nonMirroredLOM.NumCopies()).To(Equal(1)) 833 Expect(nonMirroredLOM.GetCopies()).To(BeNil()) 834 835 // Check that the content of the copy is correct. 836 copyObjHash := getTestFileHash(nonMirroredLOM.FQN) 837 Expect(copyObjHash).To(BeEquivalentTo(expectedHash)) 838 }) 839 840 // This test case can happen when we rename object to some different name. 841 It("should not count object as mirror/copy if new object has different name", func() { 842 lom := prepareLOM(mirrorFQNs[0]) 843 copyLOM := prepareCopy(lom, renamedObjFQN) 844 expectedHash := getTestFileHash(lom.FQN) 845 846 // Check that no copies were added to metadata. 847 lom.Lock(false) 848 defer lom.Unlock(false) 849 Expect(lom.IsCopy()).To(BeFalse()) 850 Expect(lom.IsHRW()).To(BeTrue()) 851 Expect(lom.HasCopies()).To(BeFalse()) 852 Expect(lom.NumCopies()).To(Equal(1)) 853 Expect(lom.GetCopies()).To(BeNil()) 854 855 // Check copy created. 856 copyLOM.Lock(false) 857 defer copyLOM.Unlock(false) 858 Expect(copyLOM.FQN).NotTo(Equal(lom.FQN)) 859 _, cksumValue := copyLOM.Checksum().Get() 860 Expect(cksumValue).To(Equal(expectedHash)) 861 Expect(copyLOM.Version()).To(Equal(desiredVersion)) // TODO: ??? 862 Expect(copyLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 863 Expect(copyLOM.IsHRW()).To(BeTrue()) 864 Expect(copyLOM.IsCopy()).To(BeFalse()) 865 Expect(copyLOM.HasCopies()).To(BeFalse()) 866 Expect(copyLOM.NumCopies()).To(Equal(1)) 867 Expect(copyLOM.GetCopies()).To(BeNil()) 868 }) 869 870 // This test case can happen when user adds new mountpath and all existing 871 // copies become non-HRW and now we need to create a HRW object. 872 It("should copy object if mirroring the non-HRW object to HRW object", func() { 873 copyLOM := prepareLOM(mirrorFQNs[1]) 874 // Recreate main/HRW object from the copy. 875 lom := prepareCopy(copyLOM, mirrorFQNs[0]) 876 877 // Check that HRW object was created correctly. 878 lom.Lock(false) 879 defer lom.Unlock(false) 880 Expect(lom.IsCopy()).To(BeFalse()) 881 Expect(lom.HasCopies()).To(BeTrue()) 882 Expect(lom.NumCopies()).To(Equal(2)) 883 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 884 Expect(lom.Version()).To(Equal(desiredVersion)) 885 Expect(lom.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 886 887 // Check that copy from which HRW object was created is also updated. 888 Expect(copyLOM.FQN).NotTo(Equal(lom.FQN)) 889 Expect(copyLOM.Version()).To(Equal(desiredVersion)) 890 Expect(copyLOM.SizeBytes(true)).To(BeEquivalentTo(testFileSize)) 891 Expect(copyLOM.IsCopy()).To(BeTrue()) 892 Expect(copyLOM.HasCopies()).To(BeTrue()) 893 Expect(copyLOM.NumCopies()).To(Equal(lom.NumCopies())) 894 Expect(copyLOM.GetCopies()).To(Equal(lom.GetCopies())) 895 }) 896 }) 897 898 Describe("DelCopies", func() { 899 It("should delete mirrored copy", func() { 900 lom := prepareLOM(mirrorFQNs[0]) 901 _ = prepareCopy(lom, mirrorFQNs[1]) 902 903 // Check that no copies were added to metadata. 904 lom.Lock(false) 905 defer lom.Unlock(false) 906 Expect(lom.IsCopy()).To(BeFalse()) 907 Expect(lom.HasCopies()).To(BeTrue()) 908 Expect(lom.NumCopies()).To(Equal(2)) 909 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]))) 910 911 // Delete copy and check if it's gone. 912 Expect(lom.DelCopies(mirrorFQNs[1])).ToNot(HaveOccurred()) 913 Expect(persist(lom)).ToNot(HaveOccurred()) 914 Expect(mirrorFQNs[1]).NotTo(BeAnExistingFile()) 915 916 // Reload default object and check if the lom was correctly updated. 917 lom = NewBasicLom(mirrorFQNs[0]) 918 Expect(lom.Load(false, true)).ToNot(HaveOccurred()) 919 Expect(lom.IsCopy()).To(BeFalse()) 920 Expect(lom.HasCopies()).To(BeFalse()) 921 Expect(lom.NumCopies()).To(Equal(1)) 922 Expect(lom.GetCopies()).To(BeNil()) 923 }) 924 925 It("should delete mirrored copy and update other copies", func() { 926 lom := prepareLOM(mirrorFQNs[0]) 927 _ = prepareCopy(lom, mirrorFQNs[1]) 928 _ = prepareCopy(lom, mirrorFQNs[2]) 929 expectedHash := getTestFileHash(lom.FQN) 930 931 // Check that copies were added to metadata. 932 lom.Lock(true) 933 defer lom.Unlock(true) 934 Expect(lom.IsCopy()).To(BeFalse()) 935 Expect(lom.HasCopies()).To(BeTrue()) 936 Expect(lom.NumCopies()).To(Equal(3)) 937 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]), HaveKey(mirrorFQNs[2]))) 938 939 // Delete copy and check if it's gone. 940 Expect(lom.DelCopies(mirrorFQNs[1])).ToNot(HaveOccurred()) 941 Expect(persist(lom)).ToNot(HaveOccurred()) 942 Expect(mirrorFQNs[1]).NotTo(BeAnExistingFile()) 943 944 // Reload default object and check if the lom was correctly updated. 945 lom = NewBasicLom(mirrorFQNs[0]) 946 Expect(lom.Load(false, true)).ToNot(HaveOccurred()) 947 Expect(lom.IsCopy()).To(BeFalse()) 948 Expect(lom.HasCopies()).To(BeTrue()) 949 Expect(lom.NumCopies()).To(Equal(2)) 950 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[2]))) 951 952 // Check that left copy was correctly updated. 953 copyLOM := NewBasicLom(mirrorFQNs[2]) 954 Expect(copyLOM.Load(false, true)).NotTo(HaveOccurred()) 955 _, cksumValue := copyLOM.Checksum().Get() 956 Expect(cksumValue).To(Equal(expectedHash)) 957 Expect(copyLOM.Version()).To(Equal(desiredVersion)) 958 Expect(copyLOM.SizeBytes()).To(BeEquivalentTo(testFileSize)) 959 960 Expect(copyLOM.IsCopy()).To(BeTrue()) 961 Expect(copyLOM.HasCopies()).To(BeTrue()) 962 Expect(copyLOM.NumCopies()).To(Equal(lom.NumCopies())) 963 Expect(copyLOM.GetCopies()).To(Equal(lom.GetCopies())) 964 }) 965 }) 966 967 Describe("DelAllCopies", func() { 968 It("should be able to delete all copies", func() { 969 lom := prepareLOM(mirrorFQNs[0]) 970 _ = prepareCopy(lom, mirrorFQNs[1]) 971 _ = prepareCopy(lom, mirrorFQNs[2]) 972 973 // Sanity check for default object. 974 lom.Lock(false) 975 defer lom.Unlock(false) 976 Expect(lom.IsCopy()).To(BeFalse()) 977 Expect(lom.HasCopies()).To(BeTrue()) 978 Expect(lom.NumCopies()).To(Equal(3)) 979 Expect(lom.GetCopies()).To(And(HaveKey(mirrorFQNs[0]), HaveKey(mirrorFQNs[1]), HaveKey(mirrorFQNs[2]))) 980 981 // Delete all copies and check if they are gone. 982 Expect(lom.DelAllCopies()).NotTo(HaveOccurred()) 983 Expect(persist(lom)).ToNot(HaveOccurred()) 984 Expect(mirrorFQNs[1]).NotTo(BeAnExistingFile()) 985 Expect(mirrorFQNs[2]).NotTo(BeAnExistingFile()) 986 987 // Reload default object and see if the lom was correctly updated. 988 lom = NewBasicLom(mirrorFQNs[0]) 989 Expect(lom.Load(false, true)).ToNot(HaveOccurred()) 990 Expect(lom.IsCopy()).To(BeFalse()) 991 Expect(lom.HasCopies()).To(BeFalse()) 992 Expect(lom.NumCopies()).To(Equal(1)) 993 Expect(lom.GetCopies()).To(BeNil()) 994 }) 995 }) 996 }) 997 998 Describe("local and cloud bucket with the same name", func() { 999 It("should have different fqn", func() { 1000 testObject := "foldr/test-obj.ext" 1001 localSameBck := cmn.Bck{Name: sameBucketName, Provider: apc.AIS, Ns: cmn.NsGlobal} 1002 cloudSameBck := cmn.Bck{Name: sameBucketName, Provider: apc.AWS, Ns: cmn.NsGlobal} 1003 desiredLocalFQN := mis[0].MakePathFQN(&localSameBck, fs.ObjectType, testObject) 1004 desiredCloudFQN := mis[0].MakePathFQN(&cloudSameBck, fs.ObjectType, testObject) 1005 1006 fs.Disable(mpaths[1]) // Ensure that it matches desiredCloudFQN 1007 fs.Disable(mpaths[2]) // ditto 1008 1009 lomLocal := &core.LOM{ObjName: testObject} 1010 err := lomLocal.InitBck(&cmn.Bck{Name: sameBucketName, Provider: apc.AIS}) 1011 Expect(err).NotTo(HaveOccurred()) 1012 err = lomLocal.Load(false, false) 1013 Expect(cos.IsNotExist(err, 0)).To(BeTrue()) 1014 Expect(lomLocal.FQN).To(Equal(desiredLocalFQN)) 1015 Expect(lomLocal.Uname()).To(Equal(lomLocal.Bck().MakeUname(testObject))) 1016 Expect(lomLocal.Bck().Provider).To(Equal(apc.AIS)) 1017 Expect(lomLocal.Mountpath().Path).To(Equal(mpaths[0])) 1018 expectEqualBck(lomLocal.Bucket(), &localSameBck) 1019 Expect(lomLocal.ObjName).To(Equal(testObject)) 1020 1021 lomCloud := &core.LOM{ObjName: testObject} 1022 err = lomCloud.InitBck(&cmn.Bck{Name: sameBucketName, Provider: apc.AWS}) 1023 Expect(err).NotTo(HaveOccurred()) 1024 err = lomCloud.Load(false, false) 1025 Expect(cos.IsNotExist(err, 0)).To(BeTrue()) 1026 Expect(lomCloud.FQN).To(Equal(desiredCloudFQN)) 1027 Expect(lomCloud.Uname()).To(Equal(lomCloud.Bck().MakeUname(testObject))) 1028 Expect(lomCloud.Bck().Provider).To(Equal(apc.AWS)) 1029 Expect(lomCloud.Mountpath().Path).To(Equal(mpaths[0])) 1030 expectEqualBck(lomCloud.Bucket(), &cloudSameBck) 1031 Expect(lomCloud.ObjName).To(Equal(testObject)) 1032 1033 fs.Enable(mpaths[1]) 1034 fs.Enable(mpaths[2]) 1035 }) 1036 }) 1037 }) 1038 1039 // 1040 // HELPERS 1041 // 1042 1043 // needs to be called inside of gomega scope like Describe/It 1044 func NewBasicLom(fqn string) *core.LOM { 1045 lom := &core.LOM{} 1046 err := lom.InitFQN(fqn, nil) 1047 Expect(err).NotTo(HaveOccurred()) 1048 return lom 1049 } 1050 1051 func filePut(fqn string, size int) *core.LOM { 1052 createTestFile(fqn, size) 1053 lom := NewBasicLom(fqn) 1054 lom.SetSize(int64(size)) 1055 lom.IncVersion() 1056 Expect(persist(lom)).NotTo(HaveOccurred()) 1057 lom.UncacheUnless() 1058 return lom 1059 } 1060 1061 func createTestFile(fqn string, size int) { 1062 _ = os.Remove(fqn) 1063 testFile, err := cos.CreateFile(fqn) 1064 Expect(err).ShouldNot(HaveOccurred()) 1065 1066 if size > 0 { 1067 buff := make([]byte, size) 1068 _, _ = cryptorand.Read(buff) 1069 _, err := testFile.Write(buff) 1070 _ = testFile.Close() 1071 1072 Expect(err).ShouldNot(HaveOccurred()) 1073 } 1074 } 1075 1076 func getTestFileHash(fqn string) (hash string) { 1077 reader, _ := os.Open(fqn) 1078 _, cksum, err := cos.CopyAndChecksum(io.Discard, reader, nil, cos.ChecksumXXHash) 1079 Expect(err).NotTo(HaveOccurred()) 1080 hash = cksum.Value() 1081 reader.Close() 1082 return 1083 } 1084 1085 func expectEqualBck(left, right *cmn.Bck) { 1086 p := right.Props 1087 right.Props = left.Props 1088 _ = Expect(left).To(Equal(right)) 1089 right.Props = p 1090 } 1091 1092 func persist(lom *core.LOM) error { 1093 if lom.AtimeUnix() == 0 { 1094 lom.SetAtimeUnix(time.Now().UnixNano()) 1095 } 1096 return lom.Persist() 1097 }