zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/cli/client/search_functions_internal_test.go (about)

     1  //go:build search
     2  // +build search
     3  
     4  //
     5  //nolint:dupl
     6  package client
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"io"
    12  	"os"
    13  	"regexp"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  
    19  	godigest "github.com/opencontainers/go-digest"
    20  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
    21  	. "github.com/smartystreets/goconvey/convey"
    22  	"github.com/spf13/cobra"
    23  
    24  	zerr "zotregistry.io/zot/errors"
    25  	"zotregistry.io/zot/pkg/common"
    26  )
    27  
    28  func TestSearchAllImages(t *testing.T) {
    29  	Convey("SearchAllImages", t, func() {
    30  		buff := bytes.NewBufferString("")
    31  		searchConfig := getMockSearchConfig(buff, mockService{
    32  			getAllImagesFn: func(ctx context.Context, config SearchConfig, username, password string,
    33  				channel chan stringResult, wtgrp *sync.WaitGroup,
    34  			) {
    35  				str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
    36  
    37  				channel <- stringResult{StrValue: str, Err: err}
    38  			},
    39  		})
    40  
    41  		err := SearchAllImages(searchConfig)
    42  		So(err, ShouldBeNil)
    43  		space := regexp.MustCompile(`\s+`)
    44  		str := space.ReplaceAllString(buff.String(), " ")
    45  		actual := strings.TrimSpace(str)
    46  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
    47  	})
    48  }
    49  
    50  func TestSearchAllImagesGQL(t *testing.T) {
    51  	Convey("SearchAllImagesGQL", t, func() {
    52  		buff := bytes.NewBufferString("")
    53  		searchConfig := getMockSearchConfig(buff, mockService{
    54  			getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
    55  			) (*common.ImageListResponse, error) {
    56  				return &common.ImageListResponse{ImageList: common.ImageList{
    57  					PaginatedImagesResult: common.PaginatedImagesResult{
    58  						Results: []common.ImageSummary{getMockImageSummary()},
    59  					},
    60  				}}, nil
    61  			},
    62  		})
    63  
    64  		err := SearchAllImagesGQL(searchConfig)
    65  		So(err, ShouldBeNil)
    66  		space := regexp.MustCompile(`\s+`)
    67  		str := space.ReplaceAllString(buff.String(), " ")
    68  		actual := strings.TrimSpace(str)
    69  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
    70  	})
    71  
    72  	Convey("SearchAllImagesGQL error", t, func() {
    73  		buff := bytes.NewBufferString("")
    74  		searchConfig := getMockSearchConfig(buff, mockService{
    75  			getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
    76  			) (*common.ImageListResponse, error) {
    77  				return &common.ImageListResponse{ImageList: common.ImageList{
    78  					PaginatedImagesResult: common.PaginatedImagesResult{
    79  						Results: []common.ImageSummary{getMockImageSummary()},
    80  					},
    81  				}}, zerr.ErrInjected
    82  			},
    83  		})
    84  
    85  		err := SearchAllImagesGQL(searchConfig)
    86  		So(err, ShouldNotBeNil)
    87  	})
    88  }
    89  
    90  func TestSearchImageByName(t *testing.T) {
    91  	Convey("SearchImageByName", t, func() {
    92  		buff := bytes.NewBufferString("")
    93  		searchConfig := getMockSearchConfig(buff, mockService{
    94  			getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
    95  				channel chan stringResult, wtgrp *sync.WaitGroup,
    96  			) {
    97  				str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
    98  
    99  				channel <- stringResult{StrValue: str, Err: err}
   100  			},
   101  		})
   102  
   103  		err := SearchImageByName(searchConfig, "repo")
   104  		So(err, ShouldBeNil)
   105  		space := regexp.MustCompile(`\s+`)
   106  		str := space.ReplaceAllString(buff.String(), " ")
   107  		actual := strings.TrimSpace(str)
   108  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   109  	})
   110  
   111  	Convey("SearchImageByName error", t, func() {
   112  		buff := bytes.NewBufferString("")
   113  		searchConfig := getMockSearchConfig(buff, mockService{
   114  			getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
   115  				channel chan stringResult, wtgrp *sync.WaitGroup,
   116  			) {
   117  				channel <- stringResult{StrValue: "", Err: zerr.ErrInjected}
   118  			},
   119  		})
   120  
   121  		err := SearchImageByName(searchConfig, "repo")
   122  		So(err, ShouldNotBeNil)
   123  	})
   124  }
   125  
   126  func TestSearchImageByNameGQL(t *testing.T) {
   127  	Convey("SearchImageByNameGQL", t, func() {
   128  		buff := bytes.NewBufferString("")
   129  		searchConfig := getMockSearchConfig(buff, mockService{
   130  			getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
   131  			) (*common.ImageListResponse, error) {
   132  				return &common.ImageListResponse{ImageList: common.ImageList{
   133  					PaginatedImagesResult: common.PaginatedImagesResult{
   134  						Results: []common.ImageSummary{getMockImageSummary()},
   135  					},
   136  				}}, nil
   137  			},
   138  		})
   139  
   140  		err := SearchImageByNameGQL(searchConfig, "repo")
   141  		So(err, ShouldBeNil)
   142  		space := regexp.MustCompile(`\s+`)
   143  		str := space.ReplaceAllString(buff.String(), " ")
   144  		actual := strings.TrimSpace(str)
   145  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   146  	})
   147  
   148  	Convey("SearchImageByNameGQL error", t, func() {
   149  		buff := bytes.NewBufferString("")
   150  		searchConfig := getMockSearchConfig(buff, mockService{
   151  			getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
   152  			) (*common.ImageListResponse, error) {
   153  				return &common.ImageListResponse{ImageList: common.ImageList{
   154  					PaginatedImagesResult: common.PaginatedImagesResult{
   155  						Results: []common.ImageSummary{getMockImageSummary()},
   156  					},
   157  				}}, zerr.ErrInjected
   158  			},
   159  		})
   160  
   161  		err := SearchImageByNameGQL(searchConfig, "repo")
   162  		So(err, ShouldNotBeNil)
   163  	})
   164  }
   165  
   166  func TestSearchImagesByDigest(t *testing.T) {
   167  	Convey("SearchImagesByDigest", t, func() {
   168  		buff := bytes.NewBufferString("")
   169  		searchConfig := getMockSearchConfig(buff, mockService{
   170  			getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
   171  				rch chan stringResult, wtgrp *sync.WaitGroup,
   172  			) {
   173  				str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
   174  
   175  				rch <- stringResult{StrValue: str, Err: err}
   176  			},
   177  		})
   178  
   179  		err := SearchImagesByDigest(searchConfig, godigest.FromString("str").String())
   180  		So(err, ShouldBeNil)
   181  		space := regexp.MustCompile(`\s+`)
   182  		str := space.ReplaceAllString(buff.String(), " ")
   183  		actual := strings.TrimSpace(str)
   184  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   185  	})
   186  
   187  	Convey("SearchImagesByDigest error", t, func() {
   188  		buff := bytes.NewBufferString("")
   189  		searchConfig := getMockSearchConfig(buff, mockService{
   190  			getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
   191  				rch chan stringResult, wtgrp *sync.WaitGroup,
   192  			) {
   193  				rch <- stringResult{StrValue: "", Err: zerr.ErrInjected}
   194  			},
   195  		})
   196  
   197  		err := SearchImagesByDigest(searchConfig, godigest.FromString("str").String())
   198  		So(err, ShouldNotBeNil)
   199  	})
   200  }
   201  
   202  func TestSearchDerivedImageListGQL(t *testing.T) {
   203  	Convey("SearchDerivedImageListGQL", t, func() {
   204  		buff := bytes.NewBufferString("")
   205  		searchConfig := getMockSearchConfig(buff, mockService{
   206  			getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   207  				derivedImage string) (*common.DerivedImageListResponse, error,
   208  			) {
   209  				return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
   210  					PaginatedImagesResult: common.PaginatedImagesResult{
   211  						Results: []common.ImageSummary{
   212  							getMockImageSummary(),
   213  						},
   214  					},
   215  				}}, nil
   216  			},
   217  		})
   218  
   219  		err := SearchDerivedImageListGQL(searchConfig, "repo:tag")
   220  		So(err, ShouldBeNil)
   221  		space := regexp.MustCompile(`\s+`)
   222  		str := space.ReplaceAllString(buff.String(), " ")
   223  		actual := strings.TrimSpace(str)
   224  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   225  	})
   226  
   227  	Convey("SearchDerivedImageListGQL error", t, func() {
   228  		buff := bytes.NewBufferString("")
   229  		searchConfig := getMockSearchConfig(buff, mockService{
   230  			getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   231  				derivedImage string) (*common.DerivedImageListResponse, error,
   232  			) {
   233  				return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
   234  					PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{}},
   235  				}}, zerr.ErrInjected
   236  			},
   237  		})
   238  
   239  		err := SearchDerivedImageListGQL(searchConfig, "repo:tag")
   240  		So(err, ShouldNotBeNil)
   241  	})
   242  }
   243  
   244  func TestSearchBaseImageListGQL(t *testing.T) {
   245  	Convey("SearchBaseImageListGQL", t, func() {
   246  		buff := bytes.NewBufferString("")
   247  		searchConfig := getMockSearchConfig(buff, mockService{
   248  			getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   249  				derivedImage string) (*common.BaseImageListResponse, error,
   250  			) {
   251  				return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
   252  					PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{
   253  						getMockImageSummary(),
   254  					}},
   255  				}}, nil
   256  			},
   257  		})
   258  
   259  		err := SearchBaseImageListGQL(searchConfig, "repo:tag")
   260  		So(err, ShouldBeNil)
   261  		space := regexp.MustCompile(`\s+`)
   262  		str := space.ReplaceAllString(buff.String(), " ")
   263  		actual := strings.TrimSpace(str)
   264  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   265  	})
   266  
   267  	Convey("SearchBaseImageListGQL error", t, func() {
   268  		buff := bytes.NewBufferString("")
   269  		searchConfig := getMockSearchConfig(buff, mockService{
   270  			getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   271  				derivedImage string) (*common.BaseImageListResponse, error,
   272  			) {
   273  				return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
   274  					PaginatedImagesResult: common.PaginatedImagesResult{Results: []common.ImageSummary{}},
   275  				}}, zerr.ErrInjected
   276  			},
   277  		})
   278  
   279  		err := SearchBaseImageListGQL(searchConfig, "repo:tag")
   280  		So(err, ShouldNotBeNil)
   281  	})
   282  }
   283  
   284  func TestSearchImagesForDigestGQL(t *testing.T) {
   285  	Convey("SearchImagesForDigestGQL", t, func() {
   286  		buff := bytes.NewBufferString("")
   287  		searchConfig := getMockSearchConfig(buff, mockService{
   288  			getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
   289  				password string, digest string) (*common.ImagesForDigest, error,
   290  			) {
   291  				return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
   292  					PaginatedImagesResult: common.PaginatedImagesResult{
   293  						Results: []common.ImageSummary{getMockImageSummary()},
   294  					},
   295  				}}, nil
   296  			},
   297  		})
   298  
   299  		err := SearchImagesForDigestGQL(searchConfig, "digest")
   300  		So(err, ShouldBeNil)
   301  		space := regexp.MustCompile(`\s+`)
   302  		str := space.ReplaceAllString(buff.String(), " ")
   303  		actual := strings.TrimSpace(str)
   304  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   305  	})
   306  
   307  	Convey("SearchImagesForDigestGQL error", t, func() {
   308  		buff := bytes.NewBufferString("")
   309  		searchConfig := getMockSearchConfig(buff, mockService{
   310  			getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
   311  				password string, digest string) (*common.ImagesForDigest, error,
   312  			) {
   313  				return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
   314  					PaginatedImagesResult: common.PaginatedImagesResult{},
   315  				}}, zerr.ErrInjected
   316  			},
   317  		})
   318  
   319  		err := SearchImagesForDigestGQL(searchConfig, "digest")
   320  		So(err, ShouldNotBeNil)
   321  	})
   322  }
   323  
   324  func TestSearchCVEForImageGQL(t *testing.T) {
   325  	Convey("SearchCVEForImageGQL", t, func() {
   326  		buff := bytes.NewBufferString("")
   327  		searchConfig := getMockSearchConfig(buff, mockService{
   328  			getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   329  				imageName string, searchedCVE string) (*cveResult, error,
   330  			) {
   331  				return &cveResult{
   332  					Data: cveData{
   333  						CVEListForImage: cveListForImage{
   334  							CVEList: []cve{
   335  								{
   336  									ID:          "dummyCVEID",
   337  									Description: "Description of the CVE",
   338  									Title:       "Title of that CVE",
   339  									Severity:    "HIGH",
   340  									PackageList: []packageList{
   341  										{
   342  											Name:             "packagename",
   343  											FixedVersion:     "fixedver",
   344  											InstalledVersion: "installedver",
   345  										},
   346  									},
   347  								},
   348  							},
   349  						},
   350  					},
   351  				}, nil
   352  			},
   353  		})
   354  
   355  		err := SearchCVEForImageGQL(searchConfig, "repo-test", "dummyCVEID")
   356  		So(err, ShouldBeNil)
   357  		space := regexp.MustCompile(`\s+`)
   358  		str := space.ReplaceAllString(buff.String(), " ")
   359  		actual := strings.TrimSpace(str)
   360  		So(actual, ShouldContainSubstring, "dummyCVEID HIGH Title of that CVE")
   361  	})
   362  
   363  	Convey("SearchCVEForImageGQL", t, func() {
   364  		buff := bytes.NewBufferString("")
   365  		searchConfig := getMockSearchConfig(buff, mockService{
   366  			getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
   367  				imageName string, searchedCVE string) (*cveResult, error,
   368  			) {
   369  				return &cveResult{}, zerr.ErrInjected
   370  			},
   371  		})
   372  
   373  		err := SearchCVEForImageGQL(searchConfig, "repo-test", "dummyCVEID")
   374  		So(err, ShouldNotBeNil)
   375  	})
   376  }
   377  
   378  func TestSearchImagesByCVEIDGQL(t *testing.T) {
   379  	Convey("SearchImagesByCVEIDGQL", t, func() {
   380  		buff := bytes.NewBufferString("")
   381  		searchConfig := getMockSearchConfig(buff, mockService{
   382  			getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   383  				imageName, cveID string) (*common.ImagesForCve, error,
   384  			) {
   385  				return &common.ImagesForCve{
   386  					ImagesForCVEList: common.ImagesForCVEList{
   387  						PaginatedImagesResult: common.PaginatedImagesResult{
   388  							Results: []common.ImageSummary{
   389  								getMockImageSummary(),
   390  							},
   391  						},
   392  					},
   393  				}, nil
   394  			},
   395  		})
   396  
   397  		err := SearchImagesByCVEIDGQL(searchConfig, "repo", "CVE-12345")
   398  		So(err, ShouldBeNil)
   399  		space := regexp.MustCompile(`\s+`)
   400  		str := space.ReplaceAllString(buff.String(), " ")
   401  		actual := strings.TrimSpace(str)
   402  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   403  	})
   404  
   405  	Convey("SearchImagesByCVEIDGQL error", t, func() {
   406  		buff := bytes.NewBufferString("")
   407  		searchConfig := getMockSearchConfig(buff, mockService{
   408  			getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   409  				imageName, cveID string) (*common.ImagesForCve, error,
   410  			) {
   411  				return &common.ImagesForCve{
   412  					ImagesForCVEList: common.ImagesForCVEList{
   413  						PaginatedImagesResult: common.PaginatedImagesResult{},
   414  					},
   415  				}, zerr.ErrInjected
   416  			},
   417  		})
   418  
   419  		err := SearchImagesByCVEIDGQL(searchConfig, "repo", "CVE-12345")
   420  		So(err, ShouldNotBeNil)
   421  	})
   422  }
   423  
   424  func TestSearchFixedTagsGQL(t *testing.T) {
   425  	Convey("SearchFixedTagsGQL", t, func() {
   426  		buff := bytes.NewBufferString("")
   427  		searchConfig := getMockSearchConfig(buff, mockService{
   428  			getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   429  				imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
   430  			) {
   431  				return &common.ImageListWithCVEFixedResponse{
   432  					ImageListWithCVEFixed: common.ImageListWithCVEFixed{
   433  						PaginatedImagesResult: common.PaginatedImagesResult{
   434  							Results: []common.ImageSummary{getMockImageSummary()},
   435  						},
   436  					},
   437  				}, nil
   438  			},
   439  		})
   440  
   441  		err := SearchFixedTagsGQL(searchConfig, "repo", "CVE-12345")
   442  		So(err, ShouldBeNil)
   443  		space := regexp.MustCompile(`\s+`)
   444  		str := space.ReplaceAllString(buff.String(), " ")
   445  		actual := strings.TrimSpace(str)
   446  		So(actual, ShouldContainSubstring, "repo tag os/arch 8c25cb36 false 100B")
   447  	})
   448  
   449  	Convey("SearchFixedTagsGQL error", t, func() {
   450  		buff := bytes.NewBufferString("")
   451  		searchConfig := getMockSearchConfig(buff, mockService{
   452  			getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   453  				imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
   454  			) {
   455  				return &common.ImageListWithCVEFixedResponse{
   456  					ImageListWithCVEFixed: common.ImageListWithCVEFixed{
   457  						PaginatedImagesResult: common.PaginatedImagesResult{},
   458  					},
   459  				}, zerr.ErrInjected
   460  			},
   461  		})
   462  
   463  		err := SearchFixedTagsGQL(searchConfig, "repo", "CVE-12345")
   464  		So(err, ShouldNotBeNil)
   465  	})
   466  }
   467  
   468  func TestSearchReferrersGQL(t *testing.T) {
   469  	Convey("SearchReferrersGQL", t, func() {
   470  		buff := bytes.NewBufferString("")
   471  		searchConfig := getMockSearchConfig(buff, mockService{
   472  			getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   473  				repo, digest string) (*common.ReferrersResp, error,
   474  			) {
   475  				return &common.ReferrersResp{
   476  					ReferrersResult: common.ReferrersResult{
   477  						Referrers: []common.Referrer{{
   478  							MediaType:    ispec.MediaTypeImageManifest,
   479  							Size:         100,
   480  							ArtifactType: "art.type",
   481  							Digest:       godigest.FromString("123").String(),
   482  						}},
   483  					},
   484  				}, nil
   485  			},
   486  		})
   487  
   488  		err := SearchReferrersGQL(searchConfig, "repo@"+godigest.FromString("str").String())
   489  		So(err, ShouldBeNil)
   490  		space := regexp.MustCompile(`\s+`)
   491  		str := space.ReplaceAllString(buff.String(), " ")
   492  		actual := strings.TrimSpace(str)
   493  		So(actual, ShouldContainSubstring,
   494  			"art.type 100 B sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3")
   495  	})
   496  
   497  	Convey("SearchReferrersGQL error", t, func() {
   498  		buff := bytes.NewBufferString("")
   499  		searchConfig := getMockSearchConfig(buff, mockService{
   500  			getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   501  				repo, digest string) (*common.ReferrersResp, error,
   502  			) {
   503  				return &common.ReferrersResp{}, zerr.ErrInjected
   504  			},
   505  		})
   506  
   507  		err := SearchReferrersGQL(searchConfig, "repo@"+godigest.FromString("str").String())
   508  		So(err, ShouldNotBeNil)
   509  	})
   510  }
   511  
   512  func TestGlobalSearchGQL(t *testing.T) {
   513  	Convey("GlobalSearchGQL", t, func() {
   514  		buff := bytes.NewBufferString("")
   515  		searchConfig := getMockSearchConfig(buff, mockService{
   516  			globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   517  				query string) (*common.GlobalSearch, error,
   518  			) {
   519  				return &common.GlobalSearch{
   520  					Repos: []common.RepoSummary{{
   521  						Name:        "repo",
   522  						Size:        "100",
   523  						LastUpdated: time.Date(2010, 1, 1, 1, 1, 1, 0, time.UTC),
   524  					}},
   525  				}, nil
   526  			},
   527  		})
   528  
   529  		err := GlobalSearchGQL(searchConfig, "repo")
   530  		So(err, ShouldBeNil)
   531  		space := regexp.MustCompile(`\s+`)
   532  		str := space.ReplaceAllString(buff.String(), " ")
   533  		actual := strings.TrimSpace(str)
   534  		So(actual, ShouldContainSubstring,
   535  			"repo ")
   536  	})
   537  
   538  	Convey("GlobalSearchGQL error", t, func() {
   539  		buff := bytes.NewBufferString("")
   540  		searchConfig := getMockSearchConfig(buff, mockService{
   541  			globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
   542  				query string) (*common.GlobalSearch, error,
   543  			) {
   544  				return &common.GlobalSearch{}, zerr.ErrInjected
   545  			},
   546  		})
   547  
   548  		err := GlobalSearchGQL(searchConfig, "repo")
   549  		So(err, ShouldNotBeNil)
   550  	})
   551  }
   552  
   553  func TestSearchReferrers(t *testing.T) {
   554  	Convey("SearchReferrers", t, func() {
   555  		buff := bytes.NewBufferString("")
   556  		searchConfig := getMockSearchConfig(buff, mockService{
   557  			getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
   558  				repo string, digest string) (referrersResult, error,
   559  			) {
   560  				return referrersResult([]common.Referrer{
   561  					{
   562  						MediaType:    ispec.MediaTypeImageManifest,
   563  						Size:         100,
   564  						ArtifactType: "art.type",
   565  						Digest:       godigest.FromString("123").String(),
   566  					},
   567  				}), nil
   568  			},
   569  		})
   570  
   571  		err := SearchReferrers(searchConfig, "repo@"+godigest.FromString("str").String())
   572  		So(err, ShouldBeNil)
   573  		space := regexp.MustCompile(`\s+`)
   574  		str := space.ReplaceAllString(buff.String(), " ")
   575  		actual := strings.TrimSpace(str)
   576  		So(actual, ShouldContainSubstring,
   577  			"art.type 100 B sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3")
   578  	})
   579  
   580  	Convey("SearchReferrers error", t, func() {
   581  		buff := bytes.NewBufferString("")
   582  		searchConfig := getMockSearchConfig(buff, mockService{
   583  			getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
   584  				repo string, digest string) (referrersResult, error,
   585  			) {
   586  				return referrersResult{}, zerr.ErrInjected
   587  			},
   588  		})
   589  
   590  		err := SearchReferrers(searchConfig, "repo@"+godigest.FromString("str").String())
   591  		So(err, ShouldNotBeNil)
   592  	})
   593  }
   594  
   595  func TestSearchRepos(t *testing.T) {
   596  	Convey("SearchRepos", t, func() {
   597  		buff := bytes.NewBufferString("")
   598  		searchConfig := getMockSearchConfig(buff, mockService{})
   599  
   600  		err := SearchRepos(searchConfig)
   601  		So(err, ShouldBeNil)
   602  		space := regexp.MustCompile(`\s+`)
   603  		str := space.ReplaceAllString(buff.String(), " ")
   604  		actual := strings.TrimSpace(str)
   605  		So(actual, ShouldContainSubstring, "repo1")
   606  		So(actual, ShouldContainSubstring, "repo2")
   607  	})
   608  }
   609  
   610  func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) SearchConfig {
   611  	return SearchConfig{
   612  		ResultWriter:  buff,
   613  		User:          "",
   614  		SearchService: mockService,
   615  		ServURL:       "http://127.0.0.1:8000",
   616  		OutputFormat:  "",
   617  		VerifyTLS:     false,
   618  		FixedFlag:     false,
   619  		Verbose:       false,
   620  		Debug:         false,
   621  	}
   622  }
   623  
   624  func getMockImageStruct() imageStruct {
   625  	return imageStruct(common.ImageSummary{
   626  		RepoName: "repo", Tag: "tag",
   627  		MediaType: ispec.MediaTypeImageManifest,
   628  		Digest:    godigest.FromString("str").String(),
   629  		Size:      "100",
   630  		Manifests: []common.ManifestSummary{{
   631  			Size:         "100",
   632  			Platform:     common.Platform{Os: "os", Arch: "arch"},
   633  			Digest:       godigest.FromString("str").String(),
   634  			ConfigDigest: godigest.FromString("str").String(),
   635  		}},
   636  	})
   637  }
   638  
   639  func getMockImageSummary() common.ImageSummary {
   640  	return common.ImageSummary{
   641  		RepoName: "repo", Tag: "tag",
   642  		MediaType: ispec.MediaTypeImageManifest,
   643  		Digest:    godigest.FromString("str").String(),
   644  		Size:      "100",
   645  		Manifests: []common.ManifestSummary{{
   646  			Size:         "100",
   647  			Platform:     common.Platform{Os: "os", Arch: "arch"},
   648  			Digest:       godigest.FromString("str").String(),
   649  			ConfigDigest: godigest.FromString("str").String(),
   650  		}},
   651  	}
   652  }
   653  
   654  func TestUtils(t *testing.T) {
   655  	Convey("Utils", t, func() {
   656  		ok := haveSameArgs(field{"query", []struct {
   657  			Name string `json:"name"`
   658  		}{
   659  			{Name: "arg1"}, {Name: "arg2"},
   660  		}}, GQLQuery{
   661  			Name: "query", Args: []string{"arg1"},
   662  		})
   663  		So(ok, ShouldBeFalse)
   664  
   665  		ok = haveSameArgs(field{"query", []struct {
   666  			Name string `json:"name"`
   667  		}{
   668  			{Name: "arg1"}, {Name: "arg2"},
   669  		}}, GQLQuery{
   670  			Name: "query", Args: []string{"arg1", "arg3"},
   671  		})
   672  		So(ok, ShouldBeFalse)
   673  
   674  		err := containsGQLQueryWithParams(
   675  			[]field{
   676  				{Name: "query"},
   677  			},
   678  			[]typeInfo{},
   679  			GQLQuery{Name: "other-name"},
   680  		)
   681  		So(err, ShouldNotBeNil)
   682  	})
   683  
   684  	Convey("GetConfigOptions", t, func() {
   685  		// no flags
   686  		cmd := &cobra.Command{}
   687  		isSpinner, verifyTLS, err := GetCliConfigOptions(cmd)
   688  		So(err, ShouldNotBeNil)
   689  		So(isSpinner, ShouldBeFalse)
   690  		So(verifyTLS, ShouldBeFalse)
   691  
   692  		// bad showspinner
   693  		configPath := makeConfigFile(`{"configs":[{"_name":"imagetest","showspinner":"bad", "verify-tls": false}]}`)
   694  		cmd = &cobra.Command{}
   695  		cmd.Flags().String(ConfigFlag, "imagetest", "")
   696  		isSpinner, verifyTLS, err = GetCliConfigOptions(cmd)
   697  		So(err, ShouldNotBeNil)
   698  		So(isSpinner, ShouldBeFalse)
   699  		So(verifyTLS, ShouldBeFalse)
   700  		os.Remove(configPath)
   701  
   702  		// bad verify-tls
   703  		configPath = makeConfigFile(`{"configs":[{"_name":"imagetest","showspinner":false, "verify-tls": "bad"}]}`)
   704  		cmd = &cobra.Command{}
   705  		cmd.Flags().String(ConfigFlag, "imagetest", "")
   706  		isSpinner, verifyTLS, err = GetCliConfigOptions(cmd)
   707  		So(err, ShouldNotBeNil)
   708  		So(isSpinner, ShouldBeFalse)
   709  		So(verifyTLS, ShouldBeFalse)
   710  		os.Remove(configPath)
   711  	})
   712  
   713  	Convey("GetServerURLFromFlags", t, func() {
   714  		cmd := &cobra.Command{}
   715  		cmd.Flags().String(URLFlag, "url", "")
   716  		url, err := GetServerURLFromFlags(cmd)
   717  		So(url, ShouldResemble, "url")
   718  		So(err, ShouldBeNil)
   719  
   720  		// err no config or url
   721  		cmd = &cobra.Command{}
   722  		url, err = GetServerURLFromFlags(cmd)
   723  		So(url, ShouldResemble, "")
   724  		So(err, ShouldNotBeNil)
   725  
   726  		// err ulr from config is empty
   727  		configPath := makeConfigFile(`{"configs":[{"_name":"imagetest"}]}`)
   728  		cmd = &cobra.Command{}
   729  		cmd.Flags().String(ConfigFlag, "imagetest", "")
   730  		url, err = GetServerURLFromFlags(cmd)
   731  		So(url, ShouldResemble, "")
   732  		So(err, ShouldNotBeNil)
   733  		os.Remove(configPath)
   734  
   735  		// err reading the server url from config
   736  		configPath = makeConfigFile("{}")
   737  		cmd = &cobra.Command{}
   738  		cmd.Flags().String(ConfigFlag, "imagetest", "")
   739  		url, err = GetServerURLFromFlags(cmd)
   740  		So(url, ShouldResemble, "")
   741  		So(err, ShouldNotBeNil)
   742  		os.Remove(configPath)
   743  	})
   744  
   745  	Convey("CheckExtEndPointQuery", t, func() {
   746  		// invalid url
   747  		err := CheckExtEndPointQuery(SearchConfig{
   748  			User:    "",
   749  			ServURL: "bad-url",
   750  		})
   751  		So(err, ShouldNotBeNil)
   752  
   753  		// good url but no connection
   754  		err = CheckExtEndPointQuery(SearchConfig{
   755  			User:         "",
   756  			ServURL:      "http://127.0.0.1:5000",
   757  			VerifyTLS:    false,
   758  			Debug:        false,
   759  			ResultWriter: io.Discard,
   760  		})
   761  		So(err, ShouldNotBeNil)
   762  	})
   763  }