mirror of
https://github.com/project-zot/zot.git
synced 2024-12-23 22:27:35 -05:00
454 lines
13 KiB
Go
454 lines
13 KiB
Go
|
package dynamo_test
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||
|
"github.com/aws/aws-sdk-go-v2/config"
|
||
|
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
|
||
|
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
|
||
|
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
|
||
|
"github.com/rs/zerolog"
|
||
|
. "github.com/smartystreets/goconvey/convey"
|
||
|
|
||
|
"zotregistry.io/zot/pkg/log"
|
||
|
"zotregistry.io/zot/pkg/meta/repodb"
|
||
|
dynamo "zotregistry.io/zot/pkg/meta/repodb/dynamodb-wrapper"
|
||
|
"zotregistry.io/zot/pkg/meta/repodb/dynamodb-wrapper/iterator"
|
||
|
dynamoParams "zotregistry.io/zot/pkg/meta/repodb/dynamodb-wrapper/params"
|
||
|
)
|
||
|
|
||
|
func TestIterator(t *testing.T) {
|
||
|
const (
|
||
|
endpoint = "http://localhost:4566"
|
||
|
region = "us-east-2"
|
||
|
)
|
||
|
|
||
|
Convey("TestIterator", t, func() {
|
||
|
dynamoWrapper, err := dynamo.NewDynamoDBWrapper(dynamoParams.DBDriverParameters{
|
||
|
Endpoint: endpoint,
|
||
|
Region: region,
|
||
|
RepoMetaTablename: "RepoMetadataTable",
|
||
|
ManifestDataTablename: "ManifestDataTable",
|
||
|
VersionTablename: "Version",
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil)
|
||
|
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetRepoTag("repo1", "tag1", "manifestType", "manifestDigest1")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetRepoTag("repo2", "tag2", "manifestType", "manifestDigest2")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetRepoTag("repo3", "tag3", "manifestType", "manifestDigest3")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
repoMetaAttributeIterator := iterator.NewBaseDynamoAttributesIterator(
|
||
|
dynamoWrapper.Client,
|
||
|
"RepoMetadataTable",
|
||
|
"RepoMetadata",
|
||
|
1,
|
||
|
log.Logger{Logger: zerolog.New(os.Stdout)},
|
||
|
)
|
||
|
|
||
|
attribute, err := repoMetaAttributeIterator.First(context.Background())
|
||
|
So(err, ShouldBeNil)
|
||
|
So(attribute, ShouldNotBeNil)
|
||
|
|
||
|
attribute, err = repoMetaAttributeIterator.Next(context.Background())
|
||
|
So(err, ShouldBeNil)
|
||
|
So(attribute, ShouldNotBeNil)
|
||
|
|
||
|
attribute, err = repoMetaAttributeIterator.Next(context.Background())
|
||
|
So(err, ShouldBeNil)
|
||
|
So(attribute, ShouldNotBeNil)
|
||
|
|
||
|
attribute, err = repoMetaAttributeIterator.Next(context.Background())
|
||
|
So(err, ShouldBeNil)
|
||
|
So(attribute, ShouldBeNil)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestIteratorErrors(t *testing.T) {
|
||
|
Convey("errors", t, func() {
|
||
|
customResolver := aws.EndpointResolverWithOptionsFunc(
|
||
|
func(service, region string, options ...interface{}) (aws.Endpoint, error) {
|
||
|
return aws.Endpoint{
|
||
|
PartitionID: "aws",
|
||
|
URL: "endpoint",
|
||
|
SigningRegion: region,
|
||
|
}, nil
|
||
|
})
|
||
|
|
||
|
cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion("region"),
|
||
|
config.WithEndpointResolverWithOptions(customResolver))
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
repoMetaAttributeIterator := iterator.NewBaseDynamoAttributesIterator(
|
||
|
dynamodb.NewFromConfig(cfg),
|
||
|
"RepoMetadataTable",
|
||
|
"RepoMetadata",
|
||
|
1,
|
||
|
log.Logger{Logger: zerolog.New(os.Stdout)},
|
||
|
)
|
||
|
|
||
|
_, err = repoMetaAttributeIterator.First(context.Background())
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestWrapperErrors(t *testing.T) {
|
||
|
const (
|
||
|
endpoint = "http://localhost:4566"
|
||
|
region = "us-east-2"
|
||
|
)
|
||
|
|
||
|
ctx := context.Background()
|
||
|
|
||
|
Convey("Errors", t, func() {
|
||
|
dynamoWrapper, err := dynamo.NewDynamoDBWrapper(dynamoParams.DBDriverParameters{ //nolint:contextcheck
|
||
|
Endpoint: endpoint,
|
||
|
Region: region,
|
||
|
RepoMetaTablename: "RepoMetadataTable",
|
||
|
ManifestDataTablename: "ManifestDataTable",
|
||
|
VersionTablename: "Version",
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil) //nolint:contextcheck
|
||
|
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil) //nolint:contextcheck
|
||
|
|
||
|
Convey("SetManifestData", func() {
|
||
|
dynamoWrapper.ManifestDataTablename = "WRONG table"
|
||
|
|
||
|
err := dynamoWrapper.SetManifestData("dig", repodb.ManifestData{})
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetManifestData", func() {
|
||
|
dynamoWrapper.ManifestDataTablename = "WRONG table"
|
||
|
|
||
|
_, err := dynamoWrapper.GetManifestData("dig")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetManifestData unmarshal error", func() {
|
||
|
err := setBadManifestData(dynamoWrapper.Client, "dig")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetManifestData("dig")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SetManifestMeta GetRepoMeta error", func() {
|
||
|
err := setBadRepoMeta(dynamoWrapper.Client, "repo1")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetManifestMeta("repo1", "dig", repodb.ManifestMetadata{})
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetManifestMeta GetManifestData not found error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetManifestMeta("repo", "dig")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetManifestMeta GetRepoMeta Not Found error", func() {
|
||
|
err := dynamoWrapper.SetManifestData("dig", repodb.ManifestData{})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetManifestMeta("repoNotFound", "dig")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetManifestMeta GetRepoMeta error", func() {
|
||
|
err := dynamoWrapper.SetManifestData("dig", repodb.ManifestData{})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetManifestMeta("repo", "dig")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("IncrementRepoStars GetRepoMeta error", func() {
|
||
|
err = dynamoWrapper.IncrementRepoStars("repo")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("DecrementRepoStars GetRepoMeta error", func() {
|
||
|
err = dynamoWrapper.DecrementRepoStars("repo")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("DeleteRepoTag Client.GetItem error", func() {
|
||
|
strSlice := make([]string, 10000)
|
||
|
repoName := strings.Join(strSlice, ".")
|
||
|
|
||
|
err = dynamoWrapper.DeleteRepoTag(repoName, "tag")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("DeleteRepoTag unmarshal error", func() {
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.DeleteRepoTag("repo", "tag")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetRepoMeta Client.GetItem error", func() {
|
||
|
strSlice := make([]string, 10000)
|
||
|
repoName := strings.Join(strSlice, ".")
|
||
|
|
||
|
_, err = dynamoWrapper.GetRepoMeta(repoName)
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetRepoMeta unmarshal error", func() {
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetRepoMeta("repo")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("IncrementImageDownloads GetRepoMeta error", func() {
|
||
|
err = dynamoWrapper.IncrementImageDownloads("repoNotFound", "")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("IncrementImageDownloads tag not found error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.IncrementImageDownloads("repo", "notFoundTag")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("IncrementImageDownloads GetManifestMeta error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.IncrementImageDownloads("repo", "tag")
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("AddManifestSignature GetRepoMeta error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.AddManifestSignature("repoNotFound", "tag", repodb.SignatureMetadata{})
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("AddManifestSignature ManifestSignatures signedManifestDigest not found error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.AddManifestSignature("repo", "tagNotFound", repodb.SignatureMetadata{})
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("AddManifestSignature SignatureType repodb.NotationType", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag", "dig", "")
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.AddManifestSignature("repo", "tagNotFound", repodb.SignatureMetadata{
|
||
|
SignatureType: "notation",
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("DeleteSignature GetRepoMeta error", func() {
|
||
|
err = dynamoWrapper.DeleteSignature("repoNotFound", "tagNotFound", repodb.SignatureMetadata{})
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("DeleteSignature sigDigest.SignatureManifestDigest != sigMeta.SignatureDigest true", func() {
|
||
|
err := setRepoMeta(dynamoWrapper.Client, repodb.RepoMetadata{
|
||
|
Name: "repo",
|
||
|
Signatures: map[string]repodb.ManifestSignatures{
|
||
|
"tag1": {
|
||
|
"cosign": []repodb.SignatureInfo{
|
||
|
{SignatureManifestDigest: "dig1"},
|
||
|
{SignatureManifestDigest: "dig2"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.DeleteSignature("repo", "tag1", repodb.SignatureMetadata{
|
||
|
SignatureDigest: "dig2",
|
||
|
SignatureType: "cosign",
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("GetMultipleRepoMeta unmarshal error", func() {
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, err = dynamoWrapper.GetMultipleRepoMeta(ctx, func(repoMeta repodb.RepoMetadata) bool { return true },
|
||
|
repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchRepos repoMeta unmarshal error", func() {
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchRepos(ctx, "", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchRepos GetManifestMeta error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag1", "notFoundDigest", "") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchRepos(ctx, "", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchRepos config unmarshal error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag1", "dig1", "") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetManifestData("dig1", repodb.ManifestData{ //nolint:contextcheck
|
||
|
ManifestBlob: []byte("{}"),
|
||
|
ConfigBlob: []byte("bad json"),
|
||
|
})
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchRepos(ctx, "", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchTags repoMeta unmarshal error", func() {
|
||
|
err = setBadRepoMeta(dynamoWrapper.Client, "repo") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchTags(ctx, "repo:", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchTags GetManifestMeta error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag1", "manifestNotFound", "") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchTags(ctx, "repo:", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
|
||
|
Convey("SearchTags config unmarshal error", func() {
|
||
|
err := dynamoWrapper.SetRepoTag("repo", "tag1", "dig1", "") //nolint:contextcheck
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
err = dynamoWrapper.SetManifestData( //nolint:contextcheck
|
||
|
"dig1",
|
||
|
repodb.ManifestData{
|
||
|
ManifestBlob: []byte("{}"),
|
||
|
ConfigBlob: []byte("bad json"),
|
||
|
},
|
||
|
)
|
||
|
So(err, ShouldBeNil)
|
||
|
|
||
|
_, _, err = dynamoWrapper.SearchTags(ctx, "repo:", repodb.Filter{}, repodb.PageInput{})
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func setBadManifestData(client *dynamodb.Client, digest string) error {
|
||
|
mdAttributeValue, err := attributevalue.Marshal("string")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||
|
ExpressionAttributeNames: map[string]string{
|
||
|
"#MD": "ManifestData",
|
||
|
},
|
||
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||
|
":ManifestData": mdAttributeValue,
|
||
|
},
|
||
|
Key: map[string]types.AttributeValue{
|
||
|
"Digest": &types.AttributeValueMemberS{
|
||
|
Value: digest,
|
||
|
},
|
||
|
},
|
||
|
TableName: aws.String("ManifestDataTable"),
|
||
|
UpdateExpression: aws.String("SET #MD = :ManifestData"),
|
||
|
})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func setBadRepoMeta(client *dynamodb.Client, repoName string) error {
|
||
|
repoAttributeValue, err := attributevalue.Marshal("string")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||
|
ExpressionAttributeNames: map[string]string{
|
||
|
"#RM": "RepoMetadata",
|
||
|
},
|
||
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||
|
":RepoMetadata": repoAttributeValue,
|
||
|
},
|
||
|
Key: map[string]types.AttributeValue{
|
||
|
"RepoName": &types.AttributeValueMemberS{
|
||
|
Value: repoName,
|
||
|
},
|
||
|
},
|
||
|
TableName: aws.String("RepoMetadataTable"),
|
||
|
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
|
||
|
})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func setRepoMeta(client *dynamodb.Client, repoMeta repodb.RepoMetadata) error {
|
||
|
repoAttributeValue, err := attributevalue.Marshal(repoMeta)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||
|
ExpressionAttributeNames: map[string]string{
|
||
|
"#RM": "RepoMetadata",
|
||
|
},
|
||
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||
|
":RepoMetadata": repoAttributeValue,
|
||
|
},
|
||
|
Key: map[string]types.AttributeValue{
|
||
|
"RepoName": &types.AttributeValueMemberS{
|
||
|
Value: repoMeta.Name,
|
||
|
},
|
||
|
},
|
||
|
TableName: aws.String("RepoMetadataTable"),
|
||
|
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
|
||
|
})
|
||
|
|
||
|
return err
|
||
|
}
|