Files
containerd/metadata/content_test.go
Derek McGowan 0d8b093361 metadata: add content lease on existing content
When a writer is requested for an object that already
exists, add that object to the provided any lease to prevent
other operations from affecting the current lease's use of
that content.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2018-01-09 14:33:30 -08:00

113 lines
2.9 KiB
Go

package metadata
import (
"bytes"
"context"
"path/filepath"
"testing"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
"github.com/containerd/containerd/content/testsuite"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/leases"
"github.com/containerd/containerd/namespaces"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
func createContentStore(ctx context.Context, root string) (content.Store, func() error, error) {
// TODO: Use mocked or in-memory store
cs, err := local.NewStore(root)
if err != nil {
return nil, nil, err
}
db, err := bolt.Open(filepath.Join(root, "metadata.db"), 0660, nil)
if err != nil {
return nil, nil, err
}
return NewDB(db, cs, nil).ContentStore(), func() error {
return db.Close()
}, nil
}
func TestContent(t *testing.T) {
testsuite.ContentSuite(t, "metadata", createContentStore)
}
func TestContentLeased(t *testing.T) {
ctx, db, cancel := testDB(t)
defer cancel()
cs := db.ContentStore()
blob := []byte("any content")
expected := digest.FromBytes(blob)
lctx, _, err := createLease(ctx, db, "lease-1")
if err != nil {
t.Fatal(err)
}
if err := content.WriteBlob(lctx, cs, "test-1", bytes.NewReader(blob), int64(len(blob)), expected); err != nil {
t.Fatal(err)
}
if err := checkContentLeased(lctx, db, expected); err != nil {
t.Fatal("lease checked failed:", err)
}
lctx, _, err = createLease(ctx, db, "lease-2")
if err != nil {
t.Fatal(err)
}
if _, err := cs.Writer(lctx, "test-2", int64(len(blob)), expected); err == nil {
t.Fatal("expected already exist error")
} else if !errdefs.IsAlreadyExists(err) {
t.Fatal(err)
}
if err := checkContentLeased(lctx, db, expected); err != nil {
t.Fatal("lease checked failed:", err)
}
}
func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) {
if err := db.Update(func(tx *bolt.Tx) error {
_, err := NewLeaseManager(tx).Create(ctx, name, nil)
return err
}); err != nil {
return nil, nil, err
}
return leases.WithLease(ctx, name), func() error {
return db.Update(func(tx *bolt.Tx) error {
return NewLeaseManager(tx).Delete(ctx, name)
})
}, nil
}
func checkContentLeased(ctx context.Context, db *DB, dgst digest.Digest) error {
ns, ok := namespaces.Namespace(ctx)
if !ok {
return errors.New("no namespace in context")
}
lease, ok := leases.Lease(ctx)
if !ok {
return errors.New("no lease in context")
}
return db.View(func(tx *bolt.Tx) error {
bkt := getBucket(tx, bucketKeyVersion, []byte(ns), bucketKeyObjectLeases, []byte(lease), bucketKeyObjectContent)
if bkt == nil {
return errors.Wrapf(errdefs.ErrNotFound, "bucket not found", lease)
}
v := bkt.Get([]byte(dgst.String()))
if v == nil {
return errors.Wrap(errdefs.ErrNotFound, "object not leased")
}
return nil
})
}