func TestDelete(t *testing.T) { sto, cleanup := newTempDiskpacked(t) defer cleanup() var ( A = &test.Blob{Contents: "some small blob"} B = &test.Blob{Contents: strings.Repeat("some middle blob", 100)} C = &test.Blob{Contents: strings.Repeat("A 8192 bytes length largish blob", 8192/32)} ) type step func() error stepAdd := func(tb *test.Blob) step { // add the blob return func() error { sb, err := sto.ReceiveBlob(tb.BlobRef(), tb.Reader()) if err != nil { return fmt.Errorf("ReceiveBlob of %s: %v", sb, err) } if sb != tb.SizedRef() { return fmt.Errorf("Received %v; want %v", sb, tb.SizedRef()) } return nil } } stepCheck := func(want ...*test.Blob) step { // check the blob wantRefs := make([]blob.SizedRef, len(want)) for i, tb := range want { wantRefs[i] = tb.SizedRef() } return func() error { if err := storagetest.CheckEnumerate(sto, wantRefs); err != nil { return err } return nil } } stepDelete := func(tb *test.Blob) step { return func() error { if err := sto.RemoveBlobs([]blob.Ref{tb.BlobRef()}); err != nil { return fmt.Errorf("RemoveBlob(%s): %v", tb.BlobRef(), err) } return nil } } var deleteTests = [][]step{ []step{ stepAdd(A), stepDelete(A), stepCheck(), stepAdd(B), stepCheck(B), stepDelete(B), stepCheck(), stepAdd(C), stepCheck(C), stepAdd(A), stepCheck(A, C), stepDelete(A), stepDelete(C), stepCheck(), }, []step{ stepAdd(A), stepAdd(B), stepAdd(C), stepCheck(A, B, C), stepDelete(C), stepCheck(A, B), }, } for i, steps := range deleteTests { for j, s := range steps { if err := s(); err != nil { t.Errorf("error at test %d, step %d: %v", i+1, j+1, err) } } } }
func TestRemoveBlobs(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() // The basic small cases are handled via storagetest in TestStorage, // so this only tests removing packed blobs. small := new(test.Fetcher) large := new(test.Fetcher) sto := &storage{ small: small, large: large, meta: sorted.NewMemoryKeyValue(), log: test.NewLogger(t, "blobpacked: "), } sto.init() const fileSize = 1 << 20 fileContents := randBytes(fileSize) if _, err := schema.WriteFileFromReader(sto, "foo.dat", bytes.NewReader(fileContents)); err != nil { t.Fatal(err) } if small.NumBlobs() != 0 || large.NumBlobs() == 0 { t.Fatalf("small, large counts == %d, %d; want 0, non-zero", small.NumBlobs(), large.NumBlobs()) } var all []blob.SizedRef if err := blobserver.EnumerateAll(ctx, sto, func(sb blob.SizedRef) error { all = append(all, sb) return nil }); err != nil { t.Fatal(err) } // Find the zip zipBlob, err := singleBlob(sto.large) if err != nil { t.Fatalf("failed to find packed zip: %v", err) } // The zip file is in use, so verify we can't delete it. if err := sto.deleteZipPack(zipBlob.Ref); err == nil { t.Fatalf("zip pack blob deleted but it should not have been allowed") } // Delete everything for len(all) > 0 { del := all[0].Ref all = all[1:] if err := sto.RemoveBlobs([]blob.Ref{del}); err != nil { t.Fatalf("RemoveBlobs: %v", err) } if err := storagetest.CheckEnumerate(sto, all); err != nil { t.Fatalf("After deleting %v, %v", del, err) } } dRows := func() (n int) { if err := sorted.ForeachInRange(sto.meta, "d:", "", func(key, value string) error { if strings.HasPrefix(key, "d:") { n++ } return nil }); err != nil { t.Fatalf("meta iteration error: %v", err) } return } if n := dRows(); n == 0 { t.Fatalf("expected a 'd:' row after deletes") } // TODO: test the background pack-deleter loop? figure out its design first. if err := sto.deleteZipPack(zipBlob.Ref); err != nil { t.Errorf("error deleting zip %v: %v", zipBlob.Ref, err) } if n := dRows(); n != 0 { t.Errorf("expected the 'd:' row to be deleted") } }