mirror of
https://github.com/project-zot/zot.git
synced 2026-06-18 05:28:07 +08:00
9dfa7c3ae6
Replace MakeTempFile usage with MakeTempFilePath and MakeTempFileWithContent helpers that automatically handle file lifecycle. This prevents resource leaks by ensuring temporary files are properly closed. Shoudld also make the tests easier to read. Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
928 lines
28 KiB
Go
928 lines
28 KiB
Go
//go:build search
|
|
|
|
//
|
|
//nolint:dupl
|
|
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
"github.com/spf13/cobra"
|
|
|
|
zerr "zotregistry.dev/zot/v2/errors"
|
|
"zotregistry.dev/zot/v2/pkg/common"
|
|
)
|
|
|
|
func TestSearchAllImages(t *testing.T) {
|
|
Convey("SearchAllImages", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getAllImagesFn: func(ctx context.Context, config SearchConfig, username, password string,
|
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
|
) {
|
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
|
|
|
channel <- stringResult{StrValue: str, Err: err}
|
|
},
|
|
})
|
|
|
|
err := SearchAllImages(searchConfig)
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
}
|
|
|
|
func TestSearchAllImagesGQL(t *testing.T) {
|
|
Convey("SearchAllImagesGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
|
) (*common.ImageListResponse, error) {
|
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
}}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchAllImagesGQL(searchConfig)
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchAllImagesGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
|
) (*common.ImageListResponse, error) {
|
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
}}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchAllImagesGQL(searchConfig)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchImageByName(t *testing.T) {
|
|
Convey("SearchImageByName", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
|
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
|
) {
|
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
|
|
|
channel <- stringResult{StrValue: str, Err: err}
|
|
},
|
|
})
|
|
|
|
err := SearchImageByName(searchConfig, "repo")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchImageByName error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
|
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
|
) {
|
|
channel <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
|
},
|
|
})
|
|
|
|
err := SearchImageByName(searchConfig, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchImageByNameGQL(t *testing.T) {
|
|
Convey("SearchImageByNameGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
|
) (*common.ImageListResponse, error) {
|
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
}}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchImageByNameGQL(searchConfig, "repo")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchImageByNameGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
|
) (*common.ImageListResponse, error) {
|
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
}}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchImageByNameGQL(searchConfig, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchImagesByDigest(t *testing.T) {
|
|
Convey("SearchImagesByDigest", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
|
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
|
) {
|
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
|
|
|
rch <- stringResult{StrValue: str, Err: err}
|
|
},
|
|
})
|
|
|
|
err := SearchImagesByDigest(searchConfig, godigest.FromString("str").String())
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchImagesByDigest error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
|
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
|
) {
|
|
rch <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
|
},
|
|
})
|
|
|
|
err := SearchImagesByDigest(searchConfig, godigest.FromString("str").String())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchDerivedImageListGQL(t *testing.T) {
|
|
Convey("SearchDerivedImageListGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
derivedImage string) (*common.DerivedImageListResponse, error,
|
|
) {
|
|
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{
|
|
getMockImageSummary(),
|
|
},
|
|
},
|
|
}}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchDerivedImageListGQL(searchConfig, "repo:tag")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchDerivedImageListGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
derivedImage string) (*common.DerivedImageListResponse, error,
|
|
) {
|
|
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{}},
|
|
}}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchDerivedImageListGQL(searchConfig, "repo:tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchBaseImageListGQL(t *testing.T) {
|
|
Convey("SearchBaseImageListGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
derivedImage string) (*common.BaseImageListResponse, error,
|
|
) {
|
|
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{
|
|
getMockImageSummary(),
|
|
}},
|
|
}}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchBaseImageListGQL(searchConfig, "repo:tag")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchBaseImageListGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
derivedImage string) (*common.BaseImageListResponse, error,
|
|
) {
|
|
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{}},
|
|
}}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchBaseImageListGQL(searchConfig, "repo:tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchImagesForDigestGQL(t *testing.T) {
|
|
Convey("SearchImagesForDigestGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
|
|
password string, digest string) (*common.ImagesForDigest, error,
|
|
) {
|
|
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
}}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchImagesForDigestGQL(searchConfig, "digest")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchImagesForDigestGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
|
|
password string, digest string) (*common.ImagesForDigest, error,
|
|
) {
|
|
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{},
|
|
}}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchImagesForDigestGQL(searchConfig, "digest")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchCVEForImageGQL(t *testing.T) {
|
|
Convey("SearchCVEForImageGQL normal mode", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
imageName string, searchedCVE string) (*cveResult, error,
|
|
) {
|
|
return &cveResult{
|
|
Data: cveData{
|
|
CVEListForImage: cveListForImage{
|
|
CVEList: []cve{
|
|
{
|
|
ID: "dummyCVEID",
|
|
Description: "Description of the CVE",
|
|
Title: "Title of that CVE",
|
|
Severity: "HIGH",
|
|
PackageList: []packageList{
|
|
{
|
|
Name: "packagename",
|
|
FixedVersion: "fixedver",
|
|
InstalledVersion: "installedver",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: "test-cve-id2",
|
|
Description: "Test CVE ID 2",
|
|
Title: "Test CVE 2",
|
|
Severity: "HIGH",
|
|
PackageList: []packageList{
|
|
{
|
|
Name: "packagename",
|
|
PackagePath: "/usr/bin/dummy.jar",
|
|
FixedVersion: "fixedver",
|
|
InstalledVersion: "installedver",
|
|
},
|
|
{
|
|
Name: "packagename",
|
|
PackagePath: "/usr/bin/dummy.gem",
|
|
FixedVersion: "fixedver",
|
|
InstalledVersion: "installedver",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Summary: common.ImageVulnerabilitySummary{
|
|
Count: 2,
|
|
UnknownCount: 0,
|
|
LowCount: 0,
|
|
MediumCount: 0,
|
|
HighCount: 2,
|
|
CriticalCount: 0,
|
|
MaxSeverity: "HIGH",
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchCVEForImageGQL(searchConfig, "repo-test", "dummyCVEID")
|
|
So(err, ShouldBeNil)
|
|
bufferContent := buff.String()
|
|
bufferLines := strings.Split(bufferContent, "\n")
|
|
|
|
// Expected result - each row indicates a row of the table with reduced spaces
|
|
expected := []string{
|
|
"CRITICAL 0, HIGH 2, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 2",
|
|
"",
|
|
"ID SEVERITY TITLE VULNERABLE PACKAGE PATH INSTALL-VER FIXED-VER",
|
|
"dummyCVEID HIGH Title of that CVE",
|
|
"packagename - installedver fixedver",
|
|
"test-cve-id2 HIGH Test CVE 2",
|
|
"packagename /usr/bin/dummy.jar installedver fixedver",
|
|
"packagename /usr/bin/dummy.gem installedver fixedver",
|
|
}
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
for lineIndex := 0; lineIndex < len(expected); lineIndex++ {
|
|
line := space.ReplaceAllString(bufferLines[lineIndex], " ")
|
|
So(line, ShouldEqualTrimSpace, expected[lineIndex])
|
|
}
|
|
})
|
|
|
|
Convey("SearchCVEForImageGQL verbose mode", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
imageName string, searchedCVE string) (*cveResult, error,
|
|
) {
|
|
return &cveResult{
|
|
Data: cveData{
|
|
CVEListForImage: cveListForImage{
|
|
CVEList: []cve{
|
|
{
|
|
ID: "CVE-100",
|
|
Description: "",
|
|
Title: "CVE-100 Title",
|
|
Severity: "HIGH",
|
|
PackageList: []packageList{},
|
|
},
|
|
{
|
|
ID: "CVE-101",
|
|
Description: "Desc 101\n",
|
|
Title: "CVE-101 Title",
|
|
Severity: "HIGH",
|
|
PackageList: []packageList{
|
|
{
|
|
Name: "Pkg1",
|
|
FixedVersion: "2.0.0",
|
|
InstalledVersion: "1.0.0",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: "CVE-102",
|
|
Description: "Desc 102",
|
|
Title: "CVE-102 Title",
|
|
Severity: "HIGH",
|
|
PackageList: []packageList{
|
|
{
|
|
Name: "dummy-java",
|
|
PackagePath: "/usr/bin/dummy.jar",
|
|
FixedVersion: "4.0.0",
|
|
InstalledVersion: "3.0.0",
|
|
},
|
|
{
|
|
Name: "dummy-ruby",
|
|
PackagePath: "/usr/bin/dummy.gem",
|
|
FixedVersion: "5.0.0",
|
|
InstalledVersion: "1.0.0",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Summary: common.ImageVulnerabilitySummary{
|
|
Count: 3,
|
|
UnknownCount: 0,
|
|
LowCount: 0,
|
|
MediumCount: 0,
|
|
HighCount: 3,
|
|
CriticalCount: 0,
|
|
MaxSeverity: "HIGH",
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
searchConfig.Verbose = true
|
|
err := SearchCVEForImageGQL(searchConfig, "repo-test", "dummyCVEID")
|
|
So(err, ShouldBeNil)
|
|
bufferContent := buff.String()
|
|
bufferLines := strings.Split(bufferContent, "\n")
|
|
|
|
// Expected result - each row indicates a line in the output
|
|
expected := []string{
|
|
"CRITICAL 0, HIGH 3, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 3",
|
|
"",
|
|
"CVE-100",
|
|
"Severity: HIGH",
|
|
"Title: CVE-100 Title",
|
|
"Description:",
|
|
"Not Specified",
|
|
"",
|
|
"Vulnerable Packages:",
|
|
"No Vulnerable Packages",
|
|
"",
|
|
"",
|
|
"CVE-101",
|
|
"Severity: HIGH",
|
|
"Title: CVE-101 Title",
|
|
"Description:",
|
|
"Desc 101",
|
|
"",
|
|
"Vulnerable Packages:",
|
|
" Package Name: Pkg1",
|
|
" Package Path: ",
|
|
" Installed Version: 1.0.0",
|
|
" Fixed Version: 2.0.0",
|
|
"",
|
|
"",
|
|
"CVE-102",
|
|
"Severity: HIGH",
|
|
"Title: CVE-102 Title",
|
|
"Description:",
|
|
"Desc 102",
|
|
"",
|
|
"Vulnerable Packages:",
|
|
" Package Name: dummy-java",
|
|
" Package Path: /usr/bin/dummy.jar",
|
|
" Installed Version: 3.0.0",
|
|
" Fixed Version: 4.0.0",
|
|
"",
|
|
" Package Name: dummy-ruby",
|
|
" Package Path: /usr/bin/dummy.gem",
|
|
" Installed Version: 1.0.0",
|
|
" Fixed Version: 5.0.0",
|
|
"",
|
|
"",
|
|
}
|
|
|
|
for index, expectedLine := range expected {
|
|
So(bufferLines[index], ShouldEqual, expectedLine)
|
|
}
|
|
})
|
|
|
|
Convey("SearchCVEForImageGQL with injected error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
imageName string, searchedCVE string) (*cveResult, error,
|
|
) {
|
|
return &cveResult{}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchCVEForImageGQL(searchConfig, "repo-test", "dummyCVEID")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchImagesByCVEIDGQL(t *testing.T) {
|
|
Convey("SearchImagesByCVEIDGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
imageName, cveID string) (*common.ImagesForCve, error,
|
|
) {
|
|
return &common.ImagesForCve{
|
|
ImagesForCVEList: common.ImagesForCVEList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{
|
|
getMockImageSummary(),
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchImagesByCVEIDGQL(searchConfig, "repo", "CVE-12345")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchImagesByCVEIDGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
imageName, cveID string) (*common.ImagesForCve, error,
|
|
) {
|
|
return &common.ImagesForCve{
|
|
ImagesForCVEList: common.ImagesForCVEList{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{},
|
|
},
|
|
}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchImagesByCVEIDGQL(searchConfig, "repo", "CVE-12345")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchFixedTagsGQL(t *testing.T) {
|
|
Convey("SearchFixedTagsGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
|
) {
|
|
return &common.ImageListWithCVEFixedResponse{
|
|
ImageListWithCVEFixed: common.ImageListWithCVEFixed{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
|
Results: []common.ImageSummary{getMockImageSummary()},
|
|
},
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchFixedTagsGQL(searchConfig, "repo", "CVE-12345")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
|
|
})
|
|
|
|
Convey("SearchFixedTagsGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
|
) {
|
|
return &common.ImageListWithCVEFixedResponse{
|
|
ImageListWithCVEFixed: common.ImageListWithCVEFixed{
|
|
PaginatedImagesResult: common.PaginatedImagesResult{},
|
|
},
|
|
}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchFixedTagsGQL(searchConfig, "repo", "CVE-12345")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchReferrersGQL(t *testing.T) {
|
|
Convey("SearchReferrersGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
repo, digest string) (*common.ReferrersResp, error,
|
|
) {
|
|
return &common.ReferrersResp{
|
|
ReferrersResult: common.ReferrersResult{
|
|
Referrers: []common.Referrer{{
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Size: 100,
|
|
ArtifactType: "art.type",
|
|
Digest: godigest.FromString("123").String(),
|
|
}},
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
err := SearchReferrersGQL(searchConfig, "repo@"+godigest.FromString("str").String())
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring,
|
|
"art.type 100 B sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3")
|
|
})
|
|
|
|
Convey("SearchReferrersGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
repo, digest string) (*common.ReferrersResp, error,
|
|
) {
|
|
return &common.ReferrersResp{}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchReferrersGQL(searchConfig, "repo@"+godigest.FromString("str").String())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestGlobalSearchGQL(t *testing.T) {
|
|
Convey("GlobalSearchGQL", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
query string) (*common.GlobalSearch, error,
|
|
) {
|
|
return &common.GlobalSearch{
|
|
Repos: []common.RepoSummary{{
|
|
Name: "repo",
|
|
Size: "100",
|
|
LastUpdated: time.Date(2010, 1, 1, 1, 1, 1, 0, time.UTC),
|
|
}},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
err := GlobalSearchGQL(searchConfig, "repo")
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring,
|
|
"repo ")
|
|
})
|
|
|
|
Convey("GlobalSearchGQL error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
|
query string) (*common.GlobalSearch, error,
|
|
) {
|
|
return &common.GlobalSearch{}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := GlobalSearchGQL(searchConfig, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchReferrers(t *testing.T) {
|
|
Convey("SearchReferrers", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
repo string, digest string) (referrersResult, error,
|
|
) {
|
|
return referrersResult([]common.Referrer{
|
|
{
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Size: 100,
|
|
ArtifactType: "art.type",
|
|
Digest: godigest.FromString("123").String(),
|
|
},
|
|
}), nil
|
|
},
|
|
})
|
|
|
|
err := SearchReferrers(searchConfig, "repo@"+godigest.FromString("str").String())
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring,
|
|
"art.type 100 B sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3")
|
|
})
|
|
|
|
Convey("SearchReferrers error", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{
|
|
getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
|
repo string, digest string) (referrersResult, error,
|
|
) {
|
|
return referrersResult{}, zerr.ErrInjected
|
|
},
|
|
})
|
|
|
|
err := SearchReferrers(searchConfig, "repo@"+godigest.FromString("str").String())
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestSearchRepos(t *testing.T) {
|
|
Convey("SearchRepos", t, func() {
|
|
buff := bytes.NewBufferString("")
|
|
searchConfig := getMockSearchConfig(buff, mockService{})
|
|
|
|
err := SearchRepos(searchConfig)
|
|
So(err, ShouldBeNil)
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
actual := strings.TrimSpace(str)
|
|
So(actual, ShouldContainSubstring, "repo1")
|
|
So(actual, ShouldContainSubstring, "repo2")
|
|
})
|
|
}
|
|
|
|
func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) SearchConfig {
|
|
return SearchConfig{
|
|
ResultWriter: buff,
|
|
User: "",
|
|
SearchService: mockService,
|
|
ServURL: "http://127.0.0.1:8000",
|
|
OutputFormat: "",
|
|
VerifyTLS: false,
|
|
FixedFlag: false,
|
|
Verbose: false,
|
|
Debug: false,
|
|
}
|
|
}
|
|
|
|
func getMockImageStruct() imageStruct {
|
|
return imageStruct(common.ImageSummary{
|
|
RepoName: "repo", Tag: "tag",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: godigest.FromString("str").String(),
|
|
Size: "100",
|
|
Manifests: []common.ManifestSummary{{
|
|
Size: "100",
|
|
Platform: common.Platform{Os: "os", Arch: "arch"},
|
|
Digest: godigest.FromString("str").String(),
|
|
ConfigDigest: godigest.FromString("str").String(),
|
|
}},
|
|
})
|
|
}
|
|
|
|
func getMockImageSummary() common.ImageSummary {
|
|
return common.ImageSummary{
|
|
RepoName: "repo", Tag: "tag",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Digest: godigest.FromString("str").String(),
|
|
Size: "100",
|
|
Manifests: []common.ManifestSummary{{
|
|
Size: "100",
|
|
Platform: common.Platform{Os: "os", Arch: "arch"},
|
|
Digest: godigest.FromString("str").String(),
|
|
ConfigDigest: godigest.FromString("str").String(),
|
|
}},
|
|
}
|
|
}
|
|
|
|
func TestUtils(t *testing.T) {
|
|
Convey("Utils", t, func() {
|
|
ok := haveSameArgs(field{"query", []struct {
|
|
Name string `json:"name"`
|
|
}{
|
|
{Name: "arg1"}, {Name: "arg2"},
|
|
}}, GQLQuery{
|
|
Name: "query", Args: []string{"arg1"},
|
|
})
|
|
So(ok, ShouldBeFalse)
|
|
|
|
ok = haveSameArgs(field{"query", []struct {
|
|
Name string `json:"name"`
|
|
}{
|
|
{Name: "arg1"}, {Name: "arg2"},
|
|
}}, GQLQuery{
|
|
Name: "query", Args: []string{"arg1", "arg3"},
|
|
})
|
|
So(ok, ShouldBeFalse)
|
|
|
|
err := containsGQLQueryWithParams(
|
|
[]field{
|
|
{Name: "query"},
|
|
},
|
|
[]typeInfo{},
|
|
GQLQuery{Name: "other-name"},
|
|
)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetConfigOptions", t, func() {
|
|
// no flags
|
|
cmd := &cobra.Command{}
|
|
isSpinner, verifyTLS, err := GetCliConfigOptions(cmd)
|
|
So(err, ShouldNotBeNil)
|
|
So(isSpinner, ShouldBeFalse)
|
|
So(verifyTLS, ShouldBeFalse)
|
|
|
|
// bad showspinner
|
|
_ = makeConfigFile(t, `{"configs":[{"_name":"imagetest","showspinner":"bad", "verify-tls": false}]}`)
|
|
cmd = &cobra.Command{}
|
|
cmd.Flags().String(ConfigFlag, "imagetest", "")
|
|
isSpinner, verifyTLS, err = GetCliConfigOptions(cmd)
|
|
So(err, ShouldNotBeNil)
|
|
So(isSpinner, ShouldBeFalse)
|
|
So(verifyTLS, ShouldBeFalse)
|
|
|
|
// bad verify-tls
|
|
_ = makeConfigFile(t, `{"configs":[{"_name":"imagetest","showspinner":false, "verify-tls": "bad"}]}`)
|
|
cmd = &cobra.Command{}
|
|
cmd.Flags().String(ConfigFlag, "imagetest", "")
|
|
isSpinner, verifyTLS, err = GetCliConfigOptions(cmd)
|
|
So(err, ShouldNotBeNil)
|
|
So(isSpinner, ShouldBeFalse)
|
|
So(verifyTLS, ShouldBeFalse)
|
|
})
|
|
|
|
Convey("GetServerURLFromFlags", t, func() {
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().String(URLFlag, "url", "")
|
|
url, err := GetServerURLFromFlags(cmd)
|
|
So(url, ShouldResemble, "url")
|
|
So(err, ShouldBeNil)
|
|
|
|
// err no config or url
|
|
cmd = &cobra.Command{}
|
|
url, err = GetServerURLFromFlags(cmd)
|
|
So(url, ShouldResemble, "")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
// err ulr from config is empty
|
|
_ = makeConfigFile(t, `{"configs":[{"_name":"imagetest"}]}`)
|
|
cmd = &cobra.Command{}
|
|
cmd.Flags().String(ConfigFlag, "imagetest", "")
|
|
url, err = GetServerURLFromFlags(cmd)
|
|
So(url, ShouldResemble, "")
|
|
So(err, ShouldNotBeNil)
|
|
|
|
// err reading the server url from config
|
|
_ = makeConfigFile(t, "{}")
|
|
cmd = &cobra.Command{}
|
|
cmd.Flags().String(ConfigFlag, "imagetest", "")
|
|
url, err = GetServerURLFromFlags(cmd)
|
|
So(url, ShouldResemble, "")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("CheckExtEndPointQuery", t, func() {
|
|
// invalid url
|
|
err := CheckExtEndPointQuery(SearchConfig{
|
|
User: "",
|
|
ServURL: "bad-url",
|
|
})
|
|
So(err, ShouldNotBeNil)
|
|
|
|
// good url but no connection
|
|
err = CheckExtEndPointQuery(SearchConfig{
|
|
User: "",
|
|
ServURL: "http://127.0.0.1:5000",
|
|
VerifyTLS: false,
|
|
Debug: false,
|
|
ResultWriter: io.Discard,
|
|
})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|