0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-01-06 22:40:28 -05:00
zot/pkg/extensions/search/convert/convert_test.go
Andrei Aaron d0eb043be5
feat: Get the image LastUpdated timestamp from annotations (#2240)
Fallback to Created field and the History entries in the image config
only if the annotation "org.opencontainers.image.created" is not available

closes #2210

Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
2024-02-14 09:14:24 -08:00

890 lines
29 KiB
Go

//go:build search
package convert_test
import (
"context"
"errors"
"testing"
"time"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.dev/zot/pkg/extensions/search/convert"
"zotregistry.dev/zot/pkg/extensions/search/gql_generated"
"zotregistry.dev/zot/pkg/extensions/search/pagination"
"zotregistry.dev/zot/pkg/log"
"zotregistry.dev/zot/pkg/meta/boltdb"
mTypes "zotregistry.dev/zot/pkg/meta/types"
reqCtx "zotregistry.dev/zot/pkg/requestcontext"
. "zotregistry.dev/zot/pkg/test/image-utils"
"zotregistry.dev/zot/pkg/test/mocks"
ociutils "zotregistry.dev/zot/pkg/test/oci-utils"
)
var ErrTestError = errors.New("TestError")
func TestUpdateLastUpdatedTimestamp(t *testing.T) {
Convey("Image summary is the first image checked for the repo", t, func() {
before := time.Time{}
after := time.Date(2023, time.April, 1, 11, 0, 0, 0, time.UTC)
img := convert.UpdateLastUpdatedTimestamp(
&before,
&gql_generated.ImageSummary{LastUpdated: &before},
&gql_generated.ImageSummary{LastUpdated: &after},
)
So(*img.LastUpdated, ShouldResemble, after)
})
Convey("Image summary is updated after the current latest image", t, func() {
before := time.Date(2022, time.April, 1, 11, 0, 0, 0, time.UTC)
after := time.Date(2023, time.April, 1, 11, 0, 0, 0, time.UTC)
img := convert.UpdateLastUpdatedTimestamp(
&before,
&gql_generated.ImageSummary{LastUpdated: &before},
&gql_generated.ImageSummary{LastUpdated: &after},
)
So(*img.LastUpdated, ShouldResemble, after)
})
Convey("Image summary is updated before the current latest image", t, func() {
before := time.Date(2022, time.April, 1, 11, 0, 0, 0, time.UTC)
after := time.Date(2023, time.April, 1, 11, 0, 0, 0, time.UTC)
img := convert.UpdateLastUpdatedTimestamp(
&after,
&gql_generated.ImageSummary{LastUpdated: &after},
&gql_generated.ImageSummary{LastUpdated: &before},
)
So(*img.LastUpdated, ShouldResemble, after)
})
}
func TestLabels(t *testing.T) {
Convey("Test labels", t, func() {
// Test various labels
labels := make(map[string]string)
created := convert.GetCreated(labels)
So(created, ShouldBeNil)
desc := convert.GetDescription(labels)
So(desc, ShouldEqual, "")
license := convert.GetLicenses(labels)
So(license, ShouldEqual, "")
vendor := convert.GetVendor(labels)
So(vendor, ShouldEqual, "")
categories := convert.GetCategories(labels)
So(categories, ShouldEqual, "")
expectedCreatedTime := time.Date(2010, 1, 1, 12, 0, 0, 0, time.UTC)
labels[ispec.AnnotationCreated] = expectedCreatedTime.Format(time.RFC3339)
labels[ispec.AnnotationVendor] = "zot"
labels[ispec.AnnotationDescription] = "zot-desc"
labels[ispec.AnnotationLicenses] = "zot-license"
labels[convert.AnnotationLabels] = "zot-labels"
created = convert.GetCreated(labels)
So(*created, ShouldEqual, expectedCreatedTime)
desc = convert.GetDescription(labels)
So(desc, ShouldEqual, "zot-desc")
license = convert.GetLicenses(labels)
So(license, ShouldEqual, "zot-license")
vendor = convert.GetVendor(labels)
So(vendor, ShouldEqual, "zot")
categories = convert.GetCategories(labels)
So(categories, ShouldEqual, "zot-labels")
labels = make(map[string]string)
// Use diff key
labels[convert.LabelAnnotationCreated] = expectedCreatedTime.Format(time.RFC3339)
labels[convert.LabelAnnotationVendor] = "zot-vendor"
labels[convert.LabelAnnotationDescription] = "zot-label-desc"
labels[ispec.AnnotationLicenses] = "zot-label-license"
created = convert.GetCreated(labels)
So(*created, ShouldEqual, expectedCreatedTime)
desc = convert.GetDescription(labels)
So(desc, ShouldEqual, "zot-label-desc")
license = convert.GetLicenses(labels)
So(license, ShouldEqual, "zot-label-license")
vendor = convert.GetVendor(labels)
So(vendor, ShouldEqual, "zot-vendor")
labels = make(map[string]string)
// Handle conversion errors
labels[ispec.AnnotationCreated] = "asd"
created = convert.GetCreated(labels)
So(created, ShouldBeNil)
})
}
func TestGetSignaturesInfo(t *testing.T) {
Convey("Test get signatures info - cosign", t, func() {
digest := godigest.FromString("dig")
signatures := map[string]mTypes.ManifestSignatures{
digest.String(): {
"cosign": []mTypes.SignatureInfo{
{
LayersInfo: []mTypes.LayerInfo{
{
LayerContent: []byte{},
LayerDigest: "",
SignatureKey: "",
Signer: "author",
},
},
},
},
},
}
signaturesSummary := convert.GetSignaturesInfo(true, signatures[digest.String()])
So(signaturesSummary, ShouldNotBeEmpty)
So(*signaturesSummary[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, true)
So(*signaturesSummary[0].Tool, ShouldEqual, "cosign")
})
Convey("Test get signatures info - notation", t, func() {
digest := godigest.FromString("dig")
signatures := map[string]mTypes.ManifestSignatures{
digest.String(): {
"notation": []mTypes.SignatureInfo{
{
LayersInfo: []mTypes.LayerInfo{
{
LayerContent: []byte{},
LayerDigest: "",
SignatureKey: "",
Signer: "author",
Date: time.Now().AddDate(0, 0, -1),
},
},
},
},
},
}
signaturesSummary := convert.GetSignaturesInfo(true, signatures[digest.String()])
So(signaturesSummary, ShouldNotBeEmpty)
So(*signaturesSummary[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, false)
So(*signaturesSummary[0].Tool, ShouldEqual, "notation")
})
}
func TestAcceptedByFilter(t *testing.T) {
Convey("Images", t, func() {
Convey("Os not found", func() {
found := convert.ImgSumAcceptedByFilter(
&gql_generated.ImageSummary{
Manifests: []*gql_generated.ManifestSummary{
{Platform: &gql_generated.Platform{Os: ref("os1")}},
{Platform: &gql_generated.Platform{Os: ref("os2")}},
},
},
mTypes.Filter{Os: []*string{ref("os3")}},
)
So(found, ShouldBeFalse)
})
Convey("Has to be signed ", func() {
found := convert.ImgSumAcceptedByFilter(
&gql_generated.ImageSummary{
Manifests: []*gql_generated.ManifestSummary{
{IsSigned: ref(false)},
},
IsSigned: ref(false),
},
mTypes.Filter{HasToBeSigned: ref(true)},
)
So(found, ShouldBeFalse)
})
})
Convey("Repos", t, func() {
Convey("Os not found", func() {
found := convert.RepoSumAcceptedByFilter(
&gql_generated.RepoSummary{
Platforms: []*gql_generated.Platform{
{Os: ref("os1")},
{Os: ref("os2")},
},
},
mTypes.Filter{Os: []*string{ref("os3")}},
)
So(found, ShouldBeFalse)
})
Convey("Arch not found", func() {
found := convert.RepoSumAcceptedByFilter(
&gql_generated.RepoSummary{
Platforms: []*gql_generated.Platform{
{Arch: ref("Arch")},
},
},
mTypes.Filter{Arch: []*string{ref("arch_not_found")}},
)
So(found, ShouldBeFalse)
})
Convey("Has to be signed ", func() {
found := convert.ImgSumAcceptedByFilter(
&gql_generated.ImageSummary{
Manifests: []*gql_generated.ManifestSummary{
{IsSigned: ref(false)},
},
IsSigned: ref(false),
},
mTypes.Filter{HasToBeSigned: ref(true)},
)
So(found, ShouldBeFalse)
})
})
}
func ref[T any](val T) *T {
ref := val
return &ref
}
func TestPaginatedConvert(t *testing.T) {
ctx := context.Background()
tempDir := t.TempDir()
driver, err := boltdb.GetBoltDriver(boltdb.DBParameters{RootDir: tempDir})
if err != nil {
t.FailNow()
}
metaDB, err := boltdb.New(driver, log.NewLogger("debug", ""))
if err != nil {
t.FailNow()
}
var (
badBothImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "bad-os", Architecture: "bad-arch"}}).Build()
badOsImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "bad-os", Architecture: "good-arch"}}).Build()
badArchImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "good-os", Architecture: "bad-arch"}}).Build()
goodImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "good-os", Architecture: "good-arch"}}).Build()
randomImage1 = CreateRandomImage()
randomImage2 = CreateRandomImage()
signatureDigest = godigest.FromString("signature")
badMultiArch = CreateMultiarchWith().Images(
[]Image{badBothImage, badOsImage, badArchImage, randomImage1}).Build()
goodMultiArch = CreateMultiarchWith().Images(
[]Image{badOsImage, badArchImage, randomImage2, goodImage}).Build()
)
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{
Name: "repo1-only-images",
Images: []ociutils.RepoImage{
{Image: goodImage, Reference: "goodImage"},
{Image: badOsImage, Reference: "badOsImage"},
{Image: badArchImage, Reference: "badArchImage"},
{Image: badBothImage, Reference: "badBothImage"},
},
IsBookmarked: true,
IsStarred: true,
},
ociutils.Repo{
Name: "repo2-only-bad-images",
Images: []ociutils.RepoImage{
{Image: randomImage1, Reference: "randomImage1"},
{Image: randomImage2, Reference: "randomImage2"},
{Image: badBothImage, Reference: "badBothImage"},
},
IsBookmarked: true,
IsStarred: true,
},
ociutils.Repo{
Name: "repo3-only-multiarch",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: badMultiArch, Reference: "badMultiArch"},
{MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
},
IsBookmarked: true,
IsStarred: true,
},
ociutils.Repo{
Name: "repo4-not-bookmarked-or-starred",
Images: []ociutils.RepoImage{
{Image: goodImage, Reference: "goodImage"},
},
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
},
},
ociutils.Repo{
Name: "repo5-signed",
Images: []ociutils.RepoImage{
{Image: goodImage, Reference: "goodImage"}, // is fake signed by the image below
},
Signatures: map[string]mTypes.ManifestSignatures{
goodImage.DigestStr(): ociutils.GetFakeSignatureInfo(signatureDigest.String()),
},
},
)
if err != nil {
t.FailNow()
}
skipCVE := convert.SkipQGLField{Vulnerabilities: true}
Convey("PaginatedRepoMeta2RepoSummaries filtering and sorting", t, func() {
// Test different combinations of the filter
repoMetaList, err := metaDB.FilterRepos(ctx, mTypes.AcceptAllRepoNames, mTypes.AcceptAllRepoMeta)
So(err, ShouldBeNil)
imageMeta, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
So(err, ShouldBeNil)
reposSum, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true),
IsStarred: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 2)
So(*reposSum[0].Name, ShouldResemble, "repo1-only-images")
So(*reposSum[1].Name, ShouldResemble, "repo3-only-multiarch")
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true),
IsStarred: ref(true),
HasToBeSigned: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{
HasToBeSigned: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1)
So(*reposSum[0].Name, ShouldResemble, "repo5-signed")
So(pageInfo.ItemCount, ShouldEqual, 1)
// no filter
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5)
So(*reposSum[0].Name, ShouldResemble, "repo1-only-images")
So(*reposSum[1].Name, ShouldResemble, "repo2-only-bad-images")
So(*reposSum[2].Name, ShouldResemble, "repo3-only-multiarch")
So(*reposSum[3].Name, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*reposSum[4].Name, ShouldResemble, "repo5-signed")
So(pageInfo.ItemCount, ShouldEqual, 5)
// no filter opposite sorting
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticDsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5)
So(*reposSum[0].Name, ShouldResemble, "repo5-signed")
So(*reposSum[1].Name, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*reposSum[2].Name, ShouldResemble, "repo3-only-multiarch")
So(*reposSum[3].Name, ShouldResemble, "repo2-only-bad-images")
So(*reposSum[4].Name, ShouldResemble, "repo1-only-images")
So(pageInfo.ItemCount, ShouldEqual, 5)
// add pagination
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true),
IsStarred: ref(true),
},
pagination.PageInput{Limit: 1, Offset: 0, SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1)
So(*reposSum[0].Name, ShouldResemble, "repo1-only-images")
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 2)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true),
IsStarred: ref(true),
},
pagination.PageInput{Limit: 1, Offset: 1, SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1)
So(*reposSum[0].Name, ShouldResemble, "repo3-only-multiarch")
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 2)
})
Convey("PaginatedRepoMeta2ImageSummaries filtering and sorting", t, func() {
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
So(err, ShouldBeNil)
imgSum, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(imgSum), ShouldEqual, 5)
So(*imgSum[0].RepoName, ShouldResemble, "repo1-only-images")
So(*imgSum[0].Tag, ShouldResemble, "goodImage")
So(*imgSum[1].RepoName, ShouldResemble, "repo3-only-multiarch")
So(*imgSum[1].Tag, ShouldResemble, "goodMultiArch")
So(*imgSum[2].RepoName, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*imgSum[2].Tag, ShouldResemble, "goodImage")
So(*imgSum[3].RepoName, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*imgSum[3].Tag, ShouldResemble, "goodMultiArch")
So(*imgSum[4].RepoName, ShouldResemble, "repo5-signed")
So(*imgSum[4].Tag, ShouldResemble, "goodImage")
So(pageInfo.ItemCount, ShouldEqual, 5)
// add page of size 2
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
},
pagination.PageInput{Limit: 2, Offset: 0, SortBy: pagination.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(imgSum), ShouldEqual, 2)
So(*imgSum[0].RepoName, ShouldResemble, "repo1-only-images")
So(*imgSum[0].Tag, ShouldResemble, "goodImage")
So(*imgSum[1].RepoName, ShouldResemble, "repo3-only-multiarch")
So(*imgSum[1].Tag, ShouldResemble, "goodMultiArch")
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
// next page
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
},
pagination.PageInput{Limit: 2, Offset: 2, SortBy: pagination.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(imgSum), ShouldEqual, 2)
So(*imgSum[0].RepoName, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*imgSum[0].Tag, ShouldResemble, "goodImage")
So(*imgSum[1].RepoName, ShouldResemble, "repo4-not-bookmarked-or-starred")
So(*imgSum[1].Tag, ShouldResemble, "goodMultiArch")
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
// last page
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
},
pagination.PageInput{Limit: 2, Offset: 4, SortBy: pagination.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(imgSum), ShouldEqual, 1)
So(*imgSum[0].RepoName, ShouldResemble, "repo5-signed")
So(*imgSum[0].Tag, ShouldResemble, "goodImage")
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 5)
// has to be signed
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
HasToBeSigned: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc},
)
So(err, ShouldBeNil)
So(len(imgSum), ShouldEqual, 1)
So(*imgSum[0].RepoName, ShouldResemble, "repo5-signed")
So(*imgSum[0].Tag, ShouldResemble, "goodImage")
So(pageInfo.ItemCount, ShouldEqual, 1)
})
}
func TestIndexAnnotations(t *testing.T) {
Convey("Test ImageIndex2ImageSummary annotations logic", t, func() {
ctx := context.Background()
tempDir := t.TempDir()
driver, err := boltdb.GetBoltDriver(boltdb.DBParameters{RootDir: tempDir})
if err != nil {
t.FailNow()
}
metaDB, err := boltdb.New(driver, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
defaultCreatedTime := *DefaultTimeRef()
configCreatedTime := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
manifestCreatedTime := time.Date(2010, 1, 1, 12, 0, 0, 0, time.UTC)
indexCreatedTime := time.Date(2011, 1, 1, 12, 0, 0, 0, time.UTC)
configLabels := map[string]string{
ispec.AnnotationCreated: configCreatedTime.Format(time.RFC3339),
ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses",
ispec.AnnotationVendor: "ConfigVendor",
ispec.AnnotationAuthors: "ConfigAuthors",
ispec.AnnotationTitle: "ConfigTitle",
ispec.AnnotationDocumentation: "ConfigDocumentation",
ispec.AnnotationSource: "ConfigSource",
}
manifestAnnotations := map[string]string{
ispec.AnnotationCreated: manifestCreatedTime.Format(time.RFC3339),
ispec.AnnotationDescription: "ManifestDescription",
ispec.AnnotationLicenses: "ManifestLicenses",
ispec.AnnotationVendor: "ManifestVendor",
ispec.AnnotationAuthors: "ManifestAuthors",
ispec.AnnotationTitle: "ManifestTitle",
ispec.AnnotationDocumentation: "ManifestDocumentation",
ispec.AnnotationSource: "ManifestSource",
}
indexAnnotations := map[string]string{
ispec.AnnotationCreated: indexCreatedTime.Format(time.RFC3339),
ispec.AnnotationDescription: "IndexDescription",
ispec.AnnotationLicenses: "IndexLicenses",
ispec.AnnotationVendor: "IndexVendor",
ispec.AnnotationAuthors: "IndexAuthors",
ispec.AnnotationTitle: "IndexTitle",
ispec.AnnotationDocumentation: "IndexDocumentation",
ispec.AnnotationSource: "IndexSource",
}
imageWithConfigAnnotations := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{
Config: ispec.ImageConfig{
Labels: configLabels,
},
}).Build()
imageWithManifestAndConfigAnnotations := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{
Config: ispec.ImageConfig{
Labels: configLabels,
},
}).Annotations(manifestAnnotations).Build()
// --------------------------------------------------------
indexWithAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithManifestAndConfigAnnotations},
).Annotations(indexAnnotations).Build()
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithAnnotations, Reference: "tag"},
},
})
So(err, ShouldBeNil)
repoMeta, err := metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err := metaDB.FilterImageMeta(ctx, []string{indexWithAnnotations.DigestStr()})
So(err, ShouldBeNil)
imageSummary, _, err := convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[indexWithAnnotations.DigestStr()]))
So(err, ShouldBeNil)
So(*imageSummary.LastUpdated, ShouldEqual, indexCreatedTime)
So(*imageSummary.Description, ShouldResemble, "IndexDescription")
So(*imageSummary.Licenses, ShouldResemble, "IndexLicenses")
So(*imageSummary.Title, ShouldResemble, "IndexTitle")
So(*imageSummary.Source, ShouldResemble, "IndexSource")
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "IndexVendor")
So(*imageSummary.Authors, ShouldResemble, "IndexAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// --------------------------------------------------------
indexWithManifestAndConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithManifestAndConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build()
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithManifestAndConfigAnnotations, Reference: "tag"},
},
})
So(err, ShouldBeNil)
digest := indexWithManifestAndConfigAnnotations.DigestStr()
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil)
So(*imageSummary.LastUpdated, ShouldEqual, manifestCreatedTime)
So(*imageSummary.Description, ShouldResemble, "ManifestDescription")
So(*imageSummary.Licenses, ShouldResemble, "ManifestLicenses")
So(*imageSummary.Title, ShouldResemble, "ManifestTitle")
So(*imageSummary.Source, ShouldResemble, "ManifestSource")
So(*imageSummary.Documentation, ShouldResemble, "ManifestDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// --------------------------------------------------------
indexWithConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build()
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithConfigAnnotations, Reference: "tag"},
},
})
So(err, ShouldBeNil)
digest = indexWithConfigAnnotations.DigestStr()
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil)
So(*imageSummary.LastUpdated, ShouldEqual, configCreatedTime)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
So(*imageSummary.Title, ShouldResemble, "ConfigTitle")
So(*imageSummary.Source, ShouldResemble, "ConfigSource")
So(*imageSummary.Documentation, ShouldResemble, "ConfigDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ConfigVendor")
So(*imageSummary.Authors, ShouldResemble, "ConfigAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//--------------------------------------------------------
indexWithMixAnnotations := CreateMultiarchWith().Images(
[]Image{
CreateImageWith().DefaultLayers().ImageConfig(ispec.Image{
Created: &defaultCreatedTime,
Config: ispec.ImageConfig{
Labels: map[string]string{
ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses",
},
},
}).Annotations(map[string]string{
ispec.AnnotationVendor: "ManifestVendor",
ispec.AnnotationAuthors: "ManifestAuthors",
}).Build(),
CreateRandomImage(),
CreateRandomImage(),
},
).Annotations(
map[string]string{
ispec.AnnotationCreated: indexCreatedTime.Format(time.RFC3339),
ispec.AnnotationTitle: "IndexTitle",
ispec.AnnotationDocumentation: "IndexDocumentation",
ispec.AnnotationSource: "IndexSource",
},
).Build()
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithMixAnnotations, Reference: "tag"},
},
})
So(err, ShouldBeNil)
digest = indexWithMixAnnotations.DigestStr()
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil)
So(*imageSummary.LastUpdated, ShouldEqual, indexCreatedTime)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
So(*imageSummary.Title, ShouldResemble, "IndexTitle")
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Source, ShouldResemble, "IndexSource")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//--------------------------------------------------------
indexWithNoAnnotations := CreateMultiarchWith().Images(
[]Image{
CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build(),
CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build(),
},
).Build()
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithNoAnnotations, Reference: "tag"},
},
})
So(err, ShouldBeNil)
digest = indexWithNoAnnotations.DigestStr()
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil)
So(*imageSummary.LastUpdated, ShouldEqual, defaultCreatedTime)
So(*imageSummary.Description, ShouldBeBlank)
So(*imageSummary.Licenses, ShouldBeBlank)
So(*imageSummary.Vendor, ShouldBeBlank)
So(*imageSummary.Authors, ShouldBeBlank)
So(*imageSummary.Title, ShouldBeBlank)
So(*imageSummary.Documentation, ShouldBeBlank)
So(*imageSummary.Source, ShouldBeBlank)
err = metaDB.ResetDB()
So(err, ShouldBeNil)
})
}
func TestConvertErrors(t *testing.T) {
ctx := context.Background()
log := log.NewLogger("debug", "")
Convey("Errors", t, func() {
Convey("RepoMeta2ExpandedRepoInfo", func() {
_, imgSums := convert.RepoMeta2ExpandedRepoInfo(ctx,
mTypes.RepoMeta{
Tags: map[mTypes.Tag]mTypes.Descriptor{"tag": {MediaType: "bad-type", Digest: "digest"}},
},
map[string]mTypes.ImageMeta{
"digest": {},
},
convert.SkipQGLField{}, nil,
log,
)
So(len(imgSums), ShouldEqual, 0)
})
Convey("RepoMeta2ExpandedRepoInfo - bad ctx value", func() {
uacKey := reqCtx.GetContextKey()
ctx := context.WithValue(ctx, uacKey, "bad context")
_, imgSums := convert.RepoMeta2ExpandedRepoInfo(ctx,
mTypes.RepoMeta{},
map[string]mTypes.ImageMeta{
"digest": {},
},
convert.SkipQGLField{}, nil,
log,
)
So(len(imgSums), ShouldEqual, 0)
})
Convey("RepoMeta2ExpandedRepoInfo - nil ctx value", func() {
uacKey := reqCtx.GetContextKey()
ctx := context.WithValue(ctx, uacKey, nil)
_, imgSums := convert.RepoMeta2ExpandedRepoInfo(ctx,
mTypes.RepoMeta{},
map[string]mTypes.ImageMeta{
"digest": {},
},
convert.SkipQGLField{}, nil,
log,
)
So(len(imgSums), ShouldEqual, 0)
})
})
}