2023-10-03 13:15:39 -05:00
|
|
|
//go:build search
|
|
|
|
// +build search
|
|
|
|
|
|
|
|
package client_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
|
2024-01-31 23:34:07 -05:00
|
|
|
"zotregistry.dev/zot/pkg/api"
|
|
|
|
"zotregistry.dev/zot/pkg/api/config"
|
|
|
|
"zotregistry.dev/zot/pkg/cli/client"
|
|
|
|
extconf "zotregistry.dev/zot/pkg/extensions/config"
|
|
|
|
test "zotregistry.dev/zot/pkg/test/common"
|
|
|
|
. "zotregistry.dev/zot/pkg/test/image-utils"
|
|
|
|
ociutils "zotregistry.dev/zot/pkg/test/oci-utils"
|
2023-10-03 13:15:39 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
customArtTypeV1 = "application/custom.art.type.v1"
|
|
|
|
customArtTypeV2 = "application/custom.art.type.v2"
|
|
|
|
repoName = "repo"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestReferrerCLI(t *testing.T) {
|
|
|
|
Convey("Test GQL", t, func() {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.GC = false
|
|
|
|
defaultVal := true
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
repo := repoName
|
|
|
|
image := CreateRandomImage()
|
|
|
|
|
|
|
|
err := UploadImage(image, baseURL, repo, "tag")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
ref1 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref2 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
ArtifactConfig(customArtTypeV1).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref3 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
ArtifactType(customArtTypeV2).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
|
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
|
|
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
|
|
|
|
os.Remove(configPath)
|
|
|
|
|
|
|
|
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff = &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
|
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
|
|
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Test REST", t, func() {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.GC = false
|
|
|
|
defaultVal := false
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
repo := repoName
|
|
|
|
image := CreateRandomImage()
|
|
|
|
|
|
|
|
err := UploadImage(image, baseURL, repo, "tag")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
ref1 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref2 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
ArtifactConfig(customArtTypeV1).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref3 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
ArtifactType(customArtTypeV2).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// get referrers by digest
|
|
|
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
|
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
|
|
|
|
os.Remove(configPath)
|
|
|
|
|
|
|
|
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff = &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
|
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
|
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormatsReferrersCLI(t *testing.T) {
|
|
|
|
Convey("Create server", t, func() {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.GC = false
|
|
|
|
defaultVal := false
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
repo := repoName
|
|
|
|
image := CreateRandomImage()
|
|
|
|
|
|
|
|
err := UploadImage(image, baseURL, repo, "tag")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// add referrers
|
|
|
|
ref1 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref2 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
ArtifactConfig(customArtTypeV1).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
ref3 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
RandomConfig().
|
|
|
|
ArtifactType(customArtTypeV2).
|
|
|
|
Subject(image.DescriptorRef()).Build()
|
|
|
|
|
|
|
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
Convey("JSON format", func() {
|
|
|
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "json", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
Convey("YAML format", func() {
|
|
|
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "yaml", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
Convey("Invalid format", func() {
|
|
|
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "invalid_format", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReferrersCLIErrors(t *testing.T) {
|
|
|
|
Convey("Errors", t, func() {
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
Convey("no url provided", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest","showspinner":false}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("getConfigValue", func() {
|
|
|
|
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`bad-json`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("bad showspinnerConfig ", func() {
|
|
|
|
args := []string{"query", "repo", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("bad verifyTLSConfig ", func() {
|
|
|
|
args := []string{"query", "repo", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(
|
|
|
|
`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("url from config is empty", func() {
|
|
|
|
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"", "showspinner":false}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("bad params combination", func() {
|
|
|
|
args := []string{"query", "repo", "reftest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSearchCLI(t *testing.T) {
|
|
|
|
Convey("Test GQL", t, func() {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.GC = false
|
|
|
|
defaultVal := true
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
const (
|
|
|
|
repo1 = "repo"
|
|
|
|
r1tag1 = "repo1tag1"
|
|
|
|
r1tag2 = "repo1tag2"
|
|
|
|
|
|
|
|
repo2 = "repo/alpine"
|
|
|
|
r2tag1 = "repo2tag1"
|
|
|
|
r2tag2 = "repo2tag2"
|
|
|
|
|
|
|
|
repo3 = "repo/test/alpine"
|
|
|
|
r3tag1 = "repo3tag1"
|
|
|
|
r3tag2 = "repo3tag2"
|
|
|
|
)
|
|
|
|
|
|
|
|
image1 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
ImageConfig(ispec.Image{
|
|
|
|
Created: DefaultTimeRef(),
|
|
|
|
Platform: ispec.Platform{OS: "Os", Architecture: "Arch"},
|
|
|
|
}).
|
|
|
|
Build()
|
|
|
|
formatterDigest1 := image1.Digest().Encoded()[:8]
|
|
|
|
|
|
|
|
image2 := CreateImageWith().
|
|
|
|
RandomLayers(1, 10).
|
|
|
|
DefaultConfig().
|
|
|
|
Build()
|
|
|
|
formatterDigest2 := image2.Digest().Encoded()[:8]
|
|
|
|
|
|
|
|
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// search by repos
|
|
|
|
|
|
|
|
args := []string{"query", "test/alpin", "--verbose", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "NAME SIZE LAST UPDATED DOWNLOADS STARS PLATFORMS")
|
|
|
|
So(str, ShouldContainSubstring, "repo/test/alpine 1.1kB 2010-01-01 01:01:01 +0000 UTC 0 0")
|
|
|
|
So(str, ShouldContainSubstring, "Os/Arch")
|
|
|
|
So(str, ShouldContainSubstring, "linux/amd64")
|
|
|
|
|
|
|
|
fmt.Println("\n", buff.String())
|
|
|
|
|
|
|
|
os.Remove(configPath)
|
|
|
|
|
|
|
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
args = []string{"query", "repo/alpine:", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff = &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
|
|
So(str, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
|
|
So(str, ShouldContainSubstring, "repo/alpine repo2tag1 Os/Arch "+formatterDigest1+" false 525B")
|
|
|
|
So(str, ShouldContainSubstring, "repo/alpine repo2tag2 linux/amd64 "+formatterDigest2+" false 552B")
|
|
|
|
|
|
|
|
fmt.Println("\n", buff.String())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormatsSearchCLI(t *testing.T) {
|
|
|
|
Convey("", t, func() {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.GC = false
|
|
|
|
defaultVal := true
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
const (
|
|
|
|
repo1 = "repo"
|
|
|
|
r1tag1 = "repo1tag1"
|
|
|
|
r1tag2 = "repo1tag2"
|
|
|
|
|
|
|
|
repo2 = "repo/alpine"
|
|
|
|
r2tag1 = "repo2tag1"
|
|
|
|
r2tag2 = "repo2tag2"
|
|
|
|
|
|
|
|
repo3 = "repo/test/alpine"
|
|
|
|
r3tag1 = "repo3tag1"
|
|
|
|
r3tag2 = "repo3tag2"
|
|
|
|
)
|
|
|
|
|
|
|
|
image1 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
|
|
|
image2 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
|
|
|
|
|
|
|
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
Convey("JSON format", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "json", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("YAML format", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "yaml", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Invalid format", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
|
|
baseURL))
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSearchCLIErrors(t *testing.T) {
|
|
|
|
Convey("Errors", t, func() {
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
|
|
|
|
Convey("no url provided", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest","showspinner":false}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("getConfigValue", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`bad-json`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("bad showspinnerConfig ", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(
|
|
|
|
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("bad verifyTLSConfig ", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(
|
|
|
|
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("url from config is empty", func() {
|
|
|
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
|
|
|
|
|
|
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest", "url":"", "showspinner":false}]}`)
|
|
|
|
|
|
|
|
defer os.Remove(configPath)
|
|
|
|
|
|
|
|
buff := &bytes.Buffer{}
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSearchSort(t *testing.T) {
|
|
|
|
rootDir := t.TempDir()
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
|
|
|
|
defaultVal := true
|
|
|
|
conf.Extensions = &extconf.ExtensionConfig{
|
|
|
|
Search: &extconf.SearchConfig{
|
|
|
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
|
|
CVE: nil,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = rootDir
|
|
|
|
|
|
|
|
image1 := CreateImageWith().DefaultLayers().
|
|
|
|
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
|
|
|
Build()
|
|
|
|
|
|
|
|
image2 := CreateImageWith().DefaultLayers().
|
|
|
|
ImageConfig(ispec.Image{Created: DateRef(2020, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
|
|
|
Build()
|
|
|
|
|
|
|
|
storeController := ociutils.GetDefaultStoreController(rootDir, ctlr.Log)
|
|
|
|
|
|
|
|
err := WriteImageToFileSystem(image1, "b-repo", "tag2", storeController)
|
|
|
|
if err != nil {
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
|
|
|
|
err = WriteImageToFileSystem(image2, "a-test-repo", "tag2", storeController)
|
|
|
|
if err != nil {
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(conf.HTTP.Port)
|
|
|
|
|
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
Convey("test sorting", t, func() {
|
|
|
|
args := []string{"query", "repo", "--sort-by", "relevance", "--url", baseURL}
|
|
|
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str := buff.String()
|
|
|
|
So(strings.Index(str, "b-repo"), ShouldBeLessThan, strings.Index(str, "a-test-repo"))
|
|
|
|
|
|
|
|
args = []string{"query", "repo", "--sort-by", "alpha-asc", "--url", baseURL}
|
|
|
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
cmd.SetOut(buff)
|
|
|
|
cmd.SetErr(buff)
|
|
|
|
cmd.SetArgs(args)
|
|
|
|
err = cmd.Execute()
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str = buff.String()
|
|
|
|
So(strings.Index(str, "a-test-repo"), ShouldBeLessThan, strings.Index(str, "b-repo"))
|
|
|
|
})
|
|
|
|
}
|