zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/meta/version/version_test.go (about) 1 package version_test 2 3 import ( 4 "context" 5 "errors" 6 "os" 7 "path" 8 "testing" 9 10 "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" 11 "github.com/aws/aws-sdk-go-v2/service/dynamodb" 12 "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" 13 "github.com/aws/aws-sdk-go/aws" 14 guuid "github.com/gofrs/uuid" 15 . "github.com/smartystreets/goconvey/convey" 16 "go.etcd.io/bbolt" 17 18 "zotregistry.io/zot/pkg/log" 19 "zotregistry.io/zot/pkg/meta/boltdb" 20 mdynamodb "zotregistry.io/zot/pkg/meta/dynamodb" 21 "zotregistry.io/zot/pkg/meta/version" 22 tskip "zotregistry.io/zot/pkg/test/skip" 23 ) 24 25 var ErrTestError = errors.New("test error") 26 27 func TestVersioningBoltDB(t *testing.T) { 28 Convey("Tests", t, func() { 29 tmpDir := t.TempDir() 30 boltDBParams := boltdb.DBParameters{RootDir: tmpDir} 31 boltDriver, err := boltdb.GetBoltDriver(boltDBParams) 32 So(err, ShouldBeNil) 33 34 log := log.NewLogger("debug", "") 35 36 boltdbWrapper, err := boltdb.New(boltDriver, log) 37 defer os.Remove(path.Join(boltDBParams.RootDir, "meta.db")) 38 So(boltdbWrapper, ShouldNotBeNil) 39 So(err, ShouldBeNil) 40 41 boltdbWrapper.Patches = []func(DB *bbolt.DB) error{ 42 func(DB *bbolt.DB) error { 43 return nil 44 }, 45 } 46 47 Convey("success", func() { 48 boltdbWrapper.Patches = []func(DB *bbolt.DB) error{ 49 func(DB *bbolt.DB) error { // V1 to V2 50 return nil 51 }, 52 } 53 54 err := setBoltDBVersion(boltdbWrapper.DB, version.Version1) 55 So(err, ShouldBeNil) 56 57 err = boltdbWrapper.PatchDB() 58 So(err, ShouldBeNil) 59 }) 60 61 Convey("DBVersion is empty", func() { 62 err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { 63 versionBuck := tx.Bucket([]byte(boltdb.VersionBucket)) 64 65 return versionBuck.Put([]byte(version.DBVersionKey), []byte("")) 66 }) 67 So(err, ShouldBeNil) 68 69 err = boltdbWrapper.PatchDB() 70 So(err, ShouldNotBeNil) 71 }) 72 73 Convey("iterate patches with skip", func() { 74 boltdbWrapper.Patches = []func(DB *bbolt.DB) error{ 75 func(DB *bbolt.DB) error { // V1 to V2 76 return nil 77 }, 78 func(DB *bbolt.DB) error { // V2 to V3 79 return nil 80 }, 81 func(DB *bbolt.DB) error { // V3 to V4 82 return nil 83 }, 84 } 85 86 err := setBoltDBVersion(boltdbWrapper.DB, version.Version1) 87 So(err, ShouldBeNil) 88 // we should skip the first patch 89 90 err = boltdbWrapper.PatchDB() 91 So(err, ShouldBeNil) 92 }) 93 94 Convey("patch has error", func() { 95 boltdbWrapper.Patches = []func(DB *bbolt.DB) error{ 96 func(DB *bbolt.DB) error { // V1 to V2 97 return ErrTestError 98 }, 99 } 100 101 err = boltdbWrapper.PatchDB() 102 So(err, ShouldNotBeNil) 103 }) 104 }) 105 } 106 107 func setBoltDBVersion(db *bbolt.DB, vers string) error { 108 err := db.Update(func(tx *bbolt.Tx) error { 109 versionBuck := tx.Bucket([]byte(boltdb.VersionBucket)) 110 111 return versionBuck.Put([]byte(version.DBVersionKey), []byte(vers)) 112 }) 113 114 return err 115 } 116 117 func TestVersioningDynamoDB(t *testing.T) { 118 tskip.SkipDynamo(t) 119 120 uuid, err := guuid.NewV4() 121 if err != nil { 122 panic(err) 123 } 124 125 Convey("Tests", t, func() { 126 params := mdynamodb.DBDriverParameters{ 127 Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"), 128 Region: "us-east-2", 129 RepoMetaTablename: "RepoMetadataTable" + uuid.String(), 130 RepoBlobsInfoTablename: "RepoBlobsInfoTablename" + uuid.String(), 131 ImageMetaTablename: "ImageMetaTablename" + uuid.String(), 132 UserDataTablename: "UserDataTable" + uuid.String(), 133 APIKeyTablename: "ApiKeyTable" + uuid.String(), 134 VersionTablename: "Version" + uuid.String(), 135 } 136 137 dynamoClient, err := mdynamodb.GetDynamoClient(params) 138 So(err, ShouldBeNil) 139 140 log := log.NewLogger("debug", "") 141 142 dynamoWrapper, err := mdynamodb.New(dynamoClient, params, log) 143 So(err, ShouldBeNil) 144 145 So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil) 146 147 Convey("dbVersion is empty", func() { 148 err := setDynamoDBVersion(dynamoWrapper.Client, params.VersionTablename, "") 149 So(err, ShouldBeNil) 150 151 err = dynamoWrapper.PatchDB() 152 So(err, ShouldNotBeNil) 153 }) 154 155 Convey("iterate patches with skip", func() { 156 dynamoWrapper.Patches = []func(client *dynamodb.Client, tableNames map[string]string) error{ 157 func(client *dynamodb.Client, tableNames map[string]string) error { // V1 to V2 158 return nil 159 }, 160 func(client *dynamodb.Client, tableNames map[string]string) error { // V2 to V3 161 return nil 162 }, 163 func(client *dynamodb.Client, tableNames map[string]string) error { // V3 to V4 164 return nil 165 }, 166 } 167 168 err := setDynamoDBVersion(dynamoWrapper.Client, params.VersionTablename, version.Version1) 169 So(err, ShouldBeNil) 170 // we should skip the first patch 171 172 err = dynamoWrapper.PatchDB() 173 So(err, ShouldBeNil) 174 }) 175 176 Convey("patch has error", func() { 177 dynamoWrapper.Patches = []func(client *dynamodb.Client, tableNames map[string]string) error{ 178 func(client *dynamodb.Client, tableNames map[string]string) error { // V1 to V2 179 return ErrTestError 180 }, 181 } 182 183 err = dynamoWrapper.PatchDB() 184 So(err, ShouldNotBeNil) 185 }) 186 }) 187 } 188 189 func setDynamoDBVersion(client *dynamodb.Client, versTable, vers string) error { 190 mdAttributeValue, err := attributevalue.Marshal(vers) 191 if err != nil { 192 return err 193 } 194 195 _, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{ 196 ExpressionAttributeNames: map[string]string{ 197 "#V": "Version", 198 }, 199 ExpressionAttributeValues: map[string]types.AttributeValue{ 200 ":Version": mdAttributeValue, 201 }, 202 Key: map[string]types.AttributeValue{ 203 "TableKey": &types.AttributeValueMemberS{ 204 Value: version.DBVersionKey, 205 }, 206 }, 207 TableName: aws.String(versTable), 208 UpdateExpression: aws.String("SET #V = :Version"), 209 }) 210 211 return err 212 }