mirror of
https://github.com/containers/podman.git
synced 2026-03-27 11:03:09 -04:00
Merge pull request #27333 from Honny1/search-tests-without-net
Eliminate network dependencies in `podman search` e2e tests with mock registry
This commit is contained in:
562
test/e2e/search_mock_registry.go
Normal file
562
test/e2e/search_mock_registry.go
Normal file
@@ -0,0 +1,562 @@
|
||||
//go:build linux || freebsd
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2" //nolint:staticcheck
|
||||
. "github.com/onsi/gomega" //nolint:staticcheck
|
||||
)
|
||||
|
||||
const (
|
||||
contentTypeJSON = "application/json"
|
||||
)
|
||||
|
||||
var searchResults = map[string]any{
|
||||
"alpine": map[string]any{
|
||||
"query": "alpine",
|
||||
"num_results": 25,
|
||||
"num_pages": 2,
|
||||
"page": 1,
|
||||
"page_size": 25,
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "cilium/alpine-curl",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/cilium/alpine-curl",
|
||||
},
|
||||
{
|
||||
"name": "libpod/alpine",
|
||||
"description": "This image is used for testing purposes only. Do NOT use it in production!",
|
||||
"is_public": true,
|
||||
"href": "/repository/libpod/alpine",
|
||||
"stars": 11,
|
||||
"official": true,
|
||||
},
|
||||
{
|
||||
"name": "openshifttest/alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/openshifttest/alpine",
|
||||
"stars": 5,
|
||||
"official": false,
|
||||
"is_automated": true,
|
||||
},
|
||||
{
|
||||
"name": "openshifttest/base-alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/openshifttest/base-alpine",
|
||||
},
|
||||
{
|
||||
"name": "astronomer/ap-alpine",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/astronomer/ap-alpine",
|
||||
},
|
||||
{
|
||||
"name": "almworks/alpine-curl",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/almworks/alpine-curl",
|
||||
},
|
||||
{
|
||||
"name": "jitesoft/alpine",
|
||||
"description": "# Alpine linux",
|
||||
"is_public": true,
|
||||
"href": "/repository/jitesoft/alpine",
|
||||
},
|
||||
{
|
||||
"name": "dougbtv/alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/dougbtv/alpine",
|
||||
},
|
||||
{
|
||||
"name": "tccr/alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/tccr/alpine",
|
||||
},
|
||||
{
|
||||
"name": "aptible/alpine",
|
||||
"description": "Alpine base image, borrowed from gliderlabs/alpine",
|
||||
"is_public": true,
|
||||
"href": "/repository/aptible/alpine",
|
||||
},
|
||||
{
|
||||
"name": "openshifttest/nginx-alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/openshifttest/nginx-alpine",
|
||||
},
|
||||
{
|
||||
"name": "wire/alpine-git",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/wire/alpine-git",
|
||||
},
|
||||
{
|
||||
"name": "ditto/alpine-non-root",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/ditto/alpine-non-root",
|
||||
},
|
||||
{
|
||||
"name": "kubevirt/alpine-ext-kernel-boot-demo",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/kubevirt/alpine-ext-kernel-boot-demo",
|
||||
},
|
||||
{
|
||||
"name": "ansible/alpine321-test-container",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/ansible/alpine321-test-container",
|
||||
},
|
||||
{
|
||||
"name": "crio/alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/crio/alpine",
|
||||
},
|
||||
{
|
||||
"name": "ansible/alpine-test-container",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/ansible/alpine-test-container",
|
||||
},
|
||||
{
|
||||
"name": "ansible/alpine322-test-container",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/ansible/alpine322-test-container",
|
||||
},
|
||||
{
|
||||
"name": "bedrock/alpine",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/bedrock/alpine",
|
||||
},
|
||||
{
|
||||
"name": "ansible/alpine3-test-container",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/ansible/alpine3-test-container",
|
||||
},
|
||||
{
|
||||
"name": "openshift-psap-qe/nginx-alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/openshift-psap-qe/nginx-alpine",
|
||||
},
|
||||
{
|
||||
"name": "startx/alpine",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/startx/alpine",
|
||||
},
|
||||
{
|
||||
"name": "pcc3202/alpine_multi",
|
||||
"description": "",
|
||||
"is_public": true,
|
||||
"href": "/repository/pcc3202/alpine_multi",
|
||||
},
|
||||
{
|
||||
"name": "nvlab/alpine",
|
||||
"description": nil,
|
||||
"is_public": true,
|
||||
"href": "/repository/nvlab/alpine",
|
||||
},
|
||||
{
|
||||
"name": "kubevirt/alpine-container-disk-demo",
|
||||
"description": "Part of kubevirt/kubevirt artifacts",
|
||||
"is_public": true,
|
||||
"href": "/repository/kubevirt/alpine-container-disk-demo",
|
||||
},
|
||||
},
|
||||
},
|
||||
"busybox": map[string]any{
|
||||
"num_results": 2,
|
||||
"query": "busybox",
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "busybox",
|
||||
"description": "Busybox base image",
|
||||
"star_count": 80,
|
||||
"is_official": true,
|
||||
"is_automated": false,
|
||||
},
|
||||
{
|
||||
"name": "progrium/busybox",
|
||||
"description": "Custom busybox build",
|
||||
"star_count": 15,
|
||||
"is_official": false,
|
||||
"is_automated": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"skopeo/stable:latest": map[string]any{
|
||||
"query": "skopeo/stable:latest",
|
||||
"num_results": 3,
|
||||
"num_pages": 1,
|
||||
"page": 1,
|
||||
"page_size": 25,
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "skopeo/stable",
|
||||
"description": "Stable Skopeo Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/skopeo/stable",
|
||||
},
|
||||
{
|
||||
"name": "skopeo/testing",
|
||||
"description": "Testing Skopeo Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/skopeo/testing",
|
||||
},
|
||||
{
|
||||
"name": "skopeo/upstream",
|
||||
"description": "Upstream Skopeo Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/skopeo/upstream",
|
||||
},
|
||||
},
|
||||
},
|
||||
"podman/stable": map[string]any{
|
||||
"query": "podman/stable",
|
||||
"num_results": 3,
|
||||
"num_pages": 1,
|
||||
"page": 1,
|
||||
"page_size": 25,
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "podman/stable",
|
||||
"description": "Stable Podman Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/podman/stable",
|
||||
},
|
||||
{
|
||||
"name": "podman/testing",
|
||||
"description": "Testing Podman Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/podman/testing",
|
||||
},
|
||||
{
|
||||
"name": "podman/upstream",
|
||||
"description": "Upstream Podman Image",
|
||||
"is_public": true,
|
||||
"href": "/repository/podman/upstream",
|
||||
},
|
||||
},
|
||||
},
|
||||
"testdigest_v2s1": map[string]any{
|
||||
"query": "testdigest_v2s1",
|
||||
"num_results": 2,
|
||||
"num_pages": 1,
|
||||
"page": 1,
|
||||
"page_size": 25,
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "libpod/testdigest_v2s1",
|
||||
"description": "Test image used by buildah regression tests",
|
||||
"is_public": true,
|
||||
"href": "/repository/libpod/testdigest_v2s1",
|
||||
},
|
||||
{
|
||||
"name": "libpod/testdigest_v2s1_with_dups",
|
||||
"description": "This is a specially crafted test-only image used in buildah CI and gating tests.",
|
||||
"is_public": true,
|
||||
"href": "/repository/libpod/testdigest_v2s1_with_dups",
|
||||
},
|
||||
},
|
||||
},
|
||||
"testdigest_v2s2": map[string]any{
|
||||
"query": "testdigest_v2s2",
|
||||
"num_results": 1,
|
||||
"num_pages": 1,
|
||||
"page": 1,
|
||||
"page_size": 25,
|
||||
"results": []map[string]any{
|
||||
{
|
||||
"name": "libpod/testdigest_v2s2",
|
||||
"description": "This is a specially crafted test-only image used in buildah CI and gating tests.",
|
||||
"is_public": true,
|
||||
"href": "/repository/libpod/testdigest_v2s2",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Mock repository tag data - simplified to just store tag lists
|
||||
var mockRepoTags = map[string][]string{
|
||||
"libpod/alpine": {"3.10.2", "3.2", "latest", "withbogusseccomp", "withseccomp"},
|
||||
"podman/stable": {
|
||||
"latest", "v1.4.2", "v1.4.4", "v1.5.0", "v1.5.1", "v1.6", "v1.6.2",
|
||||
"v1.9.0", "v1.9.1", "v2.0.2", "v2.0.6", "v2.1.1", "v2.2.1", "v3",
|
||||
"v3.1.2", "v3.2.0", "v3.2.1", "v3.2.2", "v3.2.3", "v3.3.0", "v3.3.1",
|
||||
"v3.4", "v3.4.0", "v3.4.1", "v3.4.2", "v3.4.4", "v3.4.7", "v4",
|
||||
"v4.1", "v4.1.0", "v4.1.1", "v4.2", "v4.2.0", "v4.2.1", "v4.3",
|
||||
"v4.3.0", "v4.3.1", "v4.4", "v4.4.1", "v4.4.2", "v4.4.4", "v4.5",
|
||||
"v4.5.0", "v4.5.1", "v4.6", "v4.6.1", "v4.6.2", "v4.7", "v4.7.0",
|
||||
"v4.7.2", "v4.8", "v4.8.0", "v4.8.1", "v4.8.2", "v4.8.3", "v4.9",
|
||||
"v4.9.0", "v4.9.3", "v4.9.4", "v4.9.4-immutable", "v4.9-immutable",
|
||||
"v4-immutable", "v5", "v5.0", "v5.0.1", "v5.0.1-immutable", "v5.0.2",
|
||||
"v5.0.2-immutable", "v5.0.3", "v5.0.3-immutable", "v5.0-immutable",
|
||||
"v5.1", "v5.1.0", "v5.1.0-immutable", "v5.1.1", "v5.1.1-immutable",
|
||||
"v5.1.2", "v5.1.2-immutable", "v5.1-immutable", "v5.2", "v5.2.0",
|
||||
"v5.2.0-immutable", "v5.2.1", "v5.2.1-immutable", "v5.2.2",
|
||||
"v5.2.2-immutable", "v5.2.3", "v5.2.3-immutable", "v5.2.5",
|
||||
"v5.2.5-immutable", "v5.2-immutable", "v5.3", "v5.3.0",
|
||||
"v5.3.0-immutable", "v5.3.1", "v5.3.1-immutable", "v5.3.2",
|
||||
"v5.3.2-immutable", "v5.3-immutable", "v5.4",
|
||||
},
|
||||
}
|
||||
|
||||
// Pagination tags for podman/stable (returned after v5.4 in pagination requests)
|
||||
// This simulates the specific test case where limit=100 and last=v5.4
|
||||
var podmanStablePaginatedTags = []string{
|
||||
"v5.4.0", "v5.4.0-immutable", "v5.4.1", "v5.4.1-immutable", "v5.4.2",
|
||||
"v5.4.2-immutable", "v5.4-immutable", "v5.5", "v5.5.0", "v5.5.0-immutable",
|
||||
"v5.5.1", "v5.5.1-immutable", "v5.5.2", "v5.5.2-immutable", "v5.5-immutable",
|
||||
"v5.6", "v5.6.0", "v5.6.0-immutable", "v5.6.1", "v5.6.1-immutable", "v5.6.2",
|
||||
"v5.6.2-immutable", "v5.6-immutable", "v5-immutable",
|
||||
}
|
||||
|
||||
func writeJSONResponse(w http.ResponseWriter, data any) {
|
||||
w.Header().Set("Content-Type", contentTypeJSON)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func handleV1Search(w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query().Get("q")
|
||||
if decodedQuery, err := url.QueryUnescape(query); err == nil {
|
||||
query = decodedQuery
|
||||
}
|
||||
|
||||
limitStr := r.URL.Query().Get("n")
|
||||
limitNum := -1
|
||||
if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
|
||||
limitNum = limit
|
||||
} else if err != nil {
|
||||
http.Error(w, "Invalid limit parameter", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
results := searchForResults(query)
|
||||
|
||||
if results != nil {
|
||||
response := applyLimitToResults(results, limitNum)
|
||||
writeJSONResponse(w, response)
|
||||
} else {
|
||||
defaultResponse := map[string]any{
|
||||
"num_results": 0,
|
||||
"query": query,
|
||||
"results": []any{},
|
||||
}
|
||||
writeJSONResponse(w, defaultResponse)
|
||||
}
|
||||
}
|
||||
|
||||
func searchForResults(query string) map[string]any {
|
||||
regexPattern := query
|
||||
if strings.Contains(query, "*") {
|
||||
regexPattern = strings.ReplaceAll(query, "*", ".*")
|
||||
}
|
||||
|
||||
for key, value := range searchResults {
|
||||
match, _ := regexp.MatchString(regexPattern, key)
|
||||
if match {
|
||||
return value.(map[string]any)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyLimitToResults(results map[string]any, limitNum int) map[string]any {
|
||||
originalBytes, err := json.Marshal(results)
|
||||
if err != nil {
|
||||
return results
|
||||
}
|
||||
var resultsCopy map[string]any
|
||||
if err := json.Unmarshal(originalBytes, &resultsCopy); err != nil {
|
||||
return results
|
||||
}
|
||||
|
||||
if limitNum > 0 {
|
||||
if resultsArray, ok := resultsCopy["results"].([]any); ok {
|
||||
actualLimit := limitNum
|
||||
if len(resultsArray) < limitNum {
|
||||
actualLimit = len(resultsArray)
|
||||
}
|
||||
resultsCopy["results"] = resultsArray[:actualLimit]
|
||||
resultsCopy["num_results"] = actualLimit
|
||||
}
|
||||
}
|
||||
return resultsCopy
|
||||
}
|
||||
|
||||
func handleV2(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v2/_catalog" {
|
||||
handleCatalog(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasSuffix(r.URL.Path, "/tags/list") {
|
||||
handleTagsList(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
}
|
||||
|
||||
func parseRepositoryPath(path string) (string, bool) {
|
||||
pathParts := strings.Split(strings.TrimPrefix(path, "/v2/"), "/")
|
||||
if len(pathParts) < 2 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if pathParts[len(pathParts)-1] == "list" && pathParts[len(pathParts)-2] == "tags" {
|
||||
repoName := strings.Join(pathParts[:len(pathParts)-2], "/")
|
||||
return repoName, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func handleTagsList(w http.ResponseWriter, r *http.Request) {
|
||||
repoName, isValidPath := parseRepositoryPath(r.URL.Path)
|
||||
if !isValidPath {
|
||||
http.Error(w, "Invalid tags list path", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
allTags, exists := mockRepoTags[repoName]
|
||||
if !exists {
|
||||
http.Error(w, fmt.Sprintf("repository %s not found", repoName), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
query := r.URL.Query()
|
||||
limit := -1
|
||||
last := query.Get("last")
|
||||
|
||||
if limitStr := query.Get("n"); limitStr != "" {
|
||||
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
|
||||
limit = l
|
||||
}
|
||||
}
|
||||
|
||||
paginatedTags := applyPagination(allTags, limit, last, repoName)
|
||||
|
||||
response := map[string]any{
|
||||
"name": repoName,
|
||||
"tags": paginatedTags,
|
||||
}
|
||||
writeJSONResponse(w, response)
|
||||
}
|
||||
|
||||
func applyPagination(allTags []string, limit int, last string, repoName string) []string {
|
||||
if repoName == "podman/stable" && limit == 100 && last == "v5.4" {
|
||||
return podmanStablePaginatedTags
|
||||
}
|
||||
|
||||
if limit <= 0 && last == "" {
|
||||
return allTags
|
||||
}
|
||||
|
||||
startIndex := 0
|
||||
|
||||
if last != "" {
|
||||
for i, tag := range allTags {
|
||||
if tag == last {
|
||||
startIndex = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
endIndex := startIndex + limit
|
||||
if endIndex > len(allTags) {
|
||||
endIndex = len(allTags)
|
||||
}
|
||||
return allTags[startIndex:endIndex]
|
||||
}
|
||||
|
||||
return allTags[startIndex:]
|
||||
}
|
||||
|
||||
func handleCatalog(w http.ResponseWriter, _ *http.Request) {
|
||||
repositories := make([]string, 0, len(mockRepoTags))
|
||||
for repoName := range mockRepoTags {
|
||||
repositories = append(repositories, repoName)
|
||||
}
|
||||
|
||||
response := map[string]any{
|
||||
"repositories": repositories,
|
||||
}
|
||||
writeJSONResponse(w, response)
|
||||
}
|
||||
|
||||
// CreateMockRegistryServer creates and starts a mock Docker registry server
|
||||
// Returns: server address, server instance, error channel, and logged requests slice
|
||||
func CreateMockRegistryServer() (string, *http.Server, chan error) {
|
||||
listener, err := net.Listen("tcp4", "127.0.0.1:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
serverAddr := listener.Addr().String()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/v1/search", func(w http.ResponseWriter, r *http.Request) {
|
||||
handleV1Search(w, r)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/v2/", func(w http.ResponseWriter, r *http.Request) {
|
||||
handleV2(w, r)
|
||||
})
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: mux,
|
||||
ErrorLog: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
serverErr := make(chan error, 1)
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
serverErr <- srv.Serve(listener)
|
||||
}()
|
||||
|
||||
Eventually(func() error {
|
||||
resp, err := http.Get("http://" + serverAddr + "/v2/")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("server not ready, status: %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}, "5s", "100ms").Should(Succeed())
|
||||
|
||||
return serverAddr, srv, serverErr
|
||||
}
|
||||
|
||||
func CloseMockRegistryServer(srv *http.Server, serverErr chan error) {
|
||||
srv.Close()
|
||||
Expect(<-serverErr).To(Equal(http.ErrServerClosed))
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
@@ -43,327 +44,274 @@ registries = ['{{.Host}}:{{.Port}}']
|
||||
registries = []`
|
||||
registryFileBadTmpl := template.Must(template.New("registryFileBad").Parse(badRegFileContents))
|
||||
|
||||
It("podman search", func() {
|
||||
search := podmanTest.Podman([]string{"search", "alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("alpine"))
|
||||
})
|
||||
|
||||
It("podman search single registry flag", func() {
|
||||
search := podmanTest.Podman([]string{"search", "quay.io/skopeo/stable:latest"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("quay.io/skopeo/stable"))
|
||||
})
|
||||
|
||||
It("podman search image with description", func() {
|
||||
search := podmanTest.Podman([]string{"search", "quay.io/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
output := string(search.Out.Contents())
|
||||
Expect(output).To(MatchRegexp(`(?m)NAME\s+DESCRIPTION$`))
|
||||
Expect(output).To(MatchRegexp(`(?m)quay.io/podman/stable\s+.*PODMAN logo`))
|
||||
})
|
||||
|
||||
It("podman search image with --compatible", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--compatible", "quay.io/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
output := string(search.Out.Contents())
|
||||
Expect(output).To(MatchRegexp(`(?m)NAME\s+DESCRIPTION\s+STARS\s+OFFICIAL\s+AUTOMATED$`))
|
||||
})
|
||||
|
||||
It("podman search format flag", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--format", "table {{.Index}} {{.Name}}", "testdigest_v2s2"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("quay.io/libpod/testdigest_v2s2"))
|
||||
})
|
||||
|
||||
It("podman search format json", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--format", "json", "testdigest_v2s1"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).To(BeValidJSON())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("quay.io/libpod/testdigest_v2s1"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("Test image used by buildah regression tests"))
|
||||
|
||||
// Test for https://github.com/containers/podman/issues/11894
|
||||
contents := make([]entities.ImageSearchReport, 0)
|
||||
err := json.Unmarshal(search.Out.Contents(), &contents)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(contents).ToNot(BeEmpty(), "No results from image search")
|
||||
for _, element := range contents {
|
||||
Expect(element.Description).ToNot(HaveSuffix("..."))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search format json list tags", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--list-tags", "--format", "json", ALPINE})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).To(BeValidJSON())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("quay.io/libpod/alpine"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("3.10.2"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("3.2"))
|
||||
})
|
||||
|
||||
// Test for https://github.com/containers/podman/issues/11894
|
||||
It("podman search no-trunc=false flag", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--no-trunc=false", "alpine", "--format={{.Description}}"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
|
||||
for _, line := range search.OutputToStringArray() {
|
||||
if len(line) > 44 {
|
||||
Expect(line).To(HaveSuffix("..."), line+" should have been truncated")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search limit flag", func() {
|
||||
search := podmanTest.Podman([]string{"search", "quay.io/alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 10))
|
||||
|
||||
search = podmanTest.Podman([]string{"search", "--limit", "3", "quay.io/alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(4))
|
||||
|
||||
search = podmanTest.Podman([]string{"search", "--limit", "30", "quay.io/alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(31))
|
||||
})
|
||||
|
||||
It("podman search with filter stars", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--filter", "stars=10", "--format", "{{.Stars}}", "alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(strconv.Atoi(output[i])).To(BeNumerically(">=", 10))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search with filter is-official", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--filter", "is-official", "--format", "{{.Official}}", "alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(output[i]).To(Equal("[OK]"))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search with filter is-automated", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--filter", "is-automated=false", "--format", "{{.Automated}}", "alpine"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(output[i]).To(Equal(""))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search format list tags with custom", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--list-tags", "--format", "{{.Name}}", "--limit", "1", ALPINE})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).To(Equal("quay.io/libpod/alpine"))
|
||||
})
|
||||
|
||||
It("podman search attempts HTTP if tls-verify flag is set false", func() {
|
||||
mockFakeRegistryServerAsContainer := func(name string) endpoint {
|
||||
if podmanTest.Host.Arch == "ppc64le" {
|
||||
Skip("No registry image for ppc64le")
|
||||
}
|
||||
port := GetPort()
|
||||
fakereg := podmanTest.Podman([]string{"run", "-d", "--name", "registry",
|
||||
fakereg := podmanTest.Podman([]string{"run", "-d", "--name", name,
|
||||
"-p", fmt.Sprintf("%d:5000", port),
|
||||
REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
|
||||
fakereg.WaitWithDefaultTimeout()
|
||||
Expect(fakereg).Should(ExitCleanly())
|
||||
|
||||
if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
|
||||
if !WaitContainerReady(podmanTest, name, "listening on", 20, 1) {
|
||||
Fail("Cannot start docker registry on port %s", port)
|
||||
}
|
||||
ep := endpoint{Port: strconv.Itoa(port), Host: "localhost"}
|
||||
search := podmanTest.Podman([]string{"search",
|
||||
fmt.Sprintf("%s/fake/image:andtag", ep.Address()), "--tls-verify=false"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
return ep
|
||||
}
|
||||
|
||||
// if this test succeeded, there will be no output (there is no entry named fake/image:andtag in an empty registry)
|
||||
// and the exit code will be 0
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("podman search in local registry", func() {
|
||||
if podmanTest.Host.Arch == "ppc64le" {
|
||||
Skip("No registry image for ppc64le")
|
||||
}
|
||||
port := GetPort()
|
||||
registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry3",
|
||||
"-p", fmt.Sprintf("%d:5000", port), REGISTRY_IMAGE,
|
||||
"/entrypoint.sh", "/etc/docker/registry/config.yml"})
|
||||
registry.WaitWithDefaultTimeout()
|
||||
Expect(registry).Should(ExitCleanly())
|
||||
|
||||
if !WaitContainerReady(podmanTest, "registry3", "listening on", 20, 1) {
|
||||
Fail("Cannot start docker registry on port %s", port)
|
||||
}
|
||||
ep := endpoint{Port: strconv.Itoa(port), Host: "localhost"}
|
||||
pushAlpineImageIntoMockRegistry := func(ep endpoint) string {
|
||||
err = podmanTest.RestoreArtifact(ALPINE)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
image := fmt.Sprintf("%s/my-alpine", ep.Address())
|
||||
push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, image})
|
||||
push.WaitWithDefaultTimeout()
|
||||
Expect(push).Should(ExitCleanly())
|
||||
search := podmanTest.Podman([]string{"search", image, "--tls-verify=false"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
podmanTest.PodmanExitCleanly("push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, image)
|
||||
return image
|
||||
}
|
||||
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).ShouldNot(BeEmpty())
|
||||
Context("podman search with mock registry", func() {
|
||||
var registryAddress string
|
||||
var srv *http.Server
|
||||
var serverErr chan error
|
||||
|
||||
BeforeEach(func() {
|
||||
registryAddress, srv, serverErr = CreateMockRegistryServer()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
CloseMockRegistryServer(srv, serverErr)
|
||||
})
|
||||
|
||||
It("podman search", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--tls-verify=false", registryAddress+"/alpine")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("alpine"))
|
||||
})
|
||||
|
||||
It("podman search single registry flag", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--tls-verify=false", registryAddress+"/skopeo/stable:latest")
|
||||
Expect(search.OutputToString()).To(ContainSubstring(registryAddress + "/skopeo/stable"))
|
||||
})
|
||||
|
||||
It("podman search image with description", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--tls-verify=false", registryAddress+"/podman/stable")
|
||||
output := string(search.Out.Contents())
|
||||
Expect(output).To(MatchRegexp(`(?m)NAME\s+DESCRIPTION$`))
|
||||
Expect(output).To(MatchRegexp(`(?m)/podman/stable\s+.*Podman Image`))
|
||||
})
|
||||
|
||||
It("podman search image with --compatible", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--compatible", "--tls-verify=false", registryAddress+"/podman/stable")
|
||||
output := string(search.Out.Contents())
|
||||
Expect(output).To(MatchRegexp(`(?m)NAME\s+DESCRIPTION\s+STARS\s+OFFICIAL\s+AUTOMATED$`))
|
||||
})
|
||||
|
||||
It("podman search format flag", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--format", "table {{.Index}} {{.Name}}", "--tls-verify=false", registryAddress+"/testdigest_v2s2")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
Expect(search.OutputToString()).To(ContainSubstring(registryAddress + "/libpod/testdigest_v2s2"))
|
||||
})
|
||||
|
||||
It("podman search format json", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--format", "json", "--tls-verify=false", registryAddress+"/testdigest_v2s1")
|
||||
Expect(search.OutputToString()).To(BeValidJSON())
|
||||
Expect(search.OutputToString()).To(ContainSubstring(registryAddress + "/libpod/testdigest_v2s1"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("Test image used by buildah regression tests"))
|
||||
|
||||
// Test for https://github.com/containers/podman/issues/11894
|
||||
contents := make([]entities.ImageSearchReport, 0)
|
||||
err := json.Unmarshal(search.Out.Contents(), &contents)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(contents).ToNot(BeEmpty(), "No results from image search")
|
||||
for _, element := range contents {
|
||||
Expect(element.Description).ToNot(HaveSuffix("..."))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search format json list tags", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--list-tags", "--format", "json", "--tls-verify=false", registryAddress+"/libpod/alpine:latest")
|
||||
Expect(search.OutputToString()).To(BeValidJSON())
|
||||
Expect(search.OutputToString()).To(ContainSubstring(registryAddress + "/libpod/alpine"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("3.10.2"))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("3.2"))
|
||||
})
|
||||
|
||||
// Test for https://github.com/containers/podman/issues/11894
|
||||
It("podman search no-trunc=false flag", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--no-trunc=false", "--tls-verify=false", registryAddress+"/alpine", "--format={{.Description}}")
|
||||
|
||||
for _, line := range search.OutputToStringArray() {
|
||||
if len(line) > 44 {
|
||||
Expect(line).To(HaveSuffix("..."), line+" should have been truncated")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search limit flag", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--tls-verify=false", registryAddress+"/alpine")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 10))
|
||||
|
||||
search = podmanTest.PodmanExitCleanly("search", "--limit", "3", "--tls-verify=false", registryAddress+"/alpine")
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(4))
|
||||
|
||||
search = podmanTest.PodmanExitCleanly("search", "--limit", "10", "--tls-verify=false", registryAddress+"/alpine")
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(11))
|
||||
})
|
||||
|
||||
It("podman search with filter stars", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--filter", "stars=10", "--format", "{{.Stars}}", "--tls-verify=false", registryAddress+"/alpine")
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(strconv.Atoi(output[i])).To(BeNumerically(">=", 10))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search with filter is-official", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--filter", "is-official", "--format", "{{.Official}}", "--tls-verify=false", registryAddress+"/alpine")
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(output[i]).To(Equal("[OK]"))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search with filter is-automated", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--filter", "is-automated=false", "--format", "{{.Automated}}", "--tls-verify=false", registryAddress+"/alpine")
|
||||
output := search.OutputToStringArray()
|
||||
for i := range output {
|
||||
Expect(output[i]).To(Equal(""))
|
||||
}
|
||||
})
|
||||
|
||||
It("podman search format list tags with custom", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--list-tags", "--format", "{{.Name}}", "--limit", "1", "--tls-verify=false", registryAddress+"/libpod/alpine")
|
||||
Expect(search.OutputToString()).To(Equal(registryAddress + "/libpod/alpine"))
|
||||
})
|
||||
|
||||
It("podman search with wildcards", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--tls-verify=false", registryAddress+"/*alpine*")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
Expect(search.OutputToString()).To(ContainSubstring("alpine"))
|
||||
})
|
||||
|
||||
It("podman search repository tags", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--list-tags", "--limit", "30", "--tls-verify=false", registryAddress+"/podman/stable")
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(31))
|
||||
|
||||
search = podmanTest.PodmanExitCleanly("search", "--list-tags", "--tls-verify=false", registryAddress+"/podman/stable")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 2))
|
||||
|
||||
search = podmanTest.Podman([]string{"search", "--filter=is-official", "--list-tags", "--tls-verify=false", registryAddress + "/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, "filters are not applicable to list tags result"))
|
||||
|
||||
// With trailing slash
|
||||
search = podmanTest.Podman([]string{"search", "--list-tags", "--tls-verify=false", registryAddress + "/podman/"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, `reference "podman/" must be a docker reference`))
|
||||
Expect(search.OutputToStringArray()).To(BeEmpty())
|
||||
|
||||
// No trailing slash
|
||||
search = podmanTest.Podman([]string{"search", "--list-tags", "--tls-verify=false", registryAddress + "/podman"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, "getting repository tags: fetching tags list: StatusCode: 404"))
|
||||
Expect(search.OutputToStringArray()).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("podman search with limit over 100", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", "--limit", "100", "--tls-verify=false", registryAddress+"/podman")
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically("<=", 101))
|
||||
})
|
||||
|
||||
// podman search v2 registry with empty query
|
||||
searchEmpty := podmanTest.Podman([]string{"search", fmt.Sprintf("%s/", ep.Address()), "--tls-verify=false"})
|
||||
searchEmpty.WaitWithDefaultTimeout()
|
||||
Expect(searchEmpty).Should(ExitCleanly())
|
||||
Expect(searchEmpty.OutputToStringArray()).ToNot(BeEmpty())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("my-alpine"))
|
||||
})
|
||||
|
||||
It("podman search attempts HTTP if registry is in registries.insecure and force secure is false", func() {
|
||||
if podmanTest.Host.Arch == "ppc64le" {
|
||||
Skip("No registry image for ppc64le")
|
||||
Context("podman search with container-based registries", func() {
|
||||
var ep endpoint
|
||||
var image string
|
||||
var registryName string
|
||||
var port int64
|
||||
|
||||
setupRegistryConfig := func(ep endpoint, registryName string, template *template.Template) {
|
||||
var buffer bytes.Buffer
|
||||
err := template.Execute(&buffer, ep)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
|
||||
err = os.WriteFile(fmt.Sprintf("%s/%s.conf", tempdir, registryName), buffer.Bytes(), 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
port := GetPort()
|
||||
ep := endpoint{Port: strconv.Itoa(port), Host: "localhost"}
|
||||
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
|
||||
"--name", "registry4", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
|
||||
registry.WaitWithDefaultTimeout()
|
||||
Expect(registry).Should(ExitCleanly())
|
||||
BeforeEach(func() {
|
||||
registryName = fmt.Sprintf("registry%d", GinkgoRandomSeed())
|
||||
ep = mockFakeRegistryServerAsContainer(registryName)
|
||||
image = pushAlpineImageIntoMockRegistry(ep)
|
||||
|
||||
if !WaitContainerReady(podmanTest, "registry4", "listening on", 20, 1) {
|
||||
Fail("unable to start registry on port %s", port)
|
||||
}
|
||||
port, err = strconv.ParseInt(ep.Port, 10, 64)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
err = podmanTest.RestoreArtifact(ALPINE)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
image := fmt.Sprintf("%s/my-alpine", ep.Address())
|
||||
push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, image})
|
||||
push.WaitWithDefaultTimeout()
|
||||
Expect(push).Should(ExitCleanly())
|
||||
AfterEach(func() {
|
||||
resetRegistriesConfigEnv()
|
||||
podmanTest.PodmanExitCleanly("rm", "-f", registryName)
|
||||
})
|
||||
|
||||
// registries.conf set up
|
||||
var buffer bytes.Buffer
|
||||
err = registryFileTmpl.Execute(&buffer, ep)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
|
||||
err = os.WriteFile(fmt.Sprintf("%s/registry4.conf", tempdir), buffer.Bytes(), 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
defer podmanTest.RestartRemoteService()
|
||||
}
|
||||
It("podman search attempts HTTP if tls-verify flag is set false", func() {
|
||||
// if this test succeeded, there will be no output (there is no entry named fake/image:andtag in an empty registry)
|
||||
// and the exit code will be 0
|
||||
search := podmanTest.PodmanExitCleanly("search", fmt.Sprintf("%s/fake/image:andtag", ep.Address()), "--tls-verify=false")
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
})
|
||||
|
||||
search := podmanTest.Podman([]string{"search", image})
|
||||
search.WaitWithDefaultTimeout()
|
||||
It("podman search in local registry", func() {
|
||||
search := podmanTest.PodmanExitCleanly("search", image, "--tls-verify=false")
|
||||
Expect(search.OutputToString()).ShouldNot(BeEmpty())
|
||||
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("my-alpine"))
|
||||
// podman search v2 registry with empty query
|
||||
searchEmpty := podmanTest.PodmanExitCleanly("search", fmt.Sprintf("%s/", ep.Address()), "--tls-verify=false")
|
||||
Expect(searchEmpty.OutputToStringArray()).ToNot(BeEmpty())
|
||||
Expect(search.OutputToString()).To(ContainSubstring("my-alpine"))
|
||||
})
|
||||
|
||||
// cleanup
|
||||
resetRegistriesConfigEnv()
|
||||
})
|
||||
It("podman search attempts HTTP if registry is in registries.insecure and force secure is false", func() {
|
||||
// registries.conf set up
|
||||
setupRegistryConfig(ep, registryName, registryFileTmpl)
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
defer podmanTest.RestartRemoteService()
|
||||
}
|
||||
|
||||
It("podman search doesn't attempt HTTP if force secure is true", func() {
|
||||
if podmanTest.Host.Arch == "ppc64le" {
|
||||
Skip("No registry image for ppc64le")
|
||||
}
|
||||
port := GetPort()
|
||||
ep := endpoint{Port: strconv.Itoa(port), Host: "localhost"}
|
||||
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
|
||||
"--name", "registry5", REGISTRY_IMAGE})
|
||||
registry.WaitWithDefaultTimeout()
|
||||
Expect(registry).Should(ExitCleanly())
|
||||
search := podmanTest.PodmanExitCleanly("search", image)
|
||||
Expect(search.OutputToString()).To(ContainSubstring("my-alpine"))
|
||||
})
|
||||
|
||||
if !WaitContainerReady(podmanTest, "registry5", "listening on", 20, 1) {
|
||||
Fail("Cannot start docker registry on port %s", port)
|
||||
}
|
||||
It("podman search doesn't attempt HTTP if force secure is true", func() {
|
||||
setupRegistryConfig(ep, registryName, registryFileTmpl)
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
defer podmanTest.RestartRemoteService()
|
||||
}
|
||||
|
||||
err = podmanTest.RestoreArtifact(ALPINE)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
image := fmt.Sprintf("%s/my-alpine", ep.Address())
|
||||
push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, image})
|
||||
push.WaitWithDefaultTimeout()
|
||||
Expect(push).Should(ExitCleanly())
|
||||
search := podmanTest.Podman([]string{"search", image, "--tls-verify=true"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err = registryFileTmpl.Execute(&buffer, ep)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
|
||||
err = os.WriteFile(fmt.Sprintf("%s/registry5.conf", tempdir), buffer.Bytes(), 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(search).Should(ExitWithError(125, fmt.Sprintf(`couldn't search registry "localhost:%d": pinging container registry localhost:%d: Get "https://localhost:%d/v2/": http: server gave HTTP response to HTTPS client`, port, port, port)))
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
})
|
||||
|
||||
search := podmanTest.Podman([]string{"search", image, "--tls-verify=true"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
It("podman search doesn't attempt HTTP if registry is not listed as insecure", func() {
|
||||
setupRegistryConfig(ep, registryName, registryFileBadTmpl)
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
defer podmanTest.RestartRemoteService()
|
||||
}
|
||||
|
||||
Expect(search).Should(ExitWithError(125, fmt.Sprintf(`couldn't search registry "localhost:%d": pinging container registry localhost:%d: Get "https://localhost:%d/v2/": http: server gave HTTP response to HTTPS client`, port, port, port)))
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
search := podmanTest.Podman([]string{"search", image})
|
||||
search.WaitWithDefaultTimeout()
|
||||
|
||||
// cleanup
|
||||
resetRegistriesConfigEnv()
|
||||
})
|
||||
|
||||
It("podman search doesn't attempt HTTP if registry is not listed as insecure", func() {
|
||||
if podmanTest.Host.Arch == "ppc64le" {
|
||||
Skip("No registry image for ppc64le")
|
||||
}
|
||||
port := GetPort()
|
||||
ep := endpoint{Port: strconv.Itoa(port), Host: "localhost"}
|
||||
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
|
||||
"--name", "registry6", REGISTRY_IMAGE})
|
||||
registry.WaitWithDefaultTimeout()
|
||||
Expect(registry).Should(ExitCleanly())
|
||||
|
||||
if !WaitContainerReady(podmanTest, "registry6", "listening on", 20, 1) {
|
||||
Fail("Cannot start docker registry on port %s", port)
|
||||
}
|
||||
|
||||
err = podmanTest.RestoreArtifact(ALPINE)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
image := fmt.Sprintf("%s/my-alpine", ep.Address())
|
||||
push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, image})
|
||||
push.WaitWithDefaultTimeout()
|
||||
Expect(push).Should(ExitCleanly())
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err = registryFileBadTmpl.Execute(&buffer, ep)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
|
||||
err = os.WriteFile(fmt.Sprintf("%s/registry6.conf", tempdir), buffer.Bytes(), 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
defer podmanTest.RestartRemoteService()
|
||||
}
|
||||
|
||||
search := podmanTest.Podman([]string{"search", image})
|
||||
search.WaitWithDefaultTimeout()
|
||||
|
||||
Expect(search).Should(ExitWithError(125, fmt.Sprintf(`couldn't search registry "localhost:%d": pinging container registry localhost:%d: Get "https://localhost:%d/v2/": http: server gave HTTP response to HTTPS client`, port, port, port)))
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
|
||||
// cleanup
|
||||
resetRegistriesConfigEnv()
|
||||
Expect(search).Should(ExitWithError(125, fmt.Sprintf(`couldn't search registry "localhost:%d": pinging container registry localhost:%d: Get "https://localhost:%d/v2/": http: server gave HTTP response to HTTPS client`, port, port, port)))
|
||||
Expect(search.OutputToString()).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
// search should fail with nonexistent authfile
|
||||
@@ -372,47 +320,4 @@ registries = []`
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, "credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory"))
|
||||
})
|
||||
|
||||
// Registry is unreliable (#18484), this is another super-common flake
|
||||
It("podman search with wildcards", FlakeAttempts(3), func() {
|
||||
search := podmanTest.Podman([]string{"search", "registry.access.redhat.com/*openshift*"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 1))
|
||||
})
|
||||
|
||||
It("podman search repository tags", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--list-tags", "--limit", "30", "quay.io/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(search.OutputToStringArray()).To(HaveLen(31))
|
||||
|
||||
search = podmanTest.Podman([]string{"search", "--list-tags", "quay.io/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically(">", 2))
|
||||
|
||||
search = podmanTest.Podman([]string{"search", "--filter=is-official", "--list-tags", "quay.io/podman/stable"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, "filters are not applicable to list tags result"))
|
||||
|
||||
// With trailing slash
|
||||
search = podmanTest.Podman([]string{"search", "--list-tags", "quay.io/podman/"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, `reference "podman/" must be a docker reference`))
|
||||
Expect(search.OutputToStringArray()).To(BeEmpty())
|
||||
|
||||
// No trailing slash
|
||||
search = podmanTest.Podman([]string{"search", "--list-tags", "quay.io/podman"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).To(ExitWithError(125, "getting repository tags: fetching tags list: StatusCode: 404"))
|
||||
Expect(search.OutputToStringArray()).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("podman search with limit over 100", func() {
|
||||
search := podmanTest.Podman([]string{"search", "--limit", "100", "quay.io/podman"})
|
||||
search.WaitWithDefaultTimeout()
|
||||
Expect(search).Should(ExitCleanly())
|
||||
Expect(len(search.OutputToStringArray())).To(BeNumerically("<=", 101))
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user