mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 21:17:58 +08:00
b7ab9dab16
fix: make sure metadb statistics are initialized on image download, and minor metadb fixes for Docker v2 manifest compatibility Looking into potential causes of https://github.com/project-zot/zot/issues/3163 1. One possible reason is the statistics were not properly initialized in the first place because of (unknown and/or unavoidable) errors on image push. To workaround this add logic to initialize the statistics on the call to download them. 2. Some images have the download statistics while others dont, one cause could be a bug in the logic handling manifest mediatypes in the search extension. Add compatibility checks for Docker v2 manifest types in metadb convert functions, and more tests for covering the Docker mediatype use case. Side fixes: - Ensure PushedBy Statistics entries are properly initialized in SetRepoReference - Fix and issue in the image upload test functions, they were uploading docker images with oci mediatypes in call headers Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
1349 lines
42 KiB
Go
1349 lines
42 KiB
Go
package dynamodb_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"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"
|
|
guuid "github.com/gofrs/uuid"
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
"zotregistry.dev/zot/v2/pkg/extensions/imagetrust"
|
|
"zotregistry.dev/zot/v2/pkg/log"
|
|
mdynamodb "zotregistry.dev/zot/v2/pkg/meta/dynamodb"
|
|
mTypes "zotregistry.dev/zot/v2/pkg/meta/types"
|
|
reqCtx "zotregistry.dev/zot/v2/pkg/requestcontext"
|
|
. "zotregistry.dev/zot/v2/pkg/test/image-utils"
|
|
tskip "zotregistry.dev/zot/v2/pkg/test/skip"
|
|
)
|
|
|
|
const badTablename = "bad tablename"
|
|
|
|
func TestIterator(t *testing.T) {
|
|
tskip.SkipDynamo(t)
|
|
|
|
const region = "us-east-2"
|
|
|
|
endpoint := os.Getenv("DYNAMODBMOCK_ENDPOINT")
|
|
|
|
uuid, err := guuid.NewV4()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
repoMetaTablename := "RepoMetadataTable" + uuid.String()
|
|
versionTablename := "Version" + uuid.String()
|
|
imageMetaTablename := "ImageMeta" + uuid.String()
|
|
repoBlobsTablename := "RepoBlobs" + uuid.String()
|
|
userDataTablename := "UserDataTable" + uuid.String()
|
|
apiKeyTablename := "ApiKeyTable" + uuid.String()
|
|
|
|
log := log.NewTestLogger()
|
|
|
|
Convey("TestIterator", t, func() {
|
|
params := mdynamodb.DBDriverParameters{
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
VersionTablename: versionTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
UserDataTablename: userDataTablename,
|
|
}
|
|
client, err := mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper, err := mdynamodb.New(client, params, log)
|
|
So(err, ShouldBeNil)
|
|
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename), ShouldBeNil)
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetRepoReference(context.Background(), "repo1", "tag1", CreateRandomImage().AsImageMeta())
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetRepoReference(context.Background(), "repo2", "tag2", CreateRandomImage().AsImageMeta())
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetRepoReference(context.Background(), "repo3", "tag3", CreateRandomImage().AsImageMeta())
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMetaAttributeIterator := mdynamodb.NewBaseDynamoAttributesIterator(
|
|
dynamoWrapper.Client,
|
|
dynamoWrapper.RepoMetaTablename,
|
|
"RepoMeta",
|
|
1,
|
|
log,
|
|
)
|
|
|
|
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( //nolint: staticcheck
|
|
func(service, region string, options ...interface{}) (aws.Endpoint, error) {
|
|
return aws.Endpoint{ //nolint: staticcheck
|
|
PartitionID: "aws",
|
|
URL: "endpoint",
|
|
SigningRegion: region,
|
|
}, nil
|
|
})
|
|
|
|
cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion("region"),
|
|
config.WithEndpointResolverWithOptions(customResolver)) //nolint: staticcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMetaAttributeIterator := mdynamodb.NewBaseDynamoAttributesIterator(
|
|
dynamodb.NewFromConfig(cfg),
|
|
"RepoMetadataTable",
|
|
"RepoMeta",
|
|
1,
|
|
log.NewTestLogger(),
|
|
)
|
|
|
|
_, err = repoMetaAttributeIterator.First(context.Background())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestWrapperErrors(t *testing.T) {
|
|
tskip.SkipDynamo(t)
|
|
|
|
const region = "us-east-2"
|
|
|
|
endpoint := os.Getenv("DYNAMODBMOCK_ENDPOINT")
|
|
|
|
uuid, err := guuid.NewV4()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
repoMetaTablename := "RepoMetadataTable" + uuid.String()
|
|
versionTablename := "Version" + uuid.String()
|
|
userDataTablename := "UserDataTable" + uuid.String()
|
|
apiKeyTablename := "ApiKeyTable" + uuid.String()
|
|
wrongTableName := "WRONG Tables"
|
|
imageMetaTablename := "ImageMeta" + uuid.String()
|
|
repoBlobsTablename := "RepoBlobs" + uuid.String()
|
|
|
|
log := log.NewTestLogger()
|
|
testDigest := godigest.FromString("str")
|
|
image := CreateDefaultImage()
|
|
multi := CreateMultiarchWith().Images([]Image{image}).Build()
|
|
imageMeta := image.AsImageMeta()
|
|
multiarchImageMeta := multi.AsImageMeta()
|
|
|
|
badProtoBlob := []byte("bad-repo-meta")
|
|
// goodRepoMetaBlob, err := proto.Marshal(&proto_go.RepoMeta{Name: "repo"})
|
|
// if err != nil {
|
|
// t.FailNow()
|
|
// }
|
|
|
|
//nolint: contextcheck
|
|
Convey("Errors", t, func() {
|
|
params := mdynamodb.DBDriverParameters{ //nolint:contextcheck,staticcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
VersionTablename: versionTablename,
|
|
}
|
|
client, err := mdynamodb.GetDynamoClient(params) //nolint:contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
imgTrustStore, err := imagetrust.NewAWSImageTrustStore(params.Region, params.Endpoint)
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper, err := mdynamodb.New(client, params, log) //nolint:contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper.SetImageTrustStore(imgTrustStore)
|
|
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil) //nolint:contextcheck
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.RepoBlobsTablename), ShouldBeNil) //nolint:contextcheck
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename), ShouldBeNil) //nolint:contextcheck
|
|
So(dynamoWrapper.ResetTable(dynamoWrapper.UserDataTablename), ShouldBeNil) //nolint:contextcheck
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
Convey("RemoveRepoReference", func() {
|
|
Convey("getProtoRepoMeta errors", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.RemoveRepoReference("repo", "ref", imageMeta.Digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("getProtoImageMeta errors", func() {
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: imageMeta.Digest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(imageMeta.Digest, badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.RemoveRepoReference("repo", "ref", imageMeta.Digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoBlobs errors", func() {
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setRepoBlobInfo("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.RemoveRepoReference("repo", "ref", imageMeta.Digest) //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
Convey("FilterImageMeta", func() {
|
|
Convey("FilterImageMeta with duplicate digests", func() {
|
|
image := CreateRandomImage()
|
|
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", image.AsImageMeta())
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterImageMeta(ctx, []string{image.DigestStr(), image.DigestStr()})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("manifest meta unmarshal error", func() {
|
|
err = setImageMeta(image.Digest(), badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterImageMeta(ctx, []string{image.DigestStr()})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("MediaType ImageIndex, getProtoImageMeta fails", func() {
|
|
err := dynamoWrapper.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
// manifests are missing
|
|
_, err = dynamoWrapper.FilterImageMeta(ctx, []string{multiarchImageMeta.Digest.String()})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
Convey("UpdateSignaturesValidity", func() {
|
|
digest := image.Digest()
|
|
|
|
Convey("image meta blob not found", func() {
|
|
err := dynamoWrapper.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("UpdateSignaturesValidity with context done", func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
err := dynamoWrapper.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("image meta unmarshal fail", func() {
|
|
err := setImageMeta(digest, badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("repo meta blob not found", func() {
|
|
err := dynamoWrapper.SetImageMeta(digest, imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("repo meta unmarshal fail", func() {
|
|
err := dynamoWrapper.SetImageMeta(digest, imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("UpdateStatsOnDownload", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", "ref")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ref is tag and tag is not found", func() {
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", "not-found-tag") //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("digest not found in statistics", func() {
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", godigest.FromString("not-found").String()) //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("statistics entry missing but digest exists in tags - should create and increment", func() {
|
|
// Set repo reference to create tag
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Manually remove Statistics entry to simulate missing Statistics
|
|
repoMeta, err := dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
delete(repoMeta.Statistics, imageMeta.Digest.String())
|
|
|
|
// Set repo meta back without Statistics
|
|
err = dynamoWrapper.SetRepoMeta("repo", repoMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Verify Statistics entry doesn't exist
|
|
repoMeta, err = dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
_, exists := repoMeta.Statistics[imageMeta.Digest.String()]
|
|
So(exists, ShouldBeFalse)
|
|
|
|
// Update stats - should create Statistics entry and increment
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", "tag") //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
// Verify Statistics entry was created and incremented
|
|
repoMeta, err = dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
stats, exists := repoMeta.Statistics[imageMeta.Digest.String()]
|
|
So(exists, ShouldBeTrue)
|
|
So(stats.DownloadCount, ShouldEqual, 1)
|
|
|
|
// Update stats again - should increment existing entry
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", "tag") //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMeta, err = dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
stats, exists = repoMeta.Statistics[imageMeta.Digest.String()]
|
|
So(exists, ShouldBeTrue)
|
|
So(stats.DownloadCount, ShouldEqual, 2)
|
|
})
|
|
|
|
Convey("statistics entry missing but digest exists in tags - using digest reference", func() {
|
|
// Set repo reference to create tag
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Manually remove Statistics entry
|
|
repoMeta, err := dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
delete(repoMeta.Statistics, imageMeta.Digest.String())
|
|
|
|
// Set repo meta back without Statistics
|
|
err = dynamoWrapper.SetRepoMeta("repo", repoMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Update stats using digest directly
|
|
err = dynamoWrapper.UpdateStatsOnDownload("repo", imageMeta.Digest.String()) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
// Verify Statistics entry was created
|
|
repoMeta, err = dynamoWrapper.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
stats, exists := repoMeta.Statistics[imageMeta.Digest.String()]
|
|
So(exists, ShouldBeTrue)
|
|
So(stats.DownloadCount, ShouldEqual, 1)
|
|
})
|
|
})
|
|
Convey("GetReferrersInfo", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetReferrersInfo("repo", "refDig", []string{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
Convey("DecrementRepoStars", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.DecrementRepoStars("repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("IncrementRepoStars", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.IncrementRepoStars("repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetMultipleRepoMeta", func() {
|
|
Convey("repoMetaAttributeIterator.First fails", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
_, err := dynamoWrapper.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("repo meta unmarshal fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
Convey("GetImageMeta", func() {
|
|
Convey("get image meta fails", func() {
|
|
_, err := dynamoWrapper.GetImageMeta(testDigest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("image index, missing manifests are skipped gracefully", func() {
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", multiarchImageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Missing manifests are skipped gracefully, so GetImageMeta succeeds
|
|
// but returns an index with no manifests
|
|
imageMeta, err := dynamoWrapper.GetImageMeta(multiarchImageMeta.Digest) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
So(len(imageMeta.Manifests), ShouldEqual, 0)
|
|
})
|
|
})
|
|
Convey("GetFullImageMeta", func() {
|
|
Convey("repo meta not found", func() {
|
|
_, err := dynamoWrapper.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoMeta fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("tag not found", func() {
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetFullImageMeta(ctx, "repo", "tag-not-found")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("getProtoImageMeta fails", func() {
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: godigest.FromString("not-found").String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("image is index, missing manifests are skipped gracefully", func() {
|
|
err := dynamoWrapper.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: multiarchImageMeta.Digest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
// Missing manifests are skipped gracefully, so GetFullImageMeta succeeds
|
|
// but returns an index with no manifests
|
|
fullImageMeta, err := dynamoWrapper.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldBeNil)
|
|
So(len(fullImageMeta.Manifests), ShouldEqual, 0)
|
|
})
|
|
})
|
|
|
|
Convey("FilterTags", func() {
|
|
Convey("repoMetaAttributeIterator.First fails", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
_, err = dynamoWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("repo meta unmarshal fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("found repo meta", func() {
|
|
Convey("bad image manifest", func() {
|
|
badImageDigest := godigest.FromString("bad-image-manifest")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-manifest": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: badImageDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badImageDigest, badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("bad image index", func() {
|
|
badIndexDigest := godigest.FromString("bad-image-manifest")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-index": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: badIndexDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badIndexDigest, badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("good image index, bad inside manifest", func() {
|
|
goodIndexBadManifestDigest := godigest.FromString("good-index-bad-manifests")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"good-index-bad-manifests": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: goodIndexBadManifestDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetImageMeta(goodIndexBadManifestDigest, multiarchImageMeta) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
})
|
|
|
|
Convey("SearchTags", func() {
|
|
Convey("getProtoRepoMeta errors", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.SearchTags(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("found repo meta", func() {
|
|
Convey("bad image manifest", func() {
|
|
badImageDigest := godigest.FromString("bad-image-manifest")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-manifest": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: badImageDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badImageDigest, badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("bad image index", func() {
|
|
badIndexDigest := godigest.FromString("bad-image-manifest")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-index": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: badIndexDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badIndexDigest, badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("good image index, bad inside manifest", func() {
|
|
goodIndexBadManifestDigest := godigest.FromString("good-index-bad-manifests")
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"good-index-bad-manifests": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: goodIndexBadManifestDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = dynamoWrapper.SetImageMeta(goodIndexBadManifestDigest, multiarchImageMeta) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("bad media type", func() {
|
|
err := dynamoWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ //nolint: contextcheck
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"mad-media-type": {
|
|
MediaType: "bad media type",
|
|
Digest: godigest.FromString("dig").String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.SearchTags(ctx, "repo:")
|
|
So(err, ShouldBeNil)
|
|
})
|
|
})
|
|
})
|
|
|
|
Convey("SearchRepos", func() {
|
|
Convey("repoMetaAttributeIterator.First errors", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.SearchRepos(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("repo meta unmarshal errors", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.SearchRepos(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("SetRepoReference", func() {
|
|
Convey("SetProtoImageMeta fails", func() {
|
|
dynamoWrapper.ImageMetaTablename = badTablename
|
|
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", image.AsImageMeta())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("getProtoRepoMeta fails", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", image.AsImageMeta())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("getProtoRepoBlobs fails", func() {
|
|
dynamoWrapper.RepoBlobsTablename = badTablename
|
|
|
|
err := dynamoWrapper.SetRepoReference(ctx, "repo", "tag", image.AsImageMeta())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetProtoImageMeta", func() {
|
|
Convey("Get request fails", func() {
|
|
dynamoWrapper.ImageMetaTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.GetProtoImageMeta(ctx, testDigest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("unmarshal fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, dynamoWrapper) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetProtoImageMeta(ctx, testDigest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("SetUserData", func() {
|
|
hashKey := "id"
|
|
apiKeys := make(map[string]mTypes.APIKeyDetails)
|
|
apiKeyDetails := mTypes.APIKeyDetails{
|
|
Label: "apiKey",
|
|
Scopes: []string{"repo"},
|
|
UUID: hashKey,
|
|
}
|
|
|
|
apiKeys[hashKey] = apiKeyDetails
|
|
|
|
userProfileSrc := mTypes.UserData{
|
|
Groups: []string{"group1", "group2"},
|
|
APIKeys: apiKeys,
|
|
}
|
|
|
|
err := dynamoWrapper.SetUserData(ctx, userProfileSrc)
|
|
So(err, ShouldBeNil)
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = dynamoWrapper.SetUserData(ctx, mTypes.UserData{}) //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserData", func() {
|
|
err := dynamoWrapper.DeleteUserData(ctx)
|
|
So(err, ShouldBeNil)
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = dynamoWrapper.DeleteUserData(ctx) //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleBookmarkRepo no access", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": false,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
_, err := dynamoWrapper.ToggleBookmarkRepo(ctx, "unaccesible")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleBookmarkRepo GetUserMeta no user data", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
status, err := dynamoWrapper.ToggleBookmarkRepo(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
So(status, ShouldEqual, mTypes.Added)
|
|
})
|
|
|
|
Convey("ToggleBookmarkRepo GetUserMeta client error", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": false,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
dynamoWrapper.UserDataTablename = badTablename
|
|
|
|
status, err := dynamoWrapper.ToggleBookmarkRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
So(status, ShouldEqual, mTypes.NotChanged)
|
|
})
|
|
|
|
Convey("GetBookmarkedRepos", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": false,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
repos, err := dynamoWrapper.GetBookmarkedRepos(ctx)
|
|
So(err, ShouldBeNil)
|
|
So(len(repos), ShouldEqual, 0)
|
|
})
|
|
|
|
Convey("ToggleStarRepo GetUserMeta bad context", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := dynamoWrapper.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo GetUserMeta no access", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": false,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
_, err := dynamoWrapper.ToggleStarRepo(ctx, "unaccesible")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo GetUserMeta error", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": false,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
dynamoWrapper.UserDataTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo GetRepoMeta error", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserData bad context", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
userData, err := dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
So(userData.BookmarkedRepos, ShouldBeEmpty)
|
|
So(userData.StarredRepos, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("GetUserData client error", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
dynamoWrapper.UserDataTablename = badTablename
|
|
|
|
_, err := dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserMeta unmarshal error, bad user data", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err := setBadUserData(dynamoWrapper.Client, userDataTablename, userAc.GetUsername())
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserData bad context", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("AddUserAPIKey bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.AddUserAPIKey(ctx, "", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserAPIKey bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.DeleteUserAPIKey(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("UpdateUserAPIKeyLastUsed bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.UpdateUserAPIKeyLastUsed(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := dynamoWrapper.DeleteUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetRepoLastUpdated", func() {
|
|
Convey("bad table", func() {
|
|
dynamoWrapper.RepoBlobsTablename = "bad-table"
|
|
|
|
lastUpdated := dynamoWrapper.GetRepoLastUpdated("repo")
|
|
So(lastUpdated, ShouldEqual, time.Time{})
|
|
})
|
|
|
|
Convey("unmarshal error", func() {
|
|
err := setRepoLastUpdated("repo", []byte("bad-blob"), dynamoWrapper)
|
|
So(err, ShouldBeNil)
|
|
|
|
lastUpdated := dynamoWrapper.GetRepoLastUpdated("repo")
|
|
So(lastUpdated, ShouldEqual, time.Time{})
|
|
})
|
|
})
|
|
|
|
Convey("DeleteUserAPIKey returns nil", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("email")
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
apiKeyDetails := make(map[string]mTypes.APIKeyDetails)
|
|
apiKeyDetails["id"] = mTypes.APIKeyDetails{
|
|
UUID: "id",
|
|
}
|
|
err := dynamoWrapper.SetUserData(ctx, mTypes.UserData{
|
|
APIKeys: apiKeyDetails,
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper.APIKeyTablename = wrongTableName
|
|
err = dynamoWrapper.DeleteUserAPIKey(ctx, "id")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("AddUserAPIKey", func() {
|
|
Convey("no userid found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = dynamoWrapper.AddUserAPIKey(ctx, "key", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("email")
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err := dynamoWrapper.AddUserAPIKey(ctx, "key", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper.APIKeyTablename = wrongTableName
|
|
err = dynamoWrapper.AddUserAPIKey(ctx, "key", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserAPIKeyInfo", func() {
|
|
dynamoWrapper.APIKeyTablename = wrongTableName
|
|
_, err := dynamoWrapper.GetUserAPIKeyInfo("key")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserData", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
_, err := dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
userAc = reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("email")
|
|
ctx = userAc.DeriveContext(context.Background())
|
|
|
|
dynamoWrapper.UserDataTablename = wrongTableName
|
|
_, err = dynamoWrapper.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("PatchDB dwr.getDBVersion errors", func() {
|
|
dynamoWrapper.VersionTablename = badTablename
|
|
|
|
err := dynamoWrapper.PatchDB()
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("PatchDB patchIndex < version.GetVersionIndex", func() {
|
|
err := setVersion(dynamoWrapper.Client, versionTablename, "V2")
|
|
So(err, ShouldBeNil)
|
|
|
|
dynamoWrapper.Patches = []func(client *dynamodb.Client, tableNames map[string]string) error{
|
|
func(client *dynamodb.Client, tableNames map[string]string) error { return nil },
|
|
func(client *dynamodb.Client, tableNames map[string]string) error { return nil },
|
|
func(client *dynamodb.Client, tableNames map[string]string) error { return nil },
|
|
}
|
|
|
|
err = dynamoWrapper.PatchDB()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetRepoMetaTable client errors", func() {
|
|
dynamoWrapper.RepoMetaTablename = badTablename
|
|
|
|
err := dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("getDBVersion client errors", func() {
|
|
dynamoWrapper.VersionTablename = badTablename
|
|
|
|
err := dynamoWrapper.PatchDB()
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("NewDynamoDBWrapper errors", t, func() {
|
|
params := mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: "",
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
VersionTablename: versionTablename,
|
|
}
|
|
client, err := mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: "",
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
VersionTablename: versionTablename,
|
|
}
|
|
client, err = mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: "",
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
VersionTablename: versionTablename,
|
|
}
|
|
client, err = mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: apiKeyTablename,
|
|
VersionTablename: "",
|
|
}
|
|
client, err = mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
VersionTablename: versionTablename,
|
|
UserDataTablename: "",
|
|
APIKeyTablename: apiKeyTablename,
|
|
}
|
|
client, err = mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
|
|
Endpoint: endpoint,
|
|
Region: region,
|
|
RepoMetaTablename: repoMetaTablename,
|
|
ImageMetaTablename: imageMetaTablename,
|
|
RepoBlobsInfoTablename: repoBlobsTablename,
|
|
VersionTablename: versionTablename,
|
|
UserDataTablename: userDataTablename,
|
|
APIKeyTablename: "",
|
|
}
|
|
client, err = mdynamodb.GetDynamoClient(params)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = mdynamodb.New(client, params, log)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func setRepoMeta(repo string, blob []byte, dynamoWrapper *mdynamodb.DynamoDB) error { //nolint: unparam
|
|
userAttributeValue, err := attributevalue.Marshal(blob)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = dynamoWrapper.Client.UpdateItem(context.Background(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#RM": "RepoMeta",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":RepoMeta": userAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: repo,
|
|
},
|
|
},
|
|
TableName: aws.String(dynamoWrapper.RepoMetaTablename),
|
|
UpdateExpression: aws.String("SET #RM = :RepoMeta"),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func setRepoLastUpdated(repo string, blob []byte, dynamoWrapper *mdynamodb.DynamoDB) error { //nolint: unparam
|
|
lastUpdatedAttributeValue, err := attributevalue.Marshal(blob)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = dynamoWrapper.Client.UpdateItem(context.Background(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#RLU": "RepoLastUpdated",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":RepoLastUpdated": lastUpdatedAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: repo,
|
|
},
|
|
},
|
|
TableName: aws.String(dynamoWrapper.RepoBlobsTablename),
|
|
UpdateExpression: aws.String("SET #RLU = :RepoLastUpdated"),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func setRepoBlobInfo(repo string, blob []byte, dynamoWrapper *mdynamodb.DynamoDB) error {
|
|
userAttributeValue, err := attributevalue.Marshal(blob)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = dynamoWrapper.Client.UpdateItem(context.Background(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#RB": "RepoBlobsInfo",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":RepoBlobsInfo": userAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: repo,
|
|
},
|
|
},
|
|
TableName: aws.String(dynamoWrapper.RepoBlobsTablename),
|
|
UpdateExpression: aws.String("SET #RB = :RepoBlobsInfo"),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func setImageMeta(digest godigest.Digest, blob []byte, dynamoWrapper *mdynamodb.DynamoDB) error {
|
|
userAttributeValue, err := attributevalue.Marshal(blob)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = dynamoWrapper.Client.UpdateItem(context.Background(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#IM": "ImageMeta",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":ImageMeta": userAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: digest.String(),
|
|
},
|
|
},
|
|
TableName: aws.String(dynamoWrapper.ImageMetaTablename),
|
|
UpdateExpression: aws.String("SET #IM = :ImageMeta"),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func setBadUserData(client *dynamodb.Client, userDataTablename, userID string) error {
|
|
userAttributeValue, err := attributevalue.Marshal("string")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = client.UpdateItem(context.Background(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#UM": "UserData",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":UserData": userAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: userID,
|
|
},
|
|
},
|
|
TableName: aws.String(userDataTablename),
|
|
UpdateExpression: aws.String("SET #UM = :UserData"),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func setVersion(client *dynamodb.Client, versionTablename string, version string) error {
|
|
mdAttributeValue, err := attributevalue.Marshal(version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
|
ExpressionAttributeNames: map[string]string{
|
|
"#V": "Version",
|
|
},
|
|
ExpressionAttributeValues: map[string]types.AttributeValue{
|
|
":Version": mdAttributeValue,
|
|
},
|
|
Key: map[string]types.AttributeValue{
|
|
"TableKey": &types.AttributeValueMemberS{
|
|
Value: "DBVersion",
|
|
},
|
|
},
|
|
TableName: aws.String(versionTablename),
|
|
UpdateExpression: aws.String("SET #V = :Version"),
|
|
})
|
|
|
|
return err
|
|
}
|