mirror of
https://github.com/project-zot/zot.git
synced 2025-02-17 23:45:36 -05:00
* feat: add redis cache support https://github.com/project-zot/zot/pull/2005 Fixes https://github.com/project-zot/zot/issues/2004 * feat: add redis cache support Currently, we have dynamoDB as the remote shared cache but ideal only for the cloud use case. For on-prem use case, add support for redis. Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> * feat(redis): added blackbox tests for redis Signed-off-by: Petu Eusebiu <peusebiu@cisco.com> * feat(redis): dummy implementation of MetaDB interface for redis cache Signed-off-by: Alexei Dodon <adodon@cisco.com> * feat: check validity of driver configuration on metadb instantiation Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat: multiple fixes for redis cache driver implementation - add missing method GetAllBlobs - add redis cache tests, with and without mocking Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): redis implementation for MetaDB Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): use redsync to block concurrent write access to the redis DB Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): update .github/workflows/cluster.yaml to also test redis Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(metadb): add keyPrefix parameter for redis and remove unneeded method meta.Crate() Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): support RedisCluster configuration and add unit tests Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): more tests for redis metadb implementation Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): add more examples and update examples/README.md Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): move option parsing and redis client initialization under pkg/api/config/redis Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * chore(cachedb): move Cache interface to pkg/storage/types Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): reorganize code in pkg/storage/cache.go Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): call redis.SetLogger() with the zot logger as parameter Signed-off-by: Andrei Aaron <aaaron@luxoft.com> * feat(redis): rename pkg/meta/redisdb to pkg/meta/redis Signed-off-by: Andrei Aaron <aaaron@luxoft.com> --------- Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> Signed-off-by: Petu Eusebiu <peusebiu@cisco.com> Signed-off-by: Alexei Dodon <adodon@cisco.com> Signed-off-by: Andrei Aaron <aaaron@luxoft.com> Co-authored-by: a <a@tuxpa.in> Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com> Co-authored-by: Petu Eusebiu <peusebiu@cisco.com> Co-authored-by: Alexei Dodon <adodon@cisco.com>
1532 lines
42 KiB
Go
1532 lines
42 KiB
Go
package redis_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"github.com/go-redis/redismock/v9"
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
goredis "github.com/redis/go-redis/v9"
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"zotregistry.dev/zot/pkg/log"
|
|
proto_go "zotregistry.dev/zot/pkg/meta/proto/gen"
|
|
"zotregistry.dev/zot/pkg/meta/redis"
|
|
mTypes "zotregistry.dev/zot/pkg/meta/types"
|
|
reqCtx "zotregistry.dev/zot/pkg/requestcontext"
|
|
test "zotregistry.dev/zot/pkg/test/common"
|
|
. "zotregistry.dev/zot/pkg/test/image-utils"
|
|
)
|
|
|
|
const keyPrefix = "zot"
|
|
|
|
var ErrTestError = errors.New("TestError")
|
|
|
|
type imgTrustStore struct{}
|
|
|
|
func (its imgTrustStore) VerifySignature(
|
|
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageMeta mTypes.ImageMeta,
|
|
repo string,
|
|
) (mTypes.Author, mTypes.ExpiryDate, mTypes.Validity, error) {
|
|
return "", time.Time{}, false, nil
|
|
}
|
|
|
|
func TestRedisMocked(t *testing.T) {
|
|
Convey("Test redis metadb implementation", t, func() {
|
|
log := log.NewLogger("debug", "")
|
|
So(log, ShouldNotBeNil)
|
|
|
|
client, mock := redismock.NewClientMock()
|
|
defer DumpKeys(t, client) // Troubleshoot test failures
|
|
|
|
mock.ExpectPing().SetVal("PONG")
|
|
|
|
params := redis.DBDriverParameters{KeyPrefix: "zot"}
|
|
|
|
metaDB, err := redis.New(client, params, log)
|
|
So(err, ShouldBeNil)
|
|
|
|
Convey("GetAllRepoNames HGetAll error", func() {
|
|
mock.ExpectHGetAll(metaDB.RepoMetaKey).
|
|
SetErr(ErrTestError)
|
|
|
|
repoNames, err := metaDB.GetAllRepoNames()
|
|
So(errors.Is(err, ErrTestError), ShouldEqual, true)
|
|
So(len(repoNames), ShouldEqual, 0)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("GetAllRepoNames HGetAll succeeds", func() {
|
|
mock.ExpectHGetAll(metaDB.RepoMetaKey).SetVal(
|
|
map[string]string{
|
|
"repo1": "meta1",
|
|
"repo2": "meta2",
|
|
"repo3": "meta3",
|
|
},
|
|
)
|
|
|
|
repoNames, err := metaDB.GetAllRepoNames()
|
|
So(err, ShouldBeNil)
|
|
So(len(repoNames), ShouldEqual, 3)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del RepoMetaKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del ImageMetaKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del RepoBlobsKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoBlobsKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del RepoLastUpdatedKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoBlobsKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoLastUpdatedKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del UserDataKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoBlobsKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoLastUpdatedKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.UserDataKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del UserAPIKeysKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoBlobsKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoLastUpdatedKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.UserDataKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.UserAPIKeysKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("ResetDB Del VersionKey error", func() {
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectDel(metaDB.RepoMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.ImageMetaKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoBlobsKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.RepoLastUpdatedKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.UserDataKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.UserAPIKeysKey).SetVal(0)
|
|
mock.ExpectDel(metaDB.VersionKey).SetErr(ErrTestError)
|
|
|
|
err := metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("DeleteRepoMeta Del RepoMetaKey error", func() {
|
|
mock.Regexp().ExpectSetNX(metaDB.LocksKey+":Repo:repo", `.*`, 8*time.Second).
|
|
SetVal(true)
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectHDel(metaDB.RepoMetaKey, "repo").SetErr(ErrTestError)
|
|
|
|
err := metaDB.DeleteRepoMeta("repo")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("DeleteRepoMeta Del RepoBlobsKey error", func() {
|
|
mock.Regexp().ExpectSetNX(metaDB.LocksKey+":Repo:repo", `.*`, 8*time.Second).
|
|
SetVal(true)
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectHDel(metaDB.RepoMetaKey, "repo").SetVal(0)
|
|
mock.ExpectHDel(metaDB.RepoBlobsKey, "repo").SetErr(ErrTestError)
|
|
|
|
err := metaDB.DeleteRepoMeta("repo")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("DeleteRepoMeta Del RepoLastUpdatedKey error", func() {
|
|
mock.Regexp().ExpectSetNX(metaDB.LocksKey+":Repo:repo", `.*`, 8*time.Second).
|
|
SetVal(true)
|
|
mock.ExpectTxPipeline()
|
|
mock.ExpectHDel(metaDB.RepoMetaKey, "repo").SetVal(0)
|
|
mock.ExpectHDel(metaDB.RepoBlobsKey, "repo").SetVal(0)
|
|
mock.ExpectHDel(metaDB.RepoLastUpdatedKey, "repo").SetErr(ErrTestError)
|
|
|
|
err := metaDB.DeleteRepoMeta("repo")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = mock.ExpectationsWereMet()
|
|
So(err, ShouldBeNil)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRedisRepoMeta(t *testing.T) {
|
|
miniRedis := miniredis.RunT(t)
|
|
|
|
Convey("Test repometa implementation", t, func() {
|
|
log := log.NewLogger("debug", "")
|
|
So(log, ShouldNotBeNil)
|
|
|
|
opts, err := goredis.ParseURL("redis://" + miniRedis.Addr())
|
|
So(err, ShouldBeNil)
|
|
|
|
client := goredis.NewClient(opts)
|
|
defer DumpKeys(t, client) // Troubleshoot test failures
|
|
|
|
params := redis.DBDriverParameters{KeyPrefix: "zot"}
|
|
|
|
metaDB, err := redis.New(client, params, log)
|
|
So(err, ShouldBeNil)
|
|
|
|
Convey("Test repoMeta ops", func() {
|
|
ctx := context.Background()
|
|
|
|
// Create/Get repo meta
|
|
for i := range 5 {
|
|
repoName := fmt.Sprintf("repo%d", i+1)
|
|
digest := fmt.Sprintf("dig%d", i+1)
|
|
|
|
initialRepoMeta := mTypes.RepoMeta{
|
|
Name: repoName,
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{"tag": {Digest: digest}},
|
|
|
|
Statistics: map[mTypes.ImageDigest]mTypes.DescriptorStatistics{},
|
|
Signatures: map[mTypes.ImageDigest]mTypes.ManifestSignatures{},
|
|
Referrers: map[mTypes.ImageDigest][]mTypes.ReferrerInfo{"digest": {{Digest: digest}}},
|
|
}
|
|
|
|
err = metaDB.SetRepoMeta(repoName, initialRepoMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
expectedRepoMeta, err := metaDB.GetRepoMeta(ctx, repoName)
|
|
So(err, ShouldBeNil)
|
|
|
|
So(expectedRepoMeta.Name, ShouldEqual, initialRepoMeta.Name)
|
|
So(expectedRepoMeta.Tags["tag"].Digest, ShouldEqual, initialRepoMeta.Tags["tag"].Digest)
|
|
}
|
|
|
|
// Get Multiple, Filter and Delete repo meta
|
|
repoMetas, err := metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool {
|
|
if strings.Contains(repoMeta.Name, "repo1") || strings.Contains(repoMeta.Name, "repo4") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
})
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 2)
|
|
So(repoMetas[0].Name, ShouldNotEqual, repoMetas[1].Name)
|
|
|
|
for _, repoMeta := range repoMetas {
|
|
So(repoMeta.Name, ShouldBeIn, []string{"repo1", "repo4"})
|
|
}
|
|
|
|
repoMetas, err = metaDB.FilterRepos(ctx,
|
|
func(repo string) bool {
|
|
return true
|
|
},
|
|
func(repoMeta mTypes.RepoMeta) bool {
|
|
if strings.Contains(repoMeta.Tags["tag"].Digest, "dig2") ||
|
|
strings.Contains(repoMeta.Tags["tag"].Digest, "dig5") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
},
|
|
)
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 2)
|
|
So(repoMetas[0].Tags["tag"].Digest, ShouldNotEqual, repoMetas[1].Tags["tag"].Digest)
|
|
|
|
for _, repoMeta := range repoMetas {
|
|
So(repoMeta.Tags["tag"].Digest, ShouldBeIn, []string{"dig2", "dig5"})
|
|
}
|
|
|
|
repoNames, err := metaDB.GetAllRepoNames()
|
|
So(err, ShouldBeNil)
|
|
So(len(repoNames), ShouldEqual, 5)
|
|
|
|
err = metaDB.DeleteRepoMeta("repo2")
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMeta, err := metaDB.GetRepoMeta(ctx, "repo2")
|
|
So(err, ShouldNotBeNil)
|
|
So(repoMeta.Name, ShouldBeEmpty)
|
|
|
|
repoNames, err = metaDB.GetAllRepoNames()
|
|
So(err, ShouldBeNil)
|
|
So(len(repoNames), ShouldEqual, 4)
|
|
|
|
repoMetas, err = metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 4)
|
|
|
|
repoMetas, err = metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return false })
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 0)
|
|
|
|
repoMetas, err = metaDB.FilterRepos(ctx,
|
|
func(repo string) bool {
|
|
result := strings.Contains(repo, "repo5")
|
|
|
|
return result
|
|
},
|
|
func(repoMeta mTypes.RepoMeta) bool {
|
|
if strings.Contains(repoMeta.Tags["tag"].Digest, "dig3") ||
|
|
strings.Contains(repoMeta.Tags["tag"].Digest, "dig5") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
},
|
|
)
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 1)
|
|
So(repoMetas[0].Tags["tag"].Digest, ShouldEqual, "dig5")
|
|
|
|
repoMetas, err = metaDB.SearchRepos(ctx, "repo")
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 4)
|
|
|
|
repoMetas, err = metaDB.SearchRepos(ctx, "epo3")
|
|
So(err, ShouldBeNil)
|
|
So(len(repoMetas), ShouldEqual, 1)
|
|
|
|
// Stars
|
|
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo1")
|
|
So(err, ShouldBeNil)
|
|
So(repoMeta, ShouldNotBeNil)
|
|
So(repoMeta.StarCount, ShouldEqual, 0)
|
|
|
|
err = metaDB.IncrementRepoStars("repo1")
|
|
So(err, ShouldBeNil)
|
|
err = metaDB.IncrementRepoStars("repo1")
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo1")
|
|
So(err, ShouldBeNil)
|
|
So(repoMeta, ShouldNotBeNil)
|
|
So(repoMeta.StarCount, ShouldEqual, 2)
|
|
|
|
err = metaDB.DecrementRepoStars("repo1")
|
|
So(err, ShouldBeNil)
|
|
err = metaDB.DecrementRepoStars("repo1")
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo1")
|
|
So(err, ShouldBeNil)
|
|
So(repoMeta, ShouldNotBeNil)
|
|
So(repoMeta.StarCount, ShouldEqual, 0)
|
|
|
|
err = metaDB.DecrementRepoStars("repo1")
|
|
So(err, ShouldBeNil)
|
|
|
|
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo1")
|
|
So(err, ShouldBeNil)
|
|
So(repoMeta, ShouldNotBeNil)
|
|
So(repoMeta.StarCount, ShouldEqual, 0)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRedisUnreachable(t *testing.T) {
|
|
Convey("Redis unreachable", t, func() {
|
|
miniRedis := miniredis.RunT(t)
|
|
|
|
log := log.NewLogger("debug", "")
|
|
So(log, ShouldNotBeNil)
|
|
|
|
connOpts, err := goredis.ParseURL("redis://" + miniRedis.Addr())
|
|
So(err, ShouldBeNil)
|
|
workingClient := goredis.NewClient(connOpts)
|
|
|
|
params := redis.DBDriverParameters{KeyPrefix: "zot"}
|
|
|
|
metaDB, err := redis.New(workingClient, params, log)
|
|
So(err, ShouldBeNil)
|
|
So(metaDB, ShouldNotBeNil)
|
|
|
|
connOpts, err = goredis.ParseURL("redis://127.0.0.1:" + test.GetFreePort())
|
|
So(err, ShouldBeNil)
|
|
brokenClient := goredis.NewClient(connOpts)
|
|
|
|
// Replace connection with the unreachable server
|
|
metaDB.Client = brokenClient
|
|
|
|
metaDB.SetImageTrustStore(imgTrustStore{})
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
repo := "repo"
|
|
reference := "tag"
|
|
digest := godigest.FromString("SomeString")
|
|
image := CreateDefaultImage()
|
|
imageMeta := image.AsImageMeta()
|
|
|
|
err = metaDB.SetImageMeta(digest, imageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.SetRepoReference(ctx, repo, reference, imageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.SearchRepos(ctx, repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.SearchTags(ctx, repo+":"+reference)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.FilterRepos(ctx, mTypes.AcceptAllRepoNames, mTypes.AcceptAllRepoMeta)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetRepoMeta(ctx, repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetFullImageMeta(ctx, repo, reference)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetImageMeta(digest)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.AddManifestSignature(repo, digest, mTypes.SignatureMetadata{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.DeleteSignature(repo, digest, mTypes.SignatureMetadata{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.UpdateSignaturesValidity(ctx, repo, digest)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.IncrementRepoStars(repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.DecrementRepoStars(repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.SetRepoMeta(repo, mTypes.RepoMeta{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.DeleteRepoMeta(repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetReferrersInfo(repo, digest, []string{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.UpdateStatsOnDownload(repo, reference)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.FilterImageMeta(ctx, []string{digest.String()})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.RemoveRepoReference(repo, reference, digest)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.ResetRepoReferences(repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
t := metaDB.GetRepoLastUpdated(repo)
|
|
So(t, ShouldEqual, time.Time{})
|
|
|
|
_, err = metaDB.GetAllRepoNames()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.ResetDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.PatchDB()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetStarredRepos(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetBookmarkedRepos(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.ToggleStarRepo(ctx, repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.ToggleBookmarkRepo(ctx, repo)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.SetUserGroups(ctx, []string{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetUserGroups(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.DeleteUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetUserAPIKeyInfo("hash")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.GetUserAPIKeys(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.AddUserAPIKey(ctx, "hash", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
_, err = metaDB.IsAPIKeyExpired(ctx, "hash")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.UpdateUserAPIKeyLastUsed(ctx, "hash")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.DeleteUserAPIKey(ctx, "test")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestWrapperErrors(t *testing.T) {
|
|
image := CreateDefaultImage()
|
|
imageMeta := image.AsImageMeta()
|
|
multiarchImageMeta := CreateMultiarchWith().Images([]Image{image}).Build().AsImageMeta()
|
|
|
|
badProtoBlob := []byte("bad-repo-meta")
|
|
|
|
goodRepoMetaBlob, err := proto.Marshal(&proto_go.RepoMeta{Name: "repo"})
|
|
if err != nil {
|
|
t.FailNow()
|
|
}
|
|
|
|
Convey("Errors", t, func() {
|
|
miniRedis := miniredis.RunT(t)
|
|
|
|
log := log.NewLogger("debug", "")
|
|
So(log, ShouldNotBeNil)
|
|
|
|
opts, err := goredis.ParseURL("redis://" + miniRedis.Addr())
|
|
So(err, ShouldBeNil)
|
|
|
|
client := goredis.NewClient(opts)
|
|
params := redis.DBDriverParameters{KeyPrefix: keyPrefix}
|
|
|
|
metaDB, err := redis.New(client, params, log)
|
|
So(metaDB, ShouldNotBeNil)
|
|
So(err, ShouldBeNil)
|
|
|
|
metaDB.SetImageTrustStore(imgTrustStore{})
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
Convey("RemoveRepoReference", func() {
|
|
Convey("getProtoRepoMeta errors", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.RemoveRepoReference("repo", "ref", imageMeta.Digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("getProtoImageMeta errors", func() {
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: imageMeta.Digest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(imageMeta.Digest, badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.RemoveRepoReference("repo", "ref", imageMeta.Digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoBlobs errors", func() {
|
|
err := metaDB.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setRepoBlobInfo("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.RemoveRepoReference("repo", "ref", imageMeta.Digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("UpdateSignaturesValidity", func() {
|
|
metaDB.SetImageTrustStore(imgTrustStore{})
|
|
|
|
digest := image.Digest()
|
|
|
|
ctx := context.Background()
|
|
|
|
Convey("image meta blob not found", func() {
|
|
err := metaDB.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("image meta unmarshal fail", func() {
|
|
err := setImageMeta(digest, badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("repo meta blob not found", func() {
|
|
err := metaDB.SetImageMeta(digest, imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("repo meta unmarshal fail", func() {
|
|
err := metaDB.SetImageMeta(digest, imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateSignaturesValidity(ctx, "repo", digest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetRepoLastUpdated", func() {
|
|
Convey("bad blob in db", func() {
|
|
err := setRepoLastUpdated("repo", []byte("bad-blob"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
lastUpdated := metaDB.GetRepoLastUpdated("repo")
|
|
So(lastUpdated, ShouldEqual, time.Time{})
|
|
})
|
|
|
|
Convey("empty blob in db", func() {
|
|
err := setRepoLastUpdated("repo", []byte(""), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
lastUpdated := metaDB.GetRepoLastUpdated("repo")
|
|
So(lastUpdated, ShouldEqual, time.Time{})
|
|
})
|
|
})
|
|
|
|
Convey("UpdateStatsOnDownload", func() {
|
|
Convey("repo meta not found", func() {
|
|
err = metaDB.UpdateStatsOnDownload("repo", "ref")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateStatsOnDownload("repo", "ref")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ref is tag and tag is not found", func() {
|
|
err := metaDB.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateStatsOnDownload("repo", "not-found-tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("digest not found in statistics", func() {
|
|
err := metaDB.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateStatsOnDownload("repo", godigest.FromString("not-found").String())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetReferrersInfo", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetReferrersInfo("repo", "refDig", []string{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("ResetRepoReferences", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.ResetRepoReferences("repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("DecrementRepoStars", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.DecrementRepoStars("repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("IncrementRepoStars", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.IncrementRepoStars("repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("DeleteSignature", func() {
|
|
Convey("repo meta not found", func() {
|
|
err = metaDB.DeleteSignature("repo", godigest.FromString("dig"), mTypes.SignatureMetadata{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.DeleteSignature("repo", godigest.FromString("dig"), mTypes.SignatureMetadata{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("AddManifestSignature", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.AddManifestSignature("repo", godigest.FromString("dig"), mTypes.SignatureMetadata{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetMultipleRepoMeta", func() {
|
|
Convey("unmarshalProtoRepoMeta error", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetImageMeta", func() {
|
|
Convey("malformed image manifest", func() {
|
|
badImageDigest := godigest.FromString("bad-image-manifest")
|
|
|
|
err = setImageMeta(badImageDigest, badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err := metaDB.GetImageMeta(badImageDigest)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("good image index, malformed inside manifest", func() {
|
|
goodIndexBadManifestDigest := godigest.FromString("good-index-bad-manifests")
|
|
|
|
err = metaDB.SetImageMeta(goodIndexBadManifestDigest, multiarchImageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err := metaDB.GetImageMeta(image.Digest())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("GetFullImageMeta", func() {
|
|
Convey("repo meta not found", func() {
|
|
_, err := metaDB.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoMeta fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("tag not found", func() {
|
|
err := setRepoMeta("repo", goodRepoMetaBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetFullImageMeta(ctx, "repo", "tag-not-found")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("getProtoImageMeta fails", func() {
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: godigest.FromString("not-found").String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("image is index, fail to get manifests", func() {
|
|
err := metaDB.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"tag": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: multiarchImageMeta.Digest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetFullImageMeta(ctx, "repo", "tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("FilterRepos", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.FilterRepos(ctx, mTypes.AcceptAllRepoNames, mTypes.AcceptAllRepoMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SearchTags", func() {
|
|
Convey("unmarshalProtoRepoMeta fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
// manifests are missing
|
|
_, err = metaDB.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("found repo meta", func() {
|
|
Convey("bad image manifest", func() {
|
|
badImageDigest := godigest.FromString("bad-image-manifest")
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-manifest": {
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: badImageDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badImageDigest, badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("bad image index", func() {
|
|
badIndexDigest := godigest.FromString("bad-image-manifest")
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-image-index": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: badIndexDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(badIndexDigest, badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("good image index, bad inside manifest", func() {
|
|
goodIndexBadManifestDigest := godigest.FromString("good-index-bad-manifests")
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"good-index-bad-manifests": {
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Digest: goodIndexBadManifestDigest.String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.SetImageMeta(goodIndexBadManifestDigest, multiarchImageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.SearchTags(ctx, "repo:")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
Convey("bad media type", func() {
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"mad-media-type": {
|
|
MediaType: "bad media type",
|
|
Digest: godigest.FromString("dig").String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.SearchTags(ctx, "repo:")
|
|
So(err, ShouldBeNil)
|
|
})
|
|
})
|
|
})
|
|
|
|
Convey("FilterTags", func() {
|
|
Convey("unmarshalProtoRepoMeta fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("bad media Type fails", func() {
|
|
err := metaDB.SetRepoMeta("repo", mTypes.RepoMeta{
|
|
Name: "repo",
|
|
Tags: map[mTypes.Tag]mTypes.Descriptor{
|
|
"bad-repo-meta": {
|
|
MediaType: "bad media type",
|
|
Digest: godigest.FromString("dig").String(),
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
|
|
So(err, ShouldBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("SearchRepos", func() {
|
|
Convey("unmarshalProtoRepoMeta fails", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
// manifests are missing
|
|
_, err = metaDB.SearchRepos(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("FilterImageMeta", func() {
|
|
Convey("MediaType ImageIndex, getProtoImageMeta fails", func() {
|
|
err := metaDB.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setImageMeta(image.Digest(), badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
// manifests are missing
|
|
_, err = metaDB.FilterImageMeta(ctx, []string{multiarchImageMeta.Digest.String()})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("SetRepoReference", func() {
|
|
Convey("getProtoRepoMeta errors", func() {
|
|
err := setRepoMeta("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("unmarshalProtoRepoBlobs errors", func() {
|
|
err := setRepoMeta("repo", goodRepoMetaBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = setRepoBlobInfo("repo", badProtoBlob, client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.SetRepoReference(ctx, "repo", "tag", imageMeta)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
|
|
Convey("AddUserAPIKey", func() {
|
|
// no userid found
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.AddUserAPIKey(ctx, "", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("UpdateUserAPIKey", func() {
|
|
// no userid found
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.UpdateUserAPIKeyLastUsed(ctx, "") //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserAPIKey", func() {
|
|
err = metaDB.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.AddUserAPIKey(ctx, "hashedKey", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldBeNil)
|
|
|
|
Convey("userdata not found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err := metaDB.DeleteUserData(ctx)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.DeleteUserAPIKey(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.DeleteUserAPIKey(ctx, "test") //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = deleteUserDataBucket(client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.DeleteUserAPIKey(ctx, "") //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserAPIKeyInfo", func() {
|
|
err = deleteUserAPIKeysBucket(client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetUserAPIKeyInfo("")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserData", func() {
|
|
err = setUserData("test", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = deleteUserAPIKeysBucket(client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserData", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = deleteUserDataBucket(client)
|
|
So(err, ShouldBeNil)
|
|
|
|
userAc = reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
ctx = userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.SetUserData(ctx, mTypes.UserData{}) //nolint: contextcheck
|
|
So(err, ShouldBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserData", func() {
|
|
userAc = reqCtx.NewUserAccessControl()
|
|
ctx = userAc.DeriveContext(context.Background()) //nolint:fatcontext // test code
|
|
|
|
err = metaDB.DeleteUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = deleteUserDataBucket(client)
|
|
So(err, ShouldBeNil)
|
|
|
|
userAc = reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("test")
|
|
ctx = userAc.DeriveContext(context.Background())
|
|
|
|
err = metaDB.DeleteUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserGroups and SetUserGroups", func() {
|
|
userAc = reqCtx.NewUserAccessControl()
|
|
ctx = userAc.DeriveContext(context.Background()) //nolint:fatcontext // test code
|
|
|
|
_, err := metaDB.GetUserGroups(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
err = metaDB.SetUserGroups(ctx, []string{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := metaDB.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo, no repoMeta found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setRepoMeta("repo", []byte("bad repo"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleStarRepo, bad repoMeta found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
_, err = metaDB.ToggleStarRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleBookmarkRepo bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := metaDB.ToggleBookmarkRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ToggleBookmarkRepo bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.ToggleBookmarkRepo(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := metaDB.GetUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := metaDB.SetUserData(ctx, mTypes.UserData{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserGroups bad context errors", func() {
|
|
_, err := metaDB.GetUserGroups(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err = metaDB.GetUserGroups(ctx) //nolint: contextcheck
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserGroups bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := metaDB.SetUserGroups(ctx, []string{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("SetUserGroups bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.SetUserGroups(ctx, []string{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("AddUserAPIKey bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := metaDB.AddUserAPIKey(ctx, "", &mTypes.APIKeyDetails{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("AddUserAPIKey bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.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 := metaDB.DeleteUserAPIKey(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserAPIKeys bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.GetUserAPIKeys(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("IsAPIKeyExpired bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err = metaDB.IsAPIKeyExpired(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("UpdateUserAPIKeyLastUsed bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := metaDB.UpdateUserAPIKeyLastUsed(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("UpdateUserAPIKeyLastUsed bad UserData found", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setUserData("username", []byte("dsa8"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
err = metaDB.UpdateUserAPIKeyLastUsed(ctx, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DeleteUserData bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
err := metaDB.DeleteUserData(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetStarredRepos bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := metaDB.GetStarredRepos(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetBookmarkedRepos bad context errors", func() {
|
|
uacKey := reqCtx.GetContextKey()
|
|
ctx := context.WithValue(context.Background(), uacKey, "bad context")
|
|
|
|
_, err := metaDB.GetBookmarkedRepos(ctx)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetUserRepoMeta unmarshal error", func() {
|
|
userAc := reqCtx.NewUserAccessControl()
|
|
userAc.SetUsername("username")
|
|
userAc.SetGlobPatterns("read", map[string]bool{
|
|
"repo": true,
|
|
})
|
|
|
|
ctx := userAc.DeriveContext(context.Background())
|
|
|
|
err = setRepoMeta("repo", []byte("bad repo"), client)
|
|
So(err, ShouldBeNil)
|
|
|
|
_, err := metaDB.GetRepoMeta(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
}
|
|
|
|
func setRepoMeta(repo string, blob []byte, client *goredis.Client) error { //nolint: unparam
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.RepoMetaBucket
|
|
|
|
return client.HSet(ctx, key, repo, blob).Err()
|
|
}
|
|
|
|
func setRepoLastUpdated(repo string, blob []byte, client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.RepoLastUpdatedBucket
|
|
|
|
return client.HSet(ctx, key, repo, blob).Err()
|
|
}
|
|
|
|
func setImageMeta(digest godigest.Digest, blob []byte, client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.ImageMetaBucket
|
|
|
|
return client.HSet(ctx, key, digest.String(), blob).Err()
|
|
}
|
|
|
|
func setRepoBlobInfo(repo string, blob []byte, client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.RepoBlobsBucket
|
|
|
|
return client.HSet(ctx, key, repo, blob).Err()
|
|
}
|
|
|
|
func setUserData(userID string, blob []byte, client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.UserDataBucket
|
|
|
|
return client.HSet(ctx, key, userID, blob).Err()
|
|
}
|
|
|
|
func deleteUserDataBucket(client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.UserDataBucket
|
|
|
|
return client.Del(ctx, key).Err()
|
|
}
|
|
|
|
func deleteUserAPIKeysBucket(client *goredis.Client) error {
|
|
ctx := context.Background()
|
|
key := keyPrefix + ":" + redis.UserAPIKeysBucket
|
|
|
|
return client.Del(ctx, key).Err()
|
|
}
|
|
|
|
func DumpKeys(t *testing.T, client goredis.UniversalClient) {
|
|
t.Helper()
|
|
|
|
// Retrieve all keys
|
|
keys, err := client.Keys(context.Background(), "*").Result()
|
|
if err != nil {
|
|
t.Log("Error retrieving keys:", err)
|
|
|
|
return
|
|
}
|
|
|
|
// Print the keys
|
|
t.Log("Keys in Redis:")
|
|
|
|
for _, key := range keys {
|
|
keyType, err := client.Type(context.Background(), key).Result()
|
|
if err != nil {
|
|
t.Logf("Error retrieving type for key %s: %v\n", key, err)
|
|
|
|
continue
|
|
}
|
|
|
|
var value string
|
|
|
|
switch keyType {
|
|
case "string":
|
|
value, err = client.Get(context.Background(), key).Result()
|
|
case "list":
|
|
values, err := client.LRange(context.Background(), key, 0, -1).Result()
|
|
if err == nil {
|
|
value = fmt.Sprintf("%v", values)
|
|
}
|
|
case "hash":
|
|
values, err := client.HGetAll(context.Background(), key).Result()
|
|
if err == nil {
|
|
value = fmt.Sprintf("%v", values)
|
|
}
|
|
case "set":
|
|
values, err := client.SMembers(context.Background(), key).Result()
|
|
if err == nil {
|
|
value = fmt.Sprintf("%v", values)
|
|
}
|
|
case "zset":
|
|
values, err := client.ZRange(context.Background(), key, 0, -1).Result()
|
|
if err == nil {
|
|
value = fmt.Sprintf("%v", values)
|
|
}
|
|
default:
|
|
value = "Unsupported type"
|
|
}
|
|
|
|
if err != nil {
|
|
t.Logf("Error retrieving value for key %s: %v\n", key, err)
|
|
} else {
|
|
t.Logf("Key: %s, Type: %s, Value: %s\n", key, keyType, value)
|
|
}
|
|
}
|
|
}
|