0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-23 22:27:35 -05:00
zot/pkg/meta/repodb/repodb_test.go
LaurentiuNiculae 91e14bee00
fix(loadrepodb): statistics are now preserved after reloading zot (#1289)
- before, the download count for a manifest and repo star count were lost after reload

- now we are keeping these values when we reset the repo-meta structure

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
2023-03-23 11:08:11 -07:00

2117 lines
67 KiB
Go

package repodb_test
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"os"
"path"
"strconv"
"strings"
"testing"
"time"
guuid "github.com/gofrs/uuid"
godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/meta/repodb"
bolt "zotregistry.io/zot/pkg/meta/repodb/boltdb-wrapper"
"zotregistry.io/zot/pkg/meta/repodb/common"
dynamo "zotregistry.io/zot/pkg/meta/repodb/dynamodb-wrapper"
dynamoParams "zotregistry.io/zot/pkg/meta/repodb/dynamodb-wrapper/params"
localCtx "zotregistry.io/zot/pkg/requestcontext"
"zotregistry.io/zot/pkg/test"
)
const (
LINUX = "linux"
WINDOWS = "windows"
AMD = "amd"
)
func TestBoltDBWrapper(t *testing.T) {
Convey("BoltDB Wrapper creation", t, func() {
boltDBParams := bolt.DBParameters{}
searchDB, err := bolt.NewBoltDBWrapper(boltDBParams)
So(searchDB, ShouldNotBeNil)
So(err, ShouldBeNil)
err = os.Chmod("repo.db", 0o200)
So(err, ShouldBeNil)
searchDB, err = bolt.NewBoltDBWrapper(boltDBParams)
So(searchDB, ShouldBeNil)
So(err, ShouldNotBeNil)
err = os.Chmod("repo.db", 0o600)
So(err, ShouldBeNil)
defer os.Remove("repo.db")
})
Convey("BoltDB Wrapper", t, func() {
boltDBParams := bolt.DBParameters{}
boltdbWrapper, err := bolt.NewBoltDBWrapper(boltDBParams)
defer os.Remove("repo.db")
So(boltdbWrapper, ShouldNotBeNil)
So(err, ShouldBeNil)
RunRepoDBTests(boltdbWrapper)
})
}
func TestDynamoDBWrapper(t *testing.T) {
skipIt(t)
uuid, err := guuid.NewV4()
if err != nil {
panic(err)
}
repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
artifactDataTablename := "ArtifactDataTable" + uuid.String()
Convey("DynamoDB Wrapper", t, func() {
dynamoDBDriverParams := dynamoParams.DBDriverParameters{
Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"),
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: indexDataTablename,
ArtifactDataTablename: artifactDataTablename,
VersionTablename: versionTablename,
Region: "us-east-2",
}
dynamoDriver, err := dynamo.NewDynamoDBWrapper(dynamoDBDriverParams)
So(dynamoDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
resetDynamoDBTables := func() error {
err := dynamoDriver.ResetRepoMetaTable()
if err != nil {
return err
}
err = dynamoDriver.ResetManifestDataTable()
return err
}
RunRepoDBTests(dynamoDriver, resetDynamoDBTables)
})
}
func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
Convey("Test RepoDB Interface implementation", func() {
for _, prepFunc := range preparationFuncs {
err := prepFunc()
So(err, ShouldBeNil)
}
Convey("Test SetManifestData and GetManifestData", func() {
configBlob, manifestBlob, err := generateTestImage()
So(err, ShouldBeNil)
manifestDigest := godigest.FromBytes(manifestBlob)
err = repoDB.SetManifestData(manifestDigest, repodb.ManifestData{
ManifestBlob: manifestBlob,
ConfigBlob: configBlob,
})
So(err, ShouldBeNil)
mm, err := repoDB.GetManifestData(manifestDigest)
So(err, ShouldBeNil)
So(mm.ManifestBlob, ShouldResemble, manifestBlob)
So(mm.ConfigBlob, ShouldResemble, configBlob)
})
Convey("Test GetManifestMeta fails", func() {
_, err := repoDB.GetManifestMeta("repo", "bad digest")
So(err, ShouldNotBeNil)
})
Convey("Test SetManifestMeta", func() {
Convey("RepoMeta not found", func() {
var (
manifestDigest = godigest.FromString("dig")
manifestBlob = []byte("manifestBlob")
configBlob = []byte("configBlob")
signatures = repodb.ManifestSignatures{
"digest1": []repodb.SignatureInfo{
{
SignatureManifestDigest: "signatureDigest",
LayersInfo: []repodb.LayerInfo{
{
LayerDigest: "layerDigest",
LayerContent: []byte("layerContent"),
},
},
},
},
}
)
err := repoDB.SetManifestMeta("repo", manifestDigest, repodb.ManifestMetadata{
ManifestBlob: manifestBlob,
ConfigBlob: configBlob,
DownloadCount: 10,
Signatures: signatures,
})
So(err, ShouldBeNil)
manifestMeta, err := repoDB.GetManifestMeta("repo", manifestDigest)
So(err, ShouldBeNil)
So(manifestMeta.ManifestBlob, ShouldResemble, manifestBlob)
So(manifestMeta.ConfigBlob, ShouldResemble, configBlob)
So(manifestMeta.DownloadCount, ShouldEqual, 10)
So(manifestMeta.Signatures, ShouldResemble, signatures)
})
})
Convey("Test SetRepoReference", func() {
// test behaviours
var (
repo1 = "repo1"
repo2 = "repo2"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifes2")
)
Convey("Setting a good repo", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Name, ShouldResemble, repo1)
So(repoMeta.Tags[tag1].Digest, ShouldEqual, manifestDigest1)
err = repoDB.SetRepoMeta(repo2, repodb.RepoMetadata{Tags: map[string]repodb.Descriptor{
tag2: {
Digest: manifestDigest2.String(),
},
}})
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo2)
So(err, ShouldBeNil)
So(repoMeta.Name, ShouldResemble, repo2)
So(repoMeta.Tags[tag2].Digest, ShouldEqual, manifestDigest2)
})
Convey("Setting a good repo using a digest", func() {
_, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldNotBeNil)
digest := godigest.FromString("digest")
err = repoDB.SetRepoReference(repo1, digest.String(), digest,
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Name, ShouldResemble, repo1)
})
Convey("Set multiple tags for repo", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Tags[tag1].Digest, ShouldEqual, manifestDigest1)
So(repoMeta.Tags[tag2].Digest, ShouldEqual, manifestDigest2)
})
Convey("Set multiple repos", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repoMeta1, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
repoMeta2, err := repoDB.GetRepoMeta(repo2)
So(err, ShouldBeNil)
So(repoMeta1.Tags[tag1].Digest, ShouldResemble, manifestDigest1.String())
So(repoMeta2.Tags[tag2].Digest, ShouldResemble, manifestDigest2.String())
})
Convey("Setting a repo with invalid fields", func() {
Convey("Repo name is not valid", func() {
err := repoDB.SetRepoReference("", tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
Convey("Tag is not valid", func() {
err := repoDB.SetRepoReference(repo1, "", manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
Convey("Manifest Digest is not valid", func() {
err := repoDB.SetRepoReference(repo1, tag1, "", ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
})
})
Convey("Test GetRepoMeta", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
repo2 = "repo2"
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifest2")
InexistentRepo = "InexistentRepo"
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
Convey("Get a existent repo", func() {
repoMeta1, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta1.Tags[tag1].Digest, ShouldResemble, manifestDigest1.String())
repoMeta2, err := repoDB.GetRepoMeta(repo2)
So(err, ShouldBeNil)
So(repoMeta2.Tags[tag2].Digest, ShouldResemble, manifestDigest2.String())
})
Convey("Get a repo that doesn't exist", func() {
repoMeta, err := repoDB.GetRepoMeta(InexistentRepo)
So(err, ShouldNotBeNil)
So(repoMeta, ShouldBeZeroValue)
})
})
Convey("Test DeleteRepoTag", func() {
var (
repo = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifest2")
)
err := repoDB.SetRepoReference(repo, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
Convey("Delete from repo a tag", func() {
_, err := repoDB.GetRepoMeta(repo)
So(err, ShouldBeNil)
err = repoDB.DeleteRepoTag(repo, tag1)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo)
So(err, ShouldBeNil)
_, ok := repoMeta.Tags[tag1]
So(ok, ShouldBeFalse)
So(repoMeta.Tags[tag2].Digest, ShouldResemble, manifestDigest2.String())
})
Convey("Delete inexistent tag from repo", func() {
err := repoDB.DeleteRepoTag(repo, "InexistentTag")
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo)
So(err, ShouldBeNil)
So(repoMeta.Tags[tag1].Digest, ShouldResemble, manifestDigest1.String())
So(repoMeta.Tags[tag2].Digest, ShouldResemble, manifestDigest2.String())
})
Convey("Delete from inexistent repo", func() {
err := repoDB.DeleteRepoTag("InexistentRepo", "InexistentTag")
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo)
So(err, ShouldBeNil)
So(repoMeta.Tags[tag1].Digest, ShouldResemble, manifestDigest1.String())
So(repoMeta.Tags[tag2].Digest, ShouldResemble, manifestDigest2.String())
})
})
Convey("Test GetMultipleRepoMeta", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifest2")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
Convey("Get all Repometa", func() {
repoMetaSlice, err := repoDB.GetMultipleRepoMeta(context.TODO(), func(repoMeta repodb.RepoMetadata) bool {
return true
}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repoMetaSlice), ShouldEqual, 2)
})
Convey("Get repo with a tag", func() {
repoMetaSlice, err := repoDB.GetMultipleRepoMeta(context.TODO(), func(repoMeta repodb.RepoMetadata) bool {
for tag := range repoMeta.Tags {
if tag == tag1 {
return true
}
}
return false
}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repoMetaSlice), ShouldEqual, 1)
So(repoMetaSlice[0].Tags[tag1].Digest == manifestDigest1.String(), ShouldBeTrue)
})
Convey("Wrong page input", func() {
repoMetaSlice, err := repoDB.GetMultipleRepoMeta(context.TODO(), func(repoMeta repodb.RepoMetadata) bool {
for tag := range repoMeta.Tags {
if tag == tag1 {
return true
}
}
return false
}, repodb.PageInput{Limit: -1, Offset: -1})
So(err, ShouldNotBeNil)
So(len(repoMetaSlice), ShouldEqual, 0)
})
})
Convey("Test IncrementRepoStars", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 1)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 2)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 3)
})
Convey("Test DecrementRepoStars", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 1)
err = repoDB.DecrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 0)
err = repoDB.DecrementRepoStars(repo1)
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Stars, ShouldEqual, 0)
repoMeta, err = repoDB.GetRepoMeta("badRepo")
So(err, ShouldNotBeNil)
})
Convey("Test GetRepoStars", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
stars, err := repoDB.GetRepoStars(repo1)
So(err, ShouldBeNil)
So(stars, ShouldEqual, 1)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
err = repoDB.IncrementRepoStars(repo1)
So(err, ShouldBeNil)
stars, err = repoDB.GetRepoStars(repo1)
So(err, ShouldBeNil)
So(stars, ShouldEqual, 3)
_, err = repoDB.GetRepoStars("badRepo")
So(err, ShouldNotBeNil)
})
Convey("Test IncrementImageDownloads", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
)
configBlob, manifestBlob, err := generateTestImage()
So(err, ShouldBeNil)
manifestDigest := godigest.FromBytes(manifestBlob)
err = repoDB.SetRepoReference(repo1, tag1, manifestDigest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest, repodb.ManifestMetadata{
ManifestBlob: manifestBlob,
ConfigBlob: configBlob,
})
So(err, ShouldBeNil)
err = repoDB.IncrementImageDownloads(repo1, tag1)
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 1)
err = repoDB.IncrementImageDownloads(repo1, tag1)
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 2)
_, err = repoDB.GetManifestMeta(repo1, "badManiestDigest")
So(err, ShouldNotBeNil)
})
Convey("Test AddImageSignature", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{})
So(err, ShouldBeNil)
err = repoDB.AddManifestSignature(repo1, manifestDigest1, repodb.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest",
})
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Signatures[manifestDigest1.String()]["cosign"][0].SignatureManifestDigest,
ShouldResemble, "digest")
_, err = repoDB.GetManifestMeta(repo1, "badDigest")
So(err, ShouldNotBeNil)
})
Convey("Test DeleteSignature", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{})
So(err, ShouldBeNil)
err = repoDB.AddManifestSignature(repo1, manifestDigest1, repodb.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest",
})
So(err, ShouldBeNil)
repoMeta, err := repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Signatures[manifestDigest1.String()]["cosign"][0].SignatureManifestDigest,
ShouldResemble, "digest")
err = repoDB.DeleteSignature(repo1, manifestDigest1, repodb.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest",
})
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta(repo1)
So(err, ShouldBeNil)
So(repoMeta.Signatures[manifestDigest1.String()]["cosign"], ShouldBeEmpty)
err = repoDB.DeleteSignature(repo1, "badDigest", repodb.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest",
})
So(err, ShouldNotBeNil)
})
Convey("Test SearchRepos", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
repo3 = "repo3"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifest2")
tag3 = "0.0.3"
manifestDigest3 = godigest.FromString("fake-manifest3")
ctx = context.Background()
emptyManifest ispec.Manifest
emptyConfig ispec.Manifest
)
emptyManifestBlob, err := json.Marshal(emptyManifest)
So(err, ShouldBeNil)
emptyConfigBlob, err := json.Marshal(emptyConfig)
So(err, ShouldBeNil)
emptyRepoMeta := repodb.ManifestMetadata{
ManifestBlob: emptyManifestBlob,
ConfigBlob: emptyConfigBlob,
}
Convey("Search all repos", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag3, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest3, emptyRepoMeta)
So(err, ShouldBeNil)
repos, manifestMetaMap, _, _, err := repoDB.SearchRepos(ctx, "", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(len(manifestMetaMap), ShouldEqual, 3)
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
})
Convey("Search a repo by name", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
repos, manifestMetaMap, _, _, err := repoDB.SearchRepos(ctx, repo1, repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(len(manifestMetaMap), ShouldEqual, 1)
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
})
Convey("Search non-existing repo by name", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repos, manifestMetaMap, _, _, err := repoDB.SearchRepos(ctx, "RepoThatDoesntExist", repodb.Filter{},
repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
So(len(manifestMetaMap), ShouldEqual, 0)
})
Convey("Search with partial match", func() {
err := repoDB.SetRepoReference("alpine", tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("pine", tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("golang", tag3, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta("alpine", manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta("pine", manifestDigest2, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta("golang", manifestDigest3, emptyRepoMeta)
So(err, ShouldBeNil)
repos, manifestMetaMap, _, _, err := repoDB.SearchRepos(ctx, "pine", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldNotContainKey, manifestDigest3.String())
})
Convey("Search multiple repos that share manifests", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag3, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
repos, manifestMetaMap, _, _, err := repoDB.SearchRepos(ctx, "", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 3)
So(len(manifestMetaMap), ShouldEqual, 1)
})
Convey("Search repos with access control", func() {
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag3, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
acCtx := localCtx.AccessControlContext{
ReadGlobPatterns: map[string]bool{
repo1: true,
repo2: true,
},
Username: "username",
}
authzCtxKey := localCtx.GetContextKey()
ctx := context.WithValue(context.Background(), authzCtxKey, acCtx)
repos, _, _, _, err := repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
for _, k := range repos {
So(k.Name, ShouldBeIn, []string{repo1, repo2})
}
})
Convey("Search paginated repos", func() {
reposCount := 50
repoNameBuilder := strings.Builder{}
for _, i := range rand.Perm(reposCount) {
manifestDigest := godigest.FromString("fakeManifest" + strconv.Itoa(i))
timeString := fmt.Sprintf("1%02d0-01-01 04:35", i)
createdTime, err := time.Parse("2006-01-02 15:04", timeString)
So(err, ShouldBeNil)
configContent := ispec.Image{
History: []ispec.History{
{
Created: &createdTime,
},
},
}
configBlob, err := json.Marshal(configContent)
So(err, ShouldBeNil)
manifestMeta := repodb.ManifestMetadata{
ManifestBlob: emptyManifestBlob,
ConfigBlob: configBlob,
DownloadCount: i,
}
repoName := "repo" + strconv.Itoa(i)
err = repoDB.SetRepoReference(repoName, tag1, manifestDigest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repoName, manifestDigest, manifestMeta)
So(err, ShouldBeNil)
repoNameBuilder.Reset()
}
repos, _, _, _, err := repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, reposCount)
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 20,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 20)
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 0,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo0")
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 1,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo1")
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 49,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo9")
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 49,
SortBy: repodb.AlphabeticDsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo0")
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 0,
SortBy: repodb.AlphabeticDsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo9")
// sort by downloads
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 0,
SortBy: repodb.Downloads,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo49")
// sort by last update
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 0,
SortBy: repodb.UpdateTime,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo49")
repos, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 100,
SortBy: repodb.UpdateTime,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
So(repos, ShouldBeEmpty)
})
Convey("Search with wrong pagination input", func() {
_, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 100,
SortBy: repodb.UpdateTime,
})
So(err, ShouldBeNil)
_, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: -1,
Offset: 100,
SortBy: repodb.UpdateTime,
})
So(err, ShouldNotBeNil)
_, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: -1,
SortBy: repodb.UpdateTime,
})
So(err, ShouldNotBeNil)
_, _, _, _, err = repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 1,
SortBy: repodb.SortCriteria("InvalidSortingCriteria"),
})
So(err, ShouldNotBeNil)
})
Convey("Search Repos with Indexes", func() {
var (
tag4 = "0.0.4"
indexDigest = godigest.FromString("Multiarch")
manifestDigest1 = godigest.FromString("manifestDigest1")
manifestDigest2 = godigest.FromString("manifestDigest2")
tag5 = "0.0.5"
manifestDigest3 = godigest.FromString("manifestDigest3")
)
err := repoDB.SetManifestData(manifestDigest1, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
config := ispec.Image{
Platform: ispec.Platform{
Architecture: "arch",
OS: "os",
},
}
confBlob, err := json.Marshal(config)
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestDigest2, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: confBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestDigest3, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
indexContent := ispec.Index{
MediaType: ispec.MediaTypeImageIndex,
Manifests: []ispec.Descriptor{
{
Digest: manifestDigest1,
},
{
Digest: manifestDigest2,
},
},
}
indexBlob, err := json.Marshal(indexContent)
So(err, ShouldBeNil)
err = repoDB.SetIndexData(indexDigest, repodb.IndexData{
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", tag4, indexDigest, ispec.MediaTypeImageIndex)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", tag5, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repos, manifestMetaMap, indexDataMap, _, err := repoDB.SearchRepos(ctx, "repo", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo")
So(repos[0].Tags, ShouldContainKey, tag4)
So(repos[0].Tags, ShouldContainKey, tag5)
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
So(indexDataMap, ShouldContainKey, indexDigest.String())
})
})
Convey("Test SearchTags", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
manifestDigest1 = godigest.FromString("fake-manifest1")
manifestDigest2 = godigest.FromString("fake-manifest2")
manifestDigest3 = godigest.FromString("fake-manifest3")
ctx = context.Background()
emptyManifest ispec.Manifest
emptyConfig ispec.Manifest
)
emptyManifestBlob, err := json.Marshal(emptyManifest)
So(err, ShouldBeNil)
emptyConfigBlob, err := json.Marshal(emptyConfig)
So(err, ShouldBeNil)
emptyRepoMeta := repodb.ManifestMetadata{
ManifestBlob: emptyManifestBlob,
ConfigBlob: emptyConfigBlob,
}
err = repoDB.SetRepoReference(repo1, "0.0.1", manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "0.0.2", manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "0.1.0", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "1.0.0", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "1.0.1", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, "0.0.1", manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest3, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest3, emptyRepoMeta)
So(err, ShouldBeNil)
Convey("With exact match", func() {
repos, manifestMetaMap, _, _, err := repoDB.SearchTags(ctx, "repo1:0.0.1", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(len(repos[0].Tags), ShouldEqual, 1)
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
})
Convey("With partial repo path", func() {
repos, manifestMetaMap, _, _, err := repoDB.SearchTags(ctx, "repo:0.0.1", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
So(len(manifestMetaMap), ShouldEqual, 0)
})
Convey("With partial tag", func() {
repos, manifestMetaMap, _, _, err := repoDB.SearchTags(ctx, "repo1:0.0", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(len(repos[0].Tags), ShouldEqual, 2)
So(repos[0].Tags, ShouldContainKey, "0.0.2")
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
repos, manifestMetaMap, _, _, err = repoDB.SearchTags(ctx, "repo1:0.", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(len(repos[0].Tags), ShouldEqual, 3)
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(repos[0].Tags, ShouldContainKey, "0.0.2")
So(repos[0].Tags, ShouldContainKey, "0.1.0")
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
})
Convey("With bad query", func() {
repos, manifestMetaMap, _, _, err := repoDB.SearchTags(ctx, "repo:0.0.1:test", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldNotBeNil)
So(len(repos), ShouldEqual, 0)
So(len(manifestMetaMap), ShouldEqual, 0)
})
Convey("Search with access control", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
repo3 = "repo3"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
tag3 = "0.0.3"
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag2, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag3, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
config := ispec.Image{}
configBlob, err := json.Marshal(config)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob})
So(err, ShouldBeNil)
acCtx := localCtx.AccessControlContext{
ReadGlobPatterns: map[string]bool{
repo1: true,
repo2: false,
},
Username: "username",
}
authzCtxKey := localCtx.GetContextKey()
ctx := context.WithValue(context.Background(), authzCtxKey, acCtx)
repos, _, _, _, err := repoDB.SearchTags(ctx, "repo1:", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, repo1)
repos, _, _, _, err = repoDB.SearchTags(ctx, "repo2:", repodb.Filter{}, repodb.PageInput{})
So(err, ShouldBeNil)
So(repos, ShouldBeEmpty)
})
Convey("With wrong pagination input", func() {
repos, _, _, _, err := repoDB.SearchTags(ctx, "repo2:", repodb.Filter{}, repodb.PageInput{
Limit: -1,
})
So(err, ShouldNotBeNil)
So(repos, ShouldBeEmpty)
})
Convey("Search Tags with Indexes", func() {
var (
tag4 = "0.0.4"
indexDigest = godigest.FromString("Multiarch")
manifestDigest1 = godigest.FromString("manifestDigest1")
manifestDigest2 = godigest.FromString("manifestDigest2")
tag5 = "0.0.5"
manifestDigest3 = godigest.FromString("manifestDigest3")
tag6 = "6.0.0"
manifestDigest4 = godigest.FromString("manifestDigest4")
)
err := repoDB.SetManifestData(manifestDigest1, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
config := ispec.Image{
Platform: ispec.Platform{
Architecture: "arch",
OS: "os",
},
}
confBlob, err := json.Marshal(config)
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestDigest2, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: confBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestDigest3, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestDigest4, repodb.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
indexBlob, err := test.GetIndexBlobWithManifests(
[]godigest.Digest{
manifestDigest1,
manifestDigest2,
},
)
So(err, ShouldBeNil)
err = repoDB.SetIndexData(indexDigest, repodb.IndexData{
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", tag4, indexDigest, ispec.MediaTypeImageIndex)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", tag5, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", tag6, manifestDigest4, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repos, manifestMetaMap, indexDataMap, _, err := repoDB.SearchTags(ctx, "repo:0.0", repodb.Filter{},
repodb.PageInput{})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, "repo")
So(repos[0].Tags, ShouldContainKey, tag4)
So(repos[0].Tags, ShouldContainKey, tag5)
So(repos[0].Tags, ShouldNotContainKey, tag6)
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
So(manifestMetaMap, ShouldNotContainKey, manifestDigest4.String())
So(indexDataMap, ShouldContainKey, indexDigest.String())
})
})
Convey("Paginated tag search", func() {
var (
repo1 = "repo1"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
tag3 = "0.0.3"
tag4 = "0.0.4"
tag5 = "0.0.5"
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag3, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag4, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag5, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
config := ispec.Image{}
configBlob, err := json.Marshal(config)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob})
So(err, ShouldBeNil)
repos, _, _, _, err := repoDB.SearchTags(context.TODO(), "repo1:", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 0,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
keys := make([]string, 0, len(repos[0].Tags))
for k := range repos[0].Tags {
keys = append(keys, k)
}
repos, _, _, _, err = repoDB.SearchTags(context.TODO(), "repo1:", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 1,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
for k := range repos[0].Tags {
keys = append(keys, k)
}
repos, _, _, _, err = repoDB.SearchTags(context.TODO(), "repo1:", repodb.Filter{}, repodb.PageInput{
Limit: 1,
Offset: 2,
SortBy: repodb.AlphabeticAsc,
})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
for k := range repos[0].Tags {
keys = append(keys, k)
}
So(keys, ShouldContain, tag1)
So(keys, ShouldContain, tag2)
So(keys, ShouldContain, tag3)
})
Convey("Test repo search with filtering", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
repo3 = "repo3"
repo4 = "repo4"
tag1 = "0.0.1"
tag2 = "0.0.2"
manifestDigest1 = godigest.FromString("fake-manifest1")
manifestDigest2 = godigest.FromString("fake-manifest2")
manifestDigest3 = godigest.FromString("fake-manifest3")
)
err := repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag1, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo4, tag1, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
config1 := ispec.Image{
Platform: ispec.Platform{
Architecture: AMD,
OS: LINUX,
},
}
configBlob1, err := json.Marshal(config1)
So(err, ShouldBeNil)
config2 := ispec.Image{
Platform: ispec.Platform{
Architecture: "arch",
OS: WINDOWS,
},
}
configBlob2, err := json.Marshal(config2)
So(err, ShouldBeNil)
config3 := ispec.Image{}
configBlob3, err := json.Marshal(config3)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob1})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, repodb.ManifestMetadata{ConfigBlob: configBlob2})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob1})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest2, repodb.ManifestMetadata{ConfigBlob: configBlob2})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo4, manifestDigest3, repodb.ManifestMetadata{ConfigBlob: configBlob3})
So(err, ShouldBeNil)
opSys := LINUX
arch := ""
filter := repodb.Filter{
Os: []*string{&opSys},
}
repos, _, _, _, err := repoDB.SearchRepos(context.TODO(), "", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(repos[0].Name, ShouldResemble, "repo1")
So(repos[1].Name, ShouldResemble, "repo2")
opSys = WINDOWS
filter = repodb.Filter{
Os: []*string{&opSys},
}
repos, _, _, _, err = repoDB.SearchRepos(context.TODO(), "repo", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(repos[0].Name, ShouldResemble, "repo1")
So(repos[1].Name, ShouldResemble, "repo3")
opSys = "wrong"
filter = repodb.Filter{
Os: []*string{&opSys},
}
repos, _, _, _, err = repoDB.SearchRepos(context.TODO(), "repo", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
opSys = LINUX
arch = AMD
filter = repodb.Filter{
Os: []*string{&opSys},
Arch: []*string{&arch},
}
repos, _, _, _, err = repoDB.SearchRepos(context.TODO(), "repo", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(repos[0].Name, ShouldResemble, "repo1")
So(repos[1].Name, ShouldResemble, "repo2")
opSys = WINDOWS
arch = AMD
filter = repodb.Filter{
Os: []*string{&opSys},
Arch: []*string{&arch},
}
repos, _, _, _, err = repoDB.SearchRepos(context.TODO(), "repo", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
})
Convey("Test tags search with filtering", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
repo3 = "repo3"
repo4 = "repo4"
tag1 = "0.0.1"
tag2 = "0.0.2"
tag3 = "0.0.3"
manifestDigest1 = godigest.FromString("fake-manifest1")
manifestDigest2 = godigest.FromString("fake-manifest2")
manifestDigest3 = godigest.FromString("fake-manifest3")
indexDigest = godigest.FromString("index-digest")
manifestFromIndexDigest1 = godigest.FromString("fake-manifestFromIndexDigest1")
manifestFromIndexDigest2 = godigest.FromString("fake-manifestFromIndexDigest2")
)
err := repoDB.SetRepoReference(repo1, tag3, indexDigest, ispec.MediaTypeImageIndex)
So(err, ShouldBeNil)
indexBlob, err := test.GetIndexBlobWithManifests(
[]godigest.Digest{
manifestFromIndexDigest1,
manifestFromIndexDigest2,
},
)
So(err, ShouldBeNil)
err = repoDB.SetIndexData(indexDigest, repodb.IndexData{
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag1, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo4, tag1, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
config1 := ispec.Image{
Platform: ispec.Platform{
Architecture: AMD,
OS: LINUX,
},
}
configBlob1, err := json.Marshal(config1)
So(err, ShouldBeNil)
config2 := ispec.Image{
Platform: ispec.Platform{
Architecture: "arch",
OS: WINDOWS,
},
}
configBlob2, err := json.Marshal(config2)
So(err, ShouldBeNil)
config3 := ispec.Image{}
configBlob3, err := json.Marshal(config3)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob1})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, repodb.ManifestMetadata{ConfigBlob: configBlob2})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, repodb.ManifestMetadata{ConfigBlob: configBlob1})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest2, repodb.ManifestMetadata{ConfigBlob: configBlob2})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo4, manifestDigest3, repodb.ManifestMetadata{ConfigBlob: configBlob3})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestFromIndexDigest1,
repodb.ManifestMetadata{ConfigBlob: []byte("{}")})
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestFromIndexDigest2,
repodb.ManifestMetadata{ConfigBlob: []byte("{}")})
So(err, ShouldBeNil)
opSys := LINUX
arch := AMD
filter := repodb.Filter{
Os: []*string{&opSys},
Arch: []*string{&arch},
}
repos, _, _, _, err := repoDB.SearchTags(context.TODO(), "repo1:", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Tags, ShouldContainKey, tag1)
opSys = LINUX
arch = "badArch"
filter = repodb.Filter{
Os: []*string{&opSys},
Arch: []*string{&arch},
}
repos, _, _, _, err = repoDB.SearchTags(context.TODO(), "repo1:", filter,
repodb.PageInput{SortBy: repodb.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
})
Convey("Test FilterTags", func() {
var (
repo1 = "repo1"
repo2 = "repo2"
manifestDigest1 = godigest.FromString("fake-manifest1")
manifestDigest2 = godigest.FromString("fake-manifest2")
manifestDigest3 = godigest.FromString("fake-manifest3")
indexDigest = godigest.FromString("index-digest")
manifestFromIndexDigest1 = godigest.FromString("fake-manifestFromIndexDigest1")
manifestFromIndexDigest2 = godigest.FromString("fake-manifestFromIndexDigest2")
emptyManifest ispec.Manifest
emptyConfig ispec.Image
ctx = context.Background()
)
emptyManifestBlob, err := json.Marshal(emptyManifest)
So(err, ShouldBeNil)
emptyConfigBlob, err := json.Marshal(emptyConfig)
So(err, ShouldBeNil)
emptyManifestMeta := repodb.ManifestMetadata{
ManifestBlob: emptyManifestBlob,
ConfigBlob: emptyConfigBlob,
}
emptyManifestData := repodb.ManifestData{
ManifestBlob: emptyManifestBlob,
ConfigBlob: emptyConfigBlob,
}
err = repoDB.SetRepoReference(repo1, "2.0.0", indexDigest, ispec.MediaTypeImageIndex)
So(err, ShouldBeNil)
indexBlob, err := test.GetIndexBlobWithManifests([]godigest.Digest{
manifestFromIndexDigest1,
manifestFromIndexDigest2,
})
So(err, ShouldBeNil)
err = repoDB.SetIndexData(indexDigest, repodb.IndexData{
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "0.0.1", manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "0.0.2", manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "0.1.0", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "1.0.0", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, "1.0.1", manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, "0.0.1", manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyManifestMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, emptyManifestMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest3, emptyManifestMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest3, emptyManifestMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestFromIndexDigest1, emptyManifestData)
So(err, ShouldBeNil)
err = repoDB.SetManifestData(manifestFromIndexDigest2, emptyManifestData)
So(err, ShouldBeNil)
Convey("Return all tags", func() {
repos, manifestMetaMap, indexDataMap, pageInfo, err := repoDB.FilterTags(
ctx,
func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
return true
},
repodb.PageInput{Limit: 10, Offset: 0, SortBy: repodb.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 2)
So(repos[0].Name, ShouldEqual, "repo1")
So(repos[1].Name, ShouldEqual, "repo2")
So(len(repos[0].Tags), ShouldEqual, 6)
So(len(repos[1].Tags), ShouldEqual, 1)
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(repos[0].Tags, ShouldContainKey, "0.0.2")
So(repos[0].Tags, ShouldContainKey, "0.1.0")
So(repos[0].Tags, ShouldContainKey, "1.0.0")
So(repos[0].Tags, ShouldContainKey, "1.0.1")
So(repos[0].Tags, ShouldContainKey, "2.0.0")
So(repos[1].Tags, ShouldContainKey, "0.0.1")
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
So(indexDataMap, ShouldContainKey, indexDigest.String())
So(manifestMetaMap, ShouldContainKey, manifestFromIndexDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestFromIndexDigest2.String())
So(pageInfo.ItemCount, ShouldEqual, 7)
So(pageInfo.TotalCount, ShouldEqual, 7)
})
Convey("Return all tags in a specific repo", func() {
repos, manifestMetaMap, indexDataMap, pageInfo, err := repoDB.FilterTags(
ctx,
func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
return repoMeta.Name == repo1
},
repodb.PageInput{Limit: 10, Offset: 0, SortBy: repodb.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldEqual, repo1)
So(len(repos[0].Tags), ShouldEqual, 6)
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(repos[0].Tags, ShouldContainKey, "0.0.2")
So(repos[0].Tags, ShouldContainKey, "0.1.0")
So(repos[0].Tags, ShouldContainKey, "1.0.0")
So(repos[0].Tags, ShouldContainKey, "1.0.1")
So(repos[0].Tags, ShouldContainKey, "2.0.0")
So(manifestMetaMap, ShouldContainKey, manifestDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest2.String())
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
So(indexDataMap, ShouldContainKey, indexDigest.String())
So(manifestMetaMap, ShouldContainKey, manifestFromIndexDigest1.String())
So(manifestMetaMap, ShouldContainKey, manifestFromIndexDigest2.String())
So(pageInfo.ItemCount, ShouldEqual, 6)
So(pageInfo.TotalCount, ShouldEqual, 6)
})
Convey("Filter everything out", func() {
repos, manifestMetaMap, _, pageInfo, err := repoDB.FilterTags(
ctx,
func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
return false
},
repodb.PageInput{Limit: 10, Offset: 0, SortBy: repodb.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 0)
So(len(manifestMetaMap), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
})
Convey("Search with access control", func() {
acCtx := localCtx.AccessControlContext{
ReadGlobPatterns: map[string]bool{
repo1: false,
repo2: true,
},
Username: "username",
}
authzCtxKey := localCtx.GetContextKey()
ctx := context.WithValue(context.Background(), authzCtxKey, acCtx)
repos, manifestMetaMap, _, pageInfo, err := repoDB.FilterTags(
ctx,
func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
return true
},
repodb.PageInput{Limit: 10, Offset: 0, SortBy: repodb.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(repos[0].Name, ShouldResemble, repo2)
So(len(repos[0].Tags), ShouldEqual, 1)
So(repos[0].Tags, ShouldContainKey, "0.0.1")
So(manifestMetaMap, ShouldContainKey, manifestDigest3.String())
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 1)
})
Convey("With wrong pagination input", func() {
repos, _, _, _, err := repoDB.FilterTags(
ctx,
func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
return true
},
repodb.PageInput{Limit: -1},
)
So(err, ShouldNotBeNil)
So(repos, ShouldBeEmpty)
})
})
Convey("Test index logic", func() {
multiArch, err := test.GetRandomMultiarchImage("tag1")
So(err, ShouldBeNil)
indexDigest, err := multiArch.Digest()
So(err, ShouldBeNil)
indexData, err := multiArch.IndexData()
So(err, ShouldBeNil)
err = repoDB.SetIndexData(indexDigest, indexData)
So(err, ShouldBeNil)
result, err := repoDB.GetIndexData(indexDigest)
So(err, ShouldBeNil)
So(result, ShouldResemble, indexData)
_, err = repoDB.GetIndexData(godigest.FromString("inexistent"))
So(err, ShouldNotBeNil)
})
Convey("Test artifact logic", func() {
artifact, err := test.GetRandomArtifact(nil)
So(err, ShouldBeNil)
artifactDigest, err := artifact.Digest()
So(err, ShouldBeNil)
artifactData, err := artifact.ArtifactData()
So(err, ShouldBeNil)
err = repoDB.SetArtifactData(artifactDigest, artifactData)
So(err, ShouldBeNil)
result, err := repoDB.GetArtifactData(artifactDigest)
So(err, ShouldBeNil)
So(result, ShouldResemble, artifactData)
_, err = repoDB.GetArtifactData(godigest.FromString("inexistent"))
So(err, ShouldNotBeNil)
})
Convey("Test Referrers", func() {
image, err := test.GetRandomImage("tag")
So(err, ShouldBeNil)
referredDigest, err := image.Digest()
So(err, ShouldBeNil)
manifestBlob, err := json.Marshal(image.Manifest)
So(err, ShouldBeNil)
configBlob, err := json.Marshal(image.Config)
So(err, ShouldBeNil)
manifestData := repodb.ManifestData{
ManifestBlob: manifestBlob,
ConfigBlob: configBlob,
}
err = repoDB.SetManifestData(referredDigest, manifestData)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference("repo", "tag", referredDigest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// ------- Add Artifact 1
artifact1, err := test.GetRandomArtifact(&ispec.Descriptor{
Digest: referredDigest,
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
artifactDigest1, err := artifact1.Digest()
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: artifactDigest1.String(),
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
// ------- Add Artifact 2
artifact2, err := test.GetRandomArtifact(&ispec.Descriptor{
Digest: referredDigest,
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
artifactDigest2, err := artifact2.Digest()
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: artifactDigest2.String(),
MediaType: ispec.MediaTypeArtifactManifest,
})
So(err, ShouldBeNil)
// ------ GetReferrers
referrers, err := repoDB.GetReferrersInfo("repo", referredDigest, nil)
So(len(referrers), ShouldEqual, 2)
So(referrers, ShouldContain, repodb.ReferrerInfo{
Digest: artifactDigest1.String(),
MediaType: ispec.MediaTypeImageManifest,
})
So(referrers, ShouldContain, repodb.ReferrerInfo{
Digest: artifactDigest2.String(),
MediaType: ispec.MediaTypeArtifactManifest,
})
So(err, ShouldBeNil)
// ------ DeleteReferrers
err = repoDB.DeleteReferrer("repo", referredDigest, artifactDigest1)
So(err, ShouldBeNil)
err = repoDB.DeleteReferrer("repo", referredDigest, artifactDigest2)
So(err, ShouldBeNil)
referrers, err = repoDB.GetReferrersInfo("repo", referredDigest, nil)
So(err, ShouldBeNil)
So(len(referrers), ShouldEqual, 0)
})
Convey("Test Referrers on empty Repo", func() {
repoMeta, err := repoDB.GetRepoMeta("repo")
So(err, ShouldNotBeNil)
So(repoMeta, ShouldResemble, repodb.RepoMetadata{})
referredDigest := godigest.FromString("referredDigest")
referrerDigest := godigest.FromString("referrerDigest")
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: referrerDigest.String(),
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta("repo")
So(err, ShouldBeNil)
So(repoMeta.Referrers[referredDigest.String()][0].Digest, ShouldResemble, referrerDigest.String())
})
Convey("Test Referrers add same one twice", func() {
repoMeta, err := repoDB.GetRepoMeta("repo")
So(err, ShouldNotBeNil)
So(repoMeta, ShouldResemble, repodb.RepoMetadata{})
referredDigest := godigest.FromString("referredDigest")
referrerDigest := godigest.FromString("referrerDigest")
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: referrerDigest.String(),
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: referrerDigest.String(),
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
repoMeta, err = repoDB.GetRepoMeta("repo")
So(err, ShouldBeNil)
So(len(repoMeta.Referrers[referredDigest.String()]), ShouldEqual, 1)
})
Convey("GetReferrersInfo", func() {
referredDigest := godigest.FromString("referredDigest")
err := repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: "inexistendManifestDigest",
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: "inexistendArtifactManifestDigest",
MediaType: ispec.MediaTypeArtifactManifest,
})
So(err, ShouldBeNil)
// ------- Set existent manifest and artifact manifest
err = repoDB.SetManifestData("goodManifest", repodb.ManifestData{
ManifestBlob: []byte(`{"artifactType": "unwantedType"}`),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: "goodManifest",
MediaType: ispec.MediaTypeImageManifest,
ArtifactType: "unwantedType",
})
So(err, ShouldBeNil)
err = repoDB.SetArtifactData("goodArtifact", repodb.ArtifactData{
ManifestBlob: []byte(`{"artifactType": "wantedType"}`),
})
So(err, ShouldBeNil)
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
Digest: "goodArtifact",
MediaType: ispec.MediaTypeArtifactManifest,
ArtifactType: "wantedType",
})
So(err, ShouldBeNil)
referrerInfo, err := repoDB.GetReferrersInfo("repo", referredDigest, []string{"wantedType"})
So(err, ShouldBeNil)
So(len(referrerInfo), ShouldEqual, 1)
So(referrerInfo[0].ArtifactType, ShouldResemble, "wantedType")
So(referrerInfo[0].Digest, ShouldResemble, "goodArtifact")
})
})
}
func TestRelevanceSorting(t *testing.T) {
Convey("Test Relevance Sorting", t, func() {
So(common.RankRepoName("alpine", "alpine"), ShouldEqual, 0)
So(common.RankRepoName("test/alpine", "test/alpine"), ShouldEqual, 0)
So(common.RankRepoName("test/alpine", "alpine"), ShouldEqual, -1)
So(common.RankRepoName("alpine", "test/alpine"), ShouldEqual, 1)
So(common.RankRepoName("test", "test/alpine"), ShouldEqual, 10)
So(common.RankRepoName("pine", "test/alpine"), ShouldEqual, 3)
So(common.RankRepoName("pine", "alpine/alpine"), ShouldEqual, 3)
So(common.RankRepoName("pine", "alpine/test"), ShouldEqual, 30)
So(common.RankRepoName("test/pine", "alpine"), ShouldEqual, -1)
So(common.RankRepoName("repo/test", "repo/test/alpine"), ShouldEqual, 10)
So(common.RankRepoName("repo/test/golang", "repo/test2/alpine"), ShouldEqual, -1)
So(common.RankRepoName("repo/test/pine", "repo/test/alpine"), ShouldEqual, 3)
So(common.RankRepoName("debian", "c3/debian/base-amd64"), ShouldEqual, 400)
So(common.RankRepoName("debian/base-amd64", "c3/debian/base-amd64"), ShouldEqual, 400)
So(common.RankRepoName("debian/base-amd64", "c3/aux/debian/base-amd64"), ShouldEqual, 800)
So(common.RankRepoName("aux/debian", "c3/aux/debian/base-amd64"), ShouldEqual, 400)
Convey("Integration", func() {
filePath := path.Join(t.TempDir(), "repo.db")
boltDBParams := bolt.DBParameters{
RootDir: t.TempDir(),
}
repoDB, err := bolt.NewBoltDBWrapper(boltDBParams)
So(repoDB, ShouldNotBeNil)
So(err, ShouldBeNil)
defer os.Remove(filePath)
var (
repo1 = "alpine"
repo2 = "alpine/test"
repo3 = "notalpine"
repo4 = "unmached/repo"
tag1 = "0.0.1"
manifestDigest1 = godigest.FromString("fake-manifest1")
tag2 = "0.0.2"
manifestDigest2 = godigest.FromString("fake-manifest2")
tag3 = "0.0.3"
manifestDigest3 = godigest.FromString("fake-manifest3")
ctx = context.Background()
emptyManifest ispec.Manifest
emptyConfig ispec.Manifest
)
emptyManifestBlob, err := json.Marshal(emptyManifest)
So(err, ShouldBeNil)
emptyConfigBlob, err := json.Marshal(emptyConfig)
So(err, ShouldBeNil)
emptyRepoMeta := repodb.ManifestMetadata{
ManifestBlob: emptyManifestBlob,
ConfigBlob: emptyConfigBlob,
}
err = repoDB.SetRepoReference(repo1, tag1, manifestDigest1, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo1, tag2, manifestDigest2, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo2, tag3, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo3, tag3, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetRepoReference(repo4, tag1, manifestDigest3, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo1, manifestDigest2, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo2, manifestDigest1, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo3, manifestDigest2, emptyRepoMeta)
So(err, ShouldBeNil)
err = repoDB.SetManifestMeta(repo4, manifestDigest3, emptyRepoMeta)
So(err, ShouldBeNil)
repos, _, _, _, err := repoDB.SearchRepos(ctx, "pine", repodb.Filter{},
repodb.PageInput{SortBy: repodb.Relevance},
)
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 3)
So(repos[0].Name, ShouldEqual, repo1)
So(repos[1].Name, ShouldEqual, repo3)
So(repos[2].Name, ShouldEqual, repo2)
})
})
}
func generateTestImage() ([]byte, []byte, error) {
config := ispec.Image{
Platform: ispec.Platform{
Architecture: "amd64",
OS: LINUX,
},
RootFS: ispec.RootFS{
Type: "layers",
DiffIDs: []godigest.Digest{},
},
Author: "ZotUser",
}
configBlob, err := json.Marshal(config)
if err != nil {
return []byte{}, []byte{}, err
}
configDigest := godigest.FromBytes(configBlob)
layers := [][]byte{
make([]byte, 100),
}
// init layers with random values
for i := range layers {
//nolint:gosec
_, err := rand.Read(layers[i])
if err != nil {
return []byte{}, []byte{}, err
}
}
manifest := ispec.Manifest{
Versioned: specs.Versioned{
SchemaVersion: 2,
},
Config: ispec.Descriptor{
MediaType: "application/vnd.oci.image.config.v1+json",
Digest: configDigest,
Size: int64(len(configBlob)),
},
Layers: []ispec.Descriptor{
{
MediaType: "application/vnd.oci.image.layer.v1.tar",
Digest: godigest.FromBytes(layers[0]),
Size: int64(len(layers[0])),
},
},
}
manifestBlob, err := json.Marshal(manifest)
if err != nil {
return []byte{}, []byte{}, err
}
return configBlob, manifestBlob, nil
}