func (t *ConnTest) BucketsAreSegregatedByName() { const objName = "baz" var contents []byte var err error b0, err := t.conn.OpenBucket(t.ctx, "foo") AssertEq(nil, err) b1, err := t.conn.OpenBucket(t.ctx, "bar") AssertEq(nil, err) // Add an object with the same name but different contents to each of two // buckets. _, err = gcsutil.CreateObject(t.ctx, b0, objName, []byte("taco")) AssertEq(nil, err) _, err = gcsutil.CreateObject(t.ctx, b1, objName, []byte("burrito")) AssertEq(nil, err) // Each should have stored it independently. contents, err = gcsutil.ReadObject(t.ctx, b0, objName) AssertEq(nil, err) ExpectEq("taco", string(contents)) contents, err = gcsutil.ReadObject(t.ctx, b1, objName) AssertEq(nil, err) ExpectEq("burrito", string(contents)) }
func (t *IntegrationTest) BackingObjectHasBeenOverwritten_BeforeReading() { // Create an object, then create the mutable object wrapper around it. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Overwrite the GCS object. _, err = gcsutil.CreateObject(t.ctx, t.bucket, "foo", "burrito") AssertEq(nil, err) // Sync doesn't need to do anything. rl, newObj, err := t.sync(o) AssertEq(nil, err) ExpectEq(nil, rl) ExpectEq(nil, newObj) // Anything that needs to fault in the contents should fail. _, err = t.mc.ReadAt(t.ctx, []byte{}, 0) ExpectThat(err, Error(HasSubstr("not found"))) err = t.mc.Truncate(t.ctx, 10) ExpectThat(err, Error(HasSubstr("not found"))) _, err = t.mc.WriteAt(t.ctx, []byte{}, 0) ExpectThat(err, Error(HasSubstr("not found"))) }
func (t *DirTest) CloneToChildFile_DestinationExists() { const srcName = "blah/baz" dstName := path.Join(dirInodeName, "qux") var o *gcs.Object var err error // Create the source. src, err := gcsutil.CreateObject(t.ctx, t.bucket, srcName, []byte("taco")) AssertEq(nil, err) // And a destination object that will be overwritten. _, err = gcsutil.CreateObject(t.ctx, t.bucket, dstName, []byte("")) AssertEq(nil, err) // Call the inode. o, err = t.in.CloneToChildFile(t.ctx, path.Base(dstName), src) AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dstName, o.Name) ExpectFalse(inode.IsSymlink(o)) ExpectEq(len("taco"), o.Size) // Check resulting contents. contents, err := gcsutil.ReadObject(t.ctx, t.bucket, dstName) AssertEq(nil, err) ExpectEq("taco", string(contents)) }
func (t *DirTest) LookUpChild_ImplicitDirOnly_Enabled() { const name = "qux" objName := path.Join(dirInodeName, name) + "/" var err error // Enable implicit dirs. t.resetInode(true) // Create an object that implicitly defines the directory. otherObjName := path.Join(objName, "asdf") _, err = gcsutil.CreateObject(t.ctx, t.bucket, otherObjName, []byte("")) AssertEq(nil, err) // Looking up the name should work. result, err := t.in.LookUpChild(t.ctx, name) AssertEq(nil, err) ExpectEq(nil, result.Object) ExpectEq(objName, result.FullName) ExpectTrue(result.ImplicitDir) // A conflict marker should not work. result, err = t.in.LookUpChild(t.ctx, name+inode.ConflictingFileNameSuffix) AssertEq(nil, err) ExpectFalse(result.Exists()) }
func (t *DirTest) LookUpChild_DirOnly() { const name = "qux" objName := path.Join(dirInodeName, name) + "/" var o *gcs.Object var err error // Create a backing object. createObj, err := gcsutil.CreateObject(t.ctx, t.bucket, objName, []byte("")) AssertEq(nil, err) // Look up with the proper name. result, err := t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(objName, result.FullName) ExpectEq(objName, o.Name) ExpectEq(createObj.Generation, o.Generation) ExpectEq(createObj.Size, o.Size) // A conflict marker name shouldn't work. result, err = t.in.LookUpChild(t.ctx, name+inode.ConflictingFileNameSuffix) AssertEq(nil, err) ExpectFalse(result.Exists()) }
func (t *PrefixBucketTest) DeleteObject() { var err error suffix := "taco" name := t.prefix + suffix contents := "foobar" // Create an object through the back door. _, err = gcsutil.CreateObject(t.ctx, t.wrapped, name, []byte(contents)) AssertEq(nil, err) // Delete it. err = t.bucket.DeleteObject( t.ctx, &gcs.DeleteObjectRequest{ Name: suffix, }) AssertEq(nil, err) // It should be gone. _, err = t.wrapped.StatObject( t.ctx, &gcs.StatObjectRequest{ Name: name, }) ExpectThat(err, HasSameTypeAs(&gcs.NotFoundError{})) }
func (t *FileTest) SetMtime_SourceObjectGenerationChanged() { var err error // Clobber the backing object. newObj, err := gcsutil.CreateObject( t.ctx, t.bucket, t.in.Name(), []byte("burrito")) AssertEq(nil, err) // Set mtime. mtime := time.Now().UTC().Add(123 * time.Second) err = t.in.SetMtime(t.ctx, mtime) AssertEq(nil, err) // The object in the bucket should not have been changed. statReq := &gcs.StatObjectRequest{Name: t.in.Name()} o, err := t.bucket.StatObject(t.ctx, statReq) AssertEq(nil, err) ExpectEq(newObj.Generation, o.Generation) ExpectEq(0, len(o.Metadata)) }
func (t *IntegrationTest) WithinLeaserLimit() { AssertLt(len("taco"), fileLeaserLimitBytes) // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Extend to be up against the leaser limit, then write out to GCS, which // should downgrade to a read lease. err = t.mc.Truncate(t.ctx, fileLeaserLimitBytes) AssertEq(nil, err) rl, _, err := t.sync(o) AssertEq(nil, err) // The backing object should be present and contain the correct contents. contents, err := gcsutil.ReadObject(t.ctx, t.bucket, o.Name) AssertEq(nil, err) ExpectEq(fileLeaserLimitBytes, len(contents)) // Delete the backing object. err = t.bucket.DeleteObject(t.ctx, &gcs.DeleteObjectRequest{Name: o.Name}) AssertEq(nil, err) // We should still be able to read the contents, because the read lease // should still be valid. buf := make([]byte, 4) n, err := rl.ReadAt(buf, 0) AssertEq(nil, err) ExpectEq("taco", string(buf[0:n])) }
func (t *IntegrationTest) TruncateThenSync() { // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Truncate. err = t.mc.Truncate(t.ctx, 2) AssertEq(nil, err) // Sync should save out the new generation. rl, newObj, err := t.sync(o) AssertEq(nil, err) ExpectNe(o.Generation, newObj.Generation) ExpectEq(t.objectGeneration("foo"), newObj.Generation) contents, err := gcsutil.ReadObject(t.ctx, t.bucket, "foo") AssertEq(nil, err) ExpectEq("ta", string(contents)) // Read via the lease. _, err = rl.Seek(0, 0) AssertEq(nil, err) contents, err = ioutil.ReadAll(rl) AssertEq(nil, err) ExpectEq("ta", string(contents)) }
func (t *PrefixBucketTest) CopyObject() { var err error suffix := "taco" name := t.prefix + suffix contents := "foobar" // Create an object through the back door. _, err = gcsutil.CreateObject(t.ctx, t.wrapped, name, []byte(contents)) AssertEq(nil, err) // Copy it to a new name. newSuffix := "burrito" o, err := t.bucket.CopyObject( t.ctx, &gcs.CopyObjectRequest{ SrcName: suffix, DstName: newSuffix, }) AssertEq(nil, err) ExpectEq(newSuffix, o.Name) // Read it through the back door. actual, err := gcsutil.ReadObject(t.ctx, t.wrapped, t.prefix+newSuffix) AssertEq(nil, err) ExpectEq(contents, string(actual)) }
func (t *IntegrationTest) LargerThanLeaserLimit() { AssertLt(len("taco"), fileLeaserLimitBytes) // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Extend to be past the leaser limit, then write out to GCS, which should // downgrade to a read lease. err = t.mc.Truncate(t.ctx, fileLeaserLimitBytes+1) AssertEq(nil, err) rl, _, err := t.sync(o) AssertEq(nil, err) // The backing object should be present and contain the correct contents. contents, err := gcsutil.ReadObject(t.ctx, t.bucket, o.Name) AssertEq(nil, err) ExpectEq(fileLeaserLimitBytes+1, len(contents)) // Delete the backing object. err = t.bucket.DeleteObject(t.ctx, &gcs.DeleteObjectRequest{Name: o.Name}) AssertEq(nil, err) // The contents should be lost, because the leaser should have revoked the // read lease. _, err = rl.ReadAt(make([]byte, len(contents)), 0) ExpectThat(err, Error(HasSubstr("revoked"))) }
func (t *IntegrationTest) UpdateUpdatesCache() { const name = "taco" var err error // Create an object through the back door. _, err = gcsutil.CreateObject(t.ctx, t.wrapped, name, []byte{}) AssertEq(nil, err) // Update it, putting the new version in cache. updateReq := &gcs.UpdateObjectRequest{ Name: name, } _, err = t.bucket.UpdateObject(t.ctx, updateReq) AssertEq(nil, err) // Delete the object through the back door. err = t.wrapped.DeleteObject(t.ctx, &gcs.DeleteObjectRequest{Name: name}) AssertEq(nil, err) // StatObject should still see it. o, err := t.stat(name) AssertEq(nil, err) ExpectNe(nil, o) }
func (t *IntegrationTest) BackingObjectHasBeenDeleted_BeforeReading() { // Create an object to obtain a record, then delete it. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) err = t.bucket.DeleteObject(t.ctx, &gcs.DeleteObjectRequest{Name: o.Name}) AssertEq(nil, err) // Create a mutable object around it. t.create(o) // Sync doesn't need to do anything. rl, newObj, err := t.sync(o) AssertEq(nil, err) ExpectEq(nil, rl) ExpectEq(nil, newObj) // Anything that needs to fault in the contents should fail. _, err = t.mc.ReadAt(t.ctx, []byte{}, 0) ExpectThat(err, Error(HasSubstr("not found"))) err = t.mc.Truncate(t.ctx, 10) ExpectThat(err, Error(HasSubstr("not found"))) _, err = t.mc.WriteAt(t.ctx, []byte{}, 0) ExpectThat(err, Error(HasSubstr("not found"))) }
func (t *IntegrationTest) TruncateThenSync() { // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", []byte("taco")) AssertEq(nil, err) t.create(o) // Truncate. t.clock.AdvanceTime(time.Second) truncateTime := t.clock.Now() err = t.tf.Truncate(2) t.clock.AdvanceTime(time.Second) AssertEq(nil, err) // Sync should save out the new generation. newObj, err := t.sync(o) AssertEq(nil, err) ExpectNe(o.Generation, newObj.Generation) ExpectEq(t.objectGeneration("foo"), newObj.Generation) ExpectEq( truncateTime.UTC().Format(time.RFC3339Nano), newObj.Metadata["gcsfuse_mtime"]) contents, err := gcsutil.ReadObject(t.ctx, t.bucket, "foo") AssertEq(nil, err) ExpectEq("ta", string(contents)) }
func (t *IntegrationTest) UpdateInvalidatesNegativeCache() { const name = "taco" var err error // Stat an unknown object, getting it into the negative cache. _, err = t.stat(name) AssertThat(err, HasSameTypeAs(&gcs.NotFoundError{})) // Create the object through the back door. _, err = gcsutil.CreateObject(t.ctx, t.wrapped, name, []byte{}) AssertEq(nil, err) // Update the object. updateReq := &gcs.UpdateObjectRequest{ Name: name, } _, err = t.bucket.UpdateObject(t.ctx, updateReq) AssertEq(nil, err) // Now StatObject should see it. o, err := t.stat(name) AssertEq(nil, err) ExpectNe(nil, o) }
func (t *FileTest) Sync_Clobbered() { var err error // Truncate downward. err = t.in.Truncate(t.ctx, 2) AssertEq(nil, err) // Clobber the backing object. newObj, err := gcsutil.CreateObject( t.ctx, t.bucket, t.in.Name(), []byte("burrito")) AssertEq(nil, err) // Sync. The call should succeed, but nothing should change. err = t.in.Sync(t.ctx) AssertEq(nil, err) ExpectEq(t.backingObj.Generation, t.in.SourceGeneration().Object) ExpectEq(t.backingObj.MetaGeneration, t.in.SourceGeneration().Metadata) // The object in the bucket should not have been changed. statReq := &gcs.StatObjectRequest{Name: t.in.Name()} o, err := t.bucket.StatObject(t.ctx, statReq) AssertEq(nil, err) ExpectEq(newObj.Generation, o.Generation) ExpectEq(newObj.Size, o.Size) }
func (t *ConnTest) BucketContentsAreStable() { const bucketName = "foo" const objName = "bar" var err error // Open the bucket. bucket, err := t.conn.OpenBucket(t.ctx, bucketName) AssertEq(nil, err) // Add an object to a bucket. _, err = gcsutil.CreateObject( t.ctx, bucket, objName, []byte("taco")) AssertEq(nil, err) // Grab the bucket again. It should still be there. contents, err := gcsutil.ReadObject( t.ctx, bucket, objName) AssertEq(nil, err) ExpectEq("taco", string(contents)) }
func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Enabled() { const name = "qux" fileObjName := path.Join(dirInodeName, name) dirObjName := path.Join(dirInodeName, name) + "/" var o *gcs.Object var err error // Enable implicit dirs. t.resetInode(true) // Create backing objects. fileObj, err := gcsutil.CreateObject(t.ctx, t.bucket, fileObjName, []byte("taco")) AssertEq(nil, err) dirObj, err := gcsutil.CreateObject(t.ctx, t.bucket, dirObjName, []byte("")) AssertEq(nil, err) // Create an object that implicitly defines the directory. otherObjName := path.Join(dirInodeName, name) + "/asdf" _, err = gcsutil.CreateObject(t.ctx, t.bucket, otherObjName, []byte("")) AssertEq(nil, err) // Look up with the proper name. result, err := t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dirObjName, result.FullName) ExpectEq(dirObjName, o.Name) ExpectEq(dirObj.Generation, o.Generation) ExpectEq(dirObj.Size, o.Size) // Look up with the conflict marker name. result, err = t.in.LookUpChild(t.ctx, name+inode.ConflictingFileNameSuffix) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(fileObjName, result.FullName) ExpectEq(fileObjName, o.Name) ExpectEq(fileObj.Generation, o.Generation) ExpectEq(fileObj.Size, o.Size) }
func (t *DirTest) LookUpChild_TypeCaching() { const name = "qux" fileObjName := path.Join(dirInodeName, name) dirObjName := path.Join(dirInodeName, name) + "/" var o *gcs.Object var err error // Create a backing object for a file. _, err = gcsutil.CreateObject(t.ctx, t.bucket, fileObjName, []byte("taco")) AssertEq(nil, err) // Look up; we should get the file. result, err := t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(fileObjName, o.Name) // Create a backing object for a directory. _, err = gcsutil.CreateObject(t.ctx, t.bucket, dirObjName, []byte("taco")) AssertEq(nil, err) // Look up again. Even though the directory should shadow the file, because // we've cached only seeing the file that's what we should get back. result, err = t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(fileObjName, o.Name) // But after the TTL expires, the behavior should flip. t.clock.AdvanceTime(typeCacheTTL + time.Millisecond) result, err = t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dirObjName, o.Name) }
func (t *IntegrationTest) BackingObjectHasBeenOverwritten_AfterReading() { // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Fault in the contents. _, err = t.mc.ReadAt(t.ctx, []byte{}, 0) AssertEq(nil, err) // Overwrite the backing object. _, err = gcsutil.CreateObject(t.ctx, t.bucket, "foo", "burrito") AssertEq(nil, err) // Reading and modications should still work. _, err = t.mc.ReadAt(t.ctx, []byte{}, 0) AssertEq(nil, err) _, err = t.mc.WriteAt(t.ctx, []byte("a"), 0) AssertEq(nil, err) truncateTime := t.clock.Now() err = t.mc.Truncate(t.ctx, 3) AssertEq(nil, err) t.clock.AdvanceTime(time.Second) // Stat should see the current state. sr, err := t.mc.Stat(t.ctx) AssertEq(nil, err) ExpectEq(3, sr.Size) ExpectEq(0, sr.DirtyThreshold) ExpectThat(sr.Mtime, Pointee(timeutil.TimeEq(truncateTime))) // Sync should fail with a precondition error. _, _, err = t.sync(o) ExpectThat(err, HasSameTypeAs(&gcs.PreconditionError{})) // The newer version should still be present. contents, err := gcsutil.ReadObject(t.ctx, t.bucket, o.Name) AssertEq(nil, err) ExpectEq("burrito", string(contents)) }
func (t *ForeignModsTest) ReadFromFile_Large() { randSrc := rand.New(rand.NewSource(0xdeadbeef)) // Create some random contents. const contentLen = 1 << 22 contents := randBytes(contentLen) // Repeatedly: // // * Create an object with the random contents. // * Read a random range of it. // * Verify the result. // var buf [contentLen]byte runOnce := func() { // Create an object. _, err := gcsutil.CreateObject( t.ctx, t.bucket, "foo", contents) AssertEq(nil, err) // Attempt to open it. f, err := os.Open(path.Join(t.mfs.Dir(), "foo")) AssertEq(nil, err) defer func() { AssertEq(nil, f.Close()) }() // Read part of it. offset := randSrc.Int63n(contentLen + 1) size := randSrc.Intn(int(contentLen - offset)) n, err := f.ReadAt(buf[:size], offset) if offset+int64(size) == contentLen && err == io.EOF { err = nil } AssertEq(nil, err) AssertEq(size, n) AssertTrue( bytes.Equal(contents[offset:offset+int64(size)], buf[:n]), "offset: %d\n"+ "size: %d\n"+ "n: %d", offset, size, n) } start := time.Now() for time.Since(start) < 2*time.Second { runOnce() } }
func (t *DirTest) LookUpChild_SymlinkAndDir() { const name = "qux" linkObjName := path.Join(dirInodeName, name) dirObjName := path.Join(dirInodeName, name) + "/" var o *gcs.Object var err error // Create backing objects. linkObj, err := gcsutil.CreateObject(t.ctx, t.bucket, linkObjName, []byte("taco")) AssertEq(nil, err) err = t.setSymlinkTarget(linkObjName, "blah") AssertEq(nil, err) dirObj, err := gcsutil.CreateObject(t.ctx, t.bucket, dirObjName, []byte("")) AssertEq(nil, err) // Look up with the proper name. result, err := t.in.LookUpChild(t.ctx, name) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dirObjName, result.FullName) ExpectEq(dirObjName, o.Name) ExpectEq(dirObj.Generation, o.Generation) ExpectEq(dirObj.Size, o.Size) // Look up with the conflict marker name. result, err = t.in.LookUpChild(t.ctx, name+inode.ConflictingFileNameSuffix) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(linkObjName, result.FullName) ExpectEq(linkObjName, o.Name) ExpectEq(linkObj.Generation, o.Generation) ExpectEq(linkObj.Size, o.Size) }
func (t *ReadOnlyTest) ModifyFile() { // Create an object in the bucket. _, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) // Opening it for writing should fail. f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) f.Close() ExpectThat(err, Error(HasSubstr("read-only"))) }
func (t *DirTest) CloneToChildFile_TypeCaching() { const srcName = "blah/baz" dstName := path.Join(dirInodeName, "qux") var o *gcs.Object var err error // Create the source. src, err := gcsutil.CreateObject(t.ctx, t.bucket, srcName, []byte("")) AssertEq(nil, err) // Clone to the destination. _, err = t.in.CloneToChildFile(t.ctx, path.Base(dstName), src) AssertEq(nil, err) // Create a backing object for a directory. dirObjName := dstName + "/" _, err = gcsutil.CreateObject(t.ctx, t.bucket, dirObjName, []byte("")) AssertEq(nil, err) // Look up the name. Even though the directory should shadow the file, // because we've cached only seeing the file that's what we should get back. result, err := t.in.LookUpChild(t.ctx, path.Base(dstName)) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dstName, o.Name) // But after the TTL expires, the behavior should flip. t.clock.AdvanceTime(typeCacheTTL + time.Millisecond) result, err = t.in.LookUpChild(t.ctx, path.Base(dstName)) o = result.Object AssertEq(nil, err) AssertNe(nil, o) ExpectEq(dirObjName, o.Name) }
func (t *IntegrationTest) Stat_InitialState() { // Create. o, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) t.create(o) // Stat. sr, err := t.mc.Stat(t.ctx) AssertEq(nil, err) ExpectEq(o.Size, sr.Size) ExpectEq(o.Size, sr.DirtyThreshold) ExpectEq(nil, sr.Mtime) }
func (t *DirTest) CreateChildDir_Exists() { const name = "qux" objName := path.Join(dirInodeName, name) + "/" var err error // Create an existing backing object. _, err = gcsutil.CreateObject(t.ctx, t.bucket, objName, []byte("taco")) AssertEq(nil, err) // Call the inode. _, err = t.in.CreateChildDir(t.ctx, name) ExpectThat(err, Error(HasSubstr("Precondition"))) ExpectThat(err, Error(HasSubstr("exists"))) }
func (t *ReadOnlyTest) DeleteFile() { // Create an object in the bucket. _, err := gcsutil.CreateObject(t.ctx, t.bucket, "foo", "taco") AssertEq(nil, err) // Attempt to delete it via the file system. err = os.Remove(path.Join(t.Dir, "foo")) ExpectThat(err, Error(HasSubstr("read-only"))) // the bucket should not have been modified. contents, err := gcsutil.ReadObject(t.ctx, t.bucket, "foo") AssertEq(nil, err) ExpectEq("taco", string(contents)) }
func (t *IntegrationTest) StatAddsToNegativeCache() { const name = "taco" var err error // Stat an unknown object, getting it into the negative cache. _, err = t.stat(name) AssertThat(err, HasSameTypeAs(&gcs.NotFoundError{})) // Create the object through the back door. _, err = gcsutil.CreateObject(t.ctx, t.wrapped, name, []byte{}) AssertEq(nil, err) // StatObject should still not see it yet. _, err = t.stat(name) ExpectThat(err, HasSameTypeAs(&gcs.NotFoundError{})) }
func (t *DirTest) CreateChildSymlink_Exists() { const name = "qux" const target = "taco" objName := path.Join(dirInodeName, name) var err error // Create an existing backing object. _, err = gcsutil.CreateObject(t.ctx, t.bucket, objName, "") AssertEq(nil, err) // Call the inode. _, err = t.in.CreateChildSymlink(t.ctx, name, target) ExpectThat(err, Error(HasSubstr("Precondition"))) ExpectThat(err, Error(HasSubstr("exists"))) }
func (t *IntegrationTest) CreateInsertsIntoCache() { const name = "taco" var err error // Create an object. _, err = gcsutil.CreateObject(t.ctx, t.bucket, name, []byte{}) AssertEq(nil, err) // Delete it through the back door. err = t.wrapped.DeleteObject(t.ctx, &gcs.DeleteObjectRequest{Name: name}) AssertEq(nil, err) // StatObject should still see it. o, err := t.stat(name) AssertEq(nil, err) ExpectNe(nil, o) }