Add database migrations
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
178
metadata/db_test.go
Normal file
178
metadata/db_test.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
ctx, db, cancel := testEnv(t)
|
||||
defer cancel()
|
||||
|
||||
if err := NewDB(db, nil, nil).Init(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
version, err := readDBVersion(db, bucketKeyVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if version != dbVersion {
|
||||
t.Fatalf("Unexpected version %d, expected %d", version, dbVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrations(t *testing.T) {
|
||||
migrationTests := []struct {
|
||||
name string
|
||||
init func(*bolt.Tx) error
|
||||
check func(*bolt.Tx) error
|
||||
}{
|
||||
{
|
||||
name: "ChildrenKey",
|
||||
init: func(tx *bolt.Tx) error {
|
||||
bkt, err := createSnapshotterBucket(tx, "testing", "testing")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
snapshots := []struct {
|
||||
key string
|
||||
parent string
|
||||
}{
|
||||
{
|
||||
key: "k1",
|
||||
parent: "",
|
||||
},
|
||||
{
|
||||
key: "k2",
|
||||
parent: "k1",
|
||||
},
|
||||
{
|
||||
key: "k2a",
|
||||
parent: "k1",
|
||||
},
|
||||
{
|
||||
key: "a1",
|
||||
parent: "k2",
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range snapshots {
|
||||
sbkt, err := bkt.CreateBucket([]byte(s.key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sbkt.Put(bucketKeyParent, []byte(s.parent)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
check: func(tx *bolt.Tx) error {
|
||||
bkt := getSnapshotterBucket(tx, "testing", "testing")
|
||||
if bkt == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "snapshots bucket not found")
|
||||
}
|
||||
snapshots := []struct {
|
||||
key string
|
||||
children []string
|
||||
}{
|
||||
{
|
||||
key: "k1",
|
||||
children: []string{"k2", "k2a"},
|
||||
},
|
||||
{
|
||||
key: "k2",
|
||||
children: []string{"a1"},
|
||||
},
|
||||
{
|
||||
key: "k2a",
|
||||
children: []string{},
|
||||
},
|
||||
{
|
||||
key: "a1",
|
||||
children: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range snapshots {
|
||||
sbkt := bkt.Bucket([]byte(s.key))
|
||||
if sbkt == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "key does not exist")
|
||||
}
|
||||
|
||||
cbkt := sbkt.Bucket(bucketKeyChildren)
|
||||
var cn int
|
||||
if cbkt != nil {
|
||||
cn = cbkt.Stats().KeyN
|
||||
}
|
||||
|
||||
if cn != len(s.children) {
|
||||
return errors.Errorf("unexpected number of children %d, expected %d", cn, len(s.children))
|
||||
}
|
||||
|
||||
for _, ch := range s.children {
|
||||
if v := cbkt.Get([]byte(ch)); v == nil {
|
||||
return errors.Errorf("missing child record for %s", ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if len(migrationTests) != len(migrations) {
|
||||
t.Fatal("Each migration must have a test case")
|
||||
}
|
||||
|
||||
for i, mt := range migrationTests {
|
||||
t.Run(mt.name, runMigrationTest(i, mt.init, mt.check))
|
||||
}
|
||||
}
|
||||
|
||||
func runMigrationTest(i int, init, check func(*bolt.Tx) error) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
_, db, cancel := testEnv(t)
|
||||
defer cancel()
|
||||
|
||||
if err := db.Update(init); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := db.Update(migrations[i].migrate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := db.View(check); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readDBVersion(db *bolt.DB, schema []byte) (int, error) {
|
||||
var version int
|
||||
if err := db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(schema)
|
||||
if bkt == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "no version bucket")
|
||||
}
|
||||
vb := bkt.Get(bucketKeyDBVersion)
|
||||
if vb == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "no version value")
|
||||
}
|
||||
v, _ := binary.Varint(vb)
|
||||
version = int(v)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
Reference in New Issue
Block a user