diff --git a/cli/README.md b/cli/README.md index 081960c5c..a20190f7d 100644 --- a/cli/README.md +++ b/cli/README.md @@ -221,23 +221,35 @@ General content search across all records using the search service. **Examples:** ```bash # Search by record name -dirctl search --query "name=my-agent" +dirctl search --name "my-agent" # Search by version -dirctl search --query "version=v1.0.0" +dirctl search --version "v1.0.0" + +# Search by skill name +dirctl search --skill "natural_language_processing" # Search by skill ID -dirctl search --query "skill-id=10201" +dirctl search --skill-id "10201" # Complex search with multiple criteria dirctl search --limit 10 --offset 0 \ - --query "name=my-agent" \ - --query "skill-name=Text Completion" \ - --query "locator=docker-image:https://example.com/image" + --name "my-agent" \ + --skill "natural_language_processing/natural_language_generation/text_completion" \ + --locator "docker-image:https://example.com/image" + +# Wildcard search examples +dirctl search --name "web*" --version "v1.*" +dirctl search --skill "python*" --skill "*script" ``` **Flags:** -- `--query ` - Search criteria (repeatable) +- `--name ` - Search by record name (repeatable) +- `--version ` - Search by version (repeatable) +- `--skill ` - Search by skill name (repeatable) +- `--skill-id ` - Search by skill ID (repeatable) +- `--locator ` - Search by locator type (repeatable) +- `--module ` - Search by module (repeatable) - `--limit ` - Maximum results - `--offset ` - Result offset for pagination diff --git a/cli/cmd/search/options.go b/cli/cmd/search/options.go index 63e180e45..e4730a2b3 100644 --- a/cli/cmd/search/options.go +++ b/cli/cmd/search/options.go @@ -11,7 +11,13 @@ type options struct { Limit uint32 Offset uint32 - Query Query + // Direct field flags (consistent with routing search) + Names []string + Versions []string + SkillIDs []string + SkillNames []string + Locators []string + Modules []string } func init() { @@ -20,7 +26,21 @@ func init() { flags.Uint32Var(&opts.Limit, "limit", 100, "Maximum number of results to return (default: 100)") //nolint:mnd flags.Uint32Var(&opts.Offset, "offset", 0, "Pagination offset (default: 0)") - flags.VarP(&opts.Query, "query", "q", "Search query terms") + // Direct field flags + flags.StringArrayVar(&opts.Names, "name", nil, "Search for records with specific name (can be repeated)") + flags.StringArrayVar(&opts.Versions, "version", nil, "Search for records with specific version (can be repeated)") + flags.StringArrayVar(&opts.SkillIDs, "skill-id", nil, "Search for records with specific skill ID (can be repeated)") + flags.StringArrayVar(&opts.SkillNames, "skill", nil, "Search for records with specific skill name (can be repeated)") + flags.StringArrayVar(&opts.Locators, "locator", nil, "Search for records with specific locator type (can be repeated)") + flags.StringArrayVar(&opts.Modules, "module", nil, "Search for records with specific module (can be repeated)") + + // Add examples in flag help + flags.Lookup("name").Usage = "Search for records with specific name (e.g., --name 'my-agent' --name 'web-*')" + flags.Lookup("version").Usage = "Search for records with specific version (e.g., --version 'v1.0.0' --version 'v1.*')" + flags.Lookup("skill-id").Usage = "Search for records with specific skill ID (e.g., --skill-id '10201')" + flags.Lookup("skill").Usage = "Search for records with specific skill name (e.g., --skill 'natural_language_processing' --skill 'audio')" + flags.Lookup("locator").Usage = "Search for records with specific locator type (e.g., --locator 'docker-image')" + flags.Lookup("module").Usage = "Search for records with specific module (e.g., --module 'runtime/language')" // Add output format flags presenter.AddOutputFlags(Command) diff --git a/cli/cmd/search/query.go b/cli/cmd/search/query.go deleted file mode 100644 index a1e6232b3..000000000 --- a/cli/cmd/search/query.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright AGNTCY Contributors (https://github.com/agntcy) -// SPDX-License-Identifier: Apache-2.0 - -//nolint:mnd -package search - -import ( - "errors" - "fmt" - "strings" - - searchv1 "github.com/agntcy/dir/api/search/v1" -) - -type Query []string - -func (q *Query) String() string { - return strings.Join(*q, ", ") -} - -func (q *Query) Set(value string) error { - if value == "" { - return errors.New("empty query not allowed") - } - - parts := strings.SplitN(value, "=", 2) - for i, part := range parts { - parts[i] = strings.TrimSpace(part) - - if part == "" { - return errors.New("invalid query format, empty field or value") - } - } - - if len(parts) < 2 { - return errors.New("invalid query format, expected 'field=value'") - } - - validQueryType := false - - for _, queryType := range searchv1.ValidQueryTypes { - if parts[0] == queryType { - validQueryType = true - - break - } - } - - if !validQueryType { - return fmt.Errorf( - "invalid query type: %s, valid types are: %v", - parts[0], - strings.Join(searchv1.ValidQueryTypes, ", "), - ) - } - - *q = append(*q, value) - - return nil -} - -func (q *Query) Type() string { - return "query" -} - -func (q *Query) ToAPIQueries() []*searchv1.RecordQuery { - queries := []*searchv1.RecordQuery{} - - for _, item := range *q { - parts := strings.SplitN(item, "=", 2) - - queries = append(queries, &searchv1.RecordQuery{ - Type: searchv1.RecordQueryType(searchv1.RecordQueryType_value[parts[0]]), - Value: parts[1], - }) - } - - return queries -} diff --git a/cli/cmd/search/search.go b/cli/cmd/search/search.go index cda6d1dea..6cbb6c205 100644 --- a/cli/cmd/search/search.go +++ b/cli/cmd/search/search.go @@ -19,74 +19,76 @@ var Command = &cobra.Command{ Short: "Search for records", Long: `Search for records in the directory using various filters and options. +This command provides a consistent interface with routing search commands. + Usage examples: 1. Basic search with specific filters and limit: dirctl search --limit 10 \ --offset 0 \ - --query "name=my-agent-name" \ - --query "version=v1.0.0" \ - --query "skill-id=10201" \ - --query "skill-name=Text Completion" \ - --query "locator=docker-image:https://example.com/docker-image" \ - --query "module=my-custom-module-name" + --name "my-agent-name" \ + --version "v1.0.0" \ + --skill-id "10201" \ + --skill "Text Completion" \ + --locator "docker-image:https://example.com/docker-image" \ + --module "my-custom-module-name" 2. Wildcard search examples: # Find all web-related agents - dirctl search --query "name=web*" + dirctl search --name "web*" # Find all v1.x versions - dirctl search --query "version=v1.*" + dirctl search --version "v1.*" # Find agents with Python or JavaScript skills - dirctl search --query "skill-name=python*" --query "skill-name=*script" + dirctl search --skill "python*" --skill "*script" # Find agents with HTTP-based locators - dirctl search --query "locator=http*" + dirctl search --locator "http*" # Find agents with plugin modules - dirctl search --query "module=*-plugin*" + dirctl search --module "*-plugin*" 3. Question mark wildcard (? matches exactly one character): # Find version v1.0.x where x is any single digit - dirctl search --query "version=v1.0.?" + dirctl search --version "v1.0.?" # Find agents with 3-character names ending in "api" - dirctl search --query "name=???api" + dirctl search --name "???api" # Find skills with single character variations - dirctl search --query "skill-name=Pytho?" + dirctl search --skill "Pytho?" 4. List wildcards ([] matches any character within brackets): # Find agents with numeric suffixes - dirctl search --query "name=agent-[0-9]" + dirctl search --name "agent-[0-9]" # Find versions starting with v followed by any digit - dirctl search --query "version=v[0-9].*" + dirctl search --version "v[0-9].*" # Find skills starting with uppercase letters A-M - dirctl search --query "skill-name=[A-M]*" + dirctl search --skill "[A-M]*" # Find locators with specific protocols - dirctl search --query "locator=[hf]tt[ps]*" + dirctl search --locator "[hf]tt[ps]*" 5. Complex wildcard patterns: # Find API services with v2 versions - dirctl search --query "name=api-*-service" --query "version=v2.*" + dirctl search --name "api-*-service" --version "v2.*" # Find machine learning agents - dirctl search --query "skill-name=*machine*learning*" + dirctl search --skill "*machine*learning*" # Find agents with container locators - dirctl search --query "locator=*docker*" --query "locator=*container*" + dirctl search --locator "*docker*" --locator "*container*" # Combine different wildcard types - dirctl search --query "name=web-[0-9]?" --query "version=v?.*.?" + dirctl search --name "web-[0-9]?" --version "v?.*.?" `, RunE: func(cmd *cobra.Command, _ []string) error { @@ -100,10 +102,13 @@ func runCommand(cmd *cobra.Command) error { return errors.New("failed to get client from context") } + // Build queries from direct field flags + queries := buildQueriesFromFlags() + ch, err := c.Search(cmd.Context(), &searchv1.SearchRequest{ Limit: &opts.Limit, Offset: &opts.Offset, - Queries: opts.Query.ToAPIQueries(), + Queries: queries, }) if err != nil { return fmt.Errorf("failed to search: %w", err) @@ -122,3 +127,60 @@ func runCommand(cmd *cobra.Command) error { return presenter.PrintMessage(cmd, "record CIDs", "Record CIDs found", results) } + +// buildQueriesFromFlags builds API queries. +func buildQueriesFromFlags() []*searchv1.RecordQuery { + queries := make([]*searchv1.RecordQuery, 0, + len(opts.Names)+len(opts.Versions)+len(opts.SkillIDs)+ + len(opts.SkillNames)+len(opts.Locators)+len(opts.Modules)) + + // Add name queries + for _, name := range opts.Names { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_NAME, + Value: name, + }) + } + + // Add version queries + for _, version := range opts.Versions { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_VERSION, + Value: version, + }) + } + + // Add skill-id queries + for _, skillID := range opts.SkillIDs { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_SKILL_ID, + Value: skillID, + }) + } + + // Add skill-name queries + for _, skillName := range opts.SkillNames { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_SKILL_NAME, + Value: skillName, + }) + } + + // Add locator queries + for _, locator := range opts.Locators { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_LOCATOR, + Value: locator, + }) + } + + // Add module queries + for _, module := range opts.Modules { + queries = append(queries, &searchv1.RecordQuery{ + Type: searchv1.RecordQueryType_RECORD_QUERY_TYPE_MODULE, + Value: module, + }) + } + + return queries +} diff --git a/e2e/local/01_storage_test.go b/e2e/local/01_storage_test.go index dc6e09d6b..c0e5e600f 100644 --- a/e2e/local/01_storage_test.go +++ b/e2e/local/01_storage_test.go @@ -5,7 +5,6 @@ package local import ( _ "embed" - "fmt" "os" "path/filepath" "time" @@ -128,19 +127,19 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests using a local single no WithLimit(10). WithOffset(0). WithArgs("--raw"). - WithQuery("name", version.expectedAgentName). // Use version-specific record name to prevent conflicts between V1/V2/V3 tests - WithQuery("skill-id", version.expectedSkillIDs[0]). - WithQuery("skill-name", version.expectedSkillNames[0]) + WithName(version.expectedAgentName). // Use version-specific record name to prevent conflicts between V1/V2/V3 tests + WithSkillID(version.expectedSkillIDs[0]). + WithSkillName(version.expectedSkillNames[0]) // Add locator and module queries only if they exist (not empty for minimal test) if version.expectedLocator != "" { - search = search.WithQuery("locator", version.expectedLocator) + search = search.WithLocator(version.expectedLocator) } if version.expectedModule != "" { - search = search.WithQuery("module", version.expectedModule) + search = search.WithModule(version.expectedModule) } - search.ShouldReturn(fmt.Sprintf("[%s]", cid)) + search.ShouldContain(cid) }) // Step 6: Search by second skill (depends on push) @@ -155,19 +154,19 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests using a local single no WithLimit(10). WithOffset(0). WithArgs("--raw"). - WithQuery("name", version.expectedAgentName). // Use version-specific record name to prevent conflicts between V1/V2/V3 tests - WithQuery("skill-id", version.expectedSkillIDs[1]). - WithQuery("skill-name", version.expectedSkillNames[1]) + WithName(version.expectedAgentName). // Use version-specific record name to prevent conflicts between V1/V2/V3 tests + WithSkillID(version.expectedSkillIDs[1]). + WithSkillName(version.expectedSkillNames[1]) // Add locator and module queries only if they exist (not empty for minimal test) if version.expectedLocator != "" { - search = search.WithQuery("locator", version.expectedLocator) + search = search.WithLocator(version.expectedLocator) } if version.expectedModule != "" { - search = search.WithQuery("module", version.expectedModule) + search = search.WithModule(version.expectedModule) } - search.ShouldReturn(fmt.Sprintf("[%s]", cid)) + search.ShouldContain(cid) }) // Step 7: Test non-existent pull (independent test) diff --git a/e2e/local/02_search_test.go b/e2e/local/02_search_test.go index ade04d2c1..afc6f39a7 100644 --- a/e2e/local/02_search_test.go +++ b/e2e/local/02_search_test.go @@ -66,42 +66,42 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("exact match searches (no wildcards)", func() { ginkgo.It("should find record by exact name match", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v3"). + WithName("directory.agntcy.org/cisco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record by exact version match", func() { output := cli.Search(). - WithQuery("version", "v3.0.0"). + WithVersion("v3.0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record by exact skill name match", func() { output := cli.Search(). - WithQuery("skill-name", "natural_language_processing/natural_language_generation/text_completion"). + WithSkillName("natural_language_processing/natural_language_generation/text_completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record by exact skill ID match", func() { output := cli.Search(). - WithQuery("skill-id", "10201"). + WithSkillID("10201"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record by exact locator match", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.io/agntcy/marketing-strategy"). + WithLocator("docker_image:https://ghcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record by exact module name match", func() { output := cli.Search(). - WithQuery("module", "license"). + WithModule("license"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -111,28 +111,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("name field wildcards", func() { ginkgo.It("should find record with name prefix wildcard", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/cisco/*"). + WithName("directory.agntcy.org/cisco/*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with name suffix wildcard", func() { output := cli.Search(). - WithQuery("name", "*marketing-strategy-v3"). + WithName("*marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with name middle wildcard", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/*/marketing-strategy-v3"). + WithName("directory.agntcy.org/*/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with multiple wildcards in name", func() { output := cli.Search(). - WithQuery("name", "*cisco*strategy*"). + WithName("*cisco*strategy*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -141,21 +141,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("version field wildcards", func() { ginkgo.It("should find record with version prefix wildcard", func() { output := cli.Search(). - WithQuery("version", "v3.*"). + WithVersion("v3.*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with version suffix wildcard", func() { output := cli.Search(). - WithQuery("version", "*.0.0"). + WithVersion("*.0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with version middle wildcard", func() { output := cli.Search(). - WithQuery("version", "v*0.0"). + WithVersion("v*0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -164,28 +164,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("skill name wildcards", func() { ginkgo.It("should find record with skill name prefix wildcard", func() { output := cli.Search(). - WithQuery("skill-name", "natural_language*"). + WithSkillName("natural_language*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with skill name suffix wildcard", func() { output := cli.Search(). - WithQuery("skill-name", "*Completion"). + WithSkillName("*Completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with skill name middle wildcard", func() { output := cli.Search(). - WithQuery("skill-name", "Natural*Processing*Text*"). + WithSkillName("Natural*Processing*Text*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with different skill using wildcard", func() { output := cli.Search(). - WithQuery("skill-name", "*problem_solving"). + WithSkillName("*problem_solving"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -194,28 +194,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("locator wildcards", func() { ginkgo.It("should find record with locator prefix wildcard", func() { output := cli.Search(). - WithQuery("locator", "docker_image:*"). + WithLocator("docker_image:*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with locator suffix wildcard", func() { output := cli.Search(). - WithQuery("locator", "*marketing-strategy"). + WithLocator("*marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with locator middle wildcard", func() { output := cli.Search(). - WithQuery("locator", "docker_image:*ghcr.io*marketing-strategy"). + WithLocator("docker_image:*ghcr.io*marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with protocol wildcard", func() { output := cli.Search(). - WithQuery("locator", "*://ghcr.io/agntcy/marketing-strategy"). + WithLocator("*://ghcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -224,28 +224,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("module wildcards", func() { ginkgo.It("should find record with module name prefix wildcard", func() { output := cli.Search(). - WithQuery("module", "license*"). + WithModule("license*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with module name suffix wildcard", func() { output := cli.Search(). - WithQuery("module", "*framework*"). + WithModule("*framework*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with schema module wildcard", func() { output := cli.Search(). - WithQuery("module", "*runtime*"). + WithModule("*runtime*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with module wildcard", func() { output := cli.Search(). - WithQuery("module", "*"). + WithModule("*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -256,21 +256,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("version field question mark wildcards", func() { ginkgo.It("should find record with single character version wildcard", func() { output := cli.Search(). - WithQuery("version", "v?.0.0"). + WithVersion("v?.0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with multiple question mark wildcards in version", func() { output := cli.Search(). - WithQuery("version", "v?.?.?"). + WithVersion("v?.?.?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with question mark in middle of version", func() { output := cli.Search(). - WithQuery("version", "v3.?.0"). + WithVersion("v3.?.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -279,21 +279,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("name field question mark wildcards", func() { ginkgo.It("should find record with question mark in name", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v?"). + WithName("directory.agntcy.org/cisco/marketing-strategy-v?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with multiple question marks in name", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/????o/marketing-strategy-v3"). + WithName("directory.agntcy.org/????o/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with question mark at beginning of name segment", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/?isco/marketing-strategy-v3"). + WithName("directory.agntcy.org/?isco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -302,21 +302,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("skill name question mark wildcards", func() { ginkgo.It("should find record with question mark in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "natural_language_processing/natural_language_generation/text_completio?"). + WithSkillName("natural_language_processing/natural_language_generation/text_completio?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with question mark replacing single word character", func() { output := cli.Search(). - WithQuery("skill-name", "?atural_language_processing/natural_language_generation/text_completion"). + WithSkillName("?atural_language_processing/natural_language_generation/text_completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with multiple question marks in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "natural_langua??_processing/natural_language_generation/text_completion"). + WithSkillName("natural_langua??_processing/natural_language_generation/text_completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -325,21 +325,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("locator question mark wildcards", func() { ginkgo.It("should find record with question mark in protocol", func() { output := cli.Search(). - WithQuery("locator", "docker_image:http?://ghcr.io/agntcy/marketing-strategy"). + WithLocator("docker_image:http?://ghcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with question mark in domain", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.i?/agntcy/marketing-strategy"). + WithLocator("docker_image:https://ghcr.i?/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with question mark in path", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.io/agntcy/marketing-strateg?"). + WithLocator("docker_image:https://ghcr.io/agntcy/marketing-strateg?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -348,7 +348,7 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("module question mark wildcards", func() { ginkgo.It("should find record with question mark in module name", func() { output := cli.Search(). - WithQuery("module", "licens?"). + WithModule("licens?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -357,28 +357,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("mixed ? and * wildcard patterns", func() { ginkgo.It("should find record with both wildcards in version", func() { output := cli.Search(). - WithQuery("version", "v?.*"). + WithVersion("v?.*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with both wildcards in name", func() { output := cli.Search(). - WithQuery("name", "*cisco/marketing-strategy-v?"). + WithName("*cisco/marketing-strategy-v?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with both wildcards in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "natural*processing/natural_language_generation/text_completio?"). + WithSkillName("natural*processing/natural_language_generation/text_completio?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with complex wildcard combination", func() { output := cli.Search(). - WithQuery("locator", "*://ghcr.i?/*/marketing-strateg?"). + WithLocator("*://ghcr.i?/*/marketing-strateg?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -389,21 +389,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("version field list wildcards", func() { ginkgo.It("should find record with numeric range in version", func() { output := cli.Search(). - WithQuery("version", "v[0-9].0.0"). + WithVersion("v[0-9].0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with specific digit list in version", func() { output := cli.Search(). - WithQuery("version", "v[123].0.0"). + WithVersion("v[123].0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with negated character class in version", func() { output := cli.Search(). - WithQuery("version", "v[^0-2].0.0"). + WithVersion("v[^0-2].0.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -412,21 +412,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("name field list wildcards", func() { ginkgo.It("should find record with character list in name", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[abc]isco/marketing-strategy-v3"). + WithName("directory.agntcy.org/[abc]isco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with alphabetic range in name", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[a-z]isco/marketing-strategy-v3"). + WithName("directory.agntcy.org/[a-z]isco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with negated range in name", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[^xyz]isco/marketing-strategy-v3"). + WithName("directory.agntcy.org/[^xyz]isco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -435,21 +435,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("skill name list wildcards", func() { ginkgo.It("should find record with character list in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "[mn]atural_language_processing/natural_language_generation/text_completion"). + WithSkillName("[mn]atural_language_processing/natural_language_generation/text_completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with alphabetic range in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "[A-Z]atural_language_processing/natural_language_generation/text_completion"). + WithSkillName("[A-Z]atural_language_processing/natural_language_generation/text_completion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with negated character class in skill name", func() { output := cli.Search(). - WithQuery("skill-name", "natural_language_processing/natural_language_generation/text_[^D-Z]ompletion"). + WithSkillName("natural_language_processing/natural_language_generation/text_[^D-Z]ompletion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -458,21 +458,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("locator list wildcards", func() { ginkgo.It("should find record with character list in protocol", func() { output := cli.Search(). - WithQuery("locator", "docker_image:[ht]ttps://ghcr.io/agntcy/marketing-strategy"). + WithLocator("docker_image:[ht]ttps://ghcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with alphabetic range in domain", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://[a-z]hcr.io/agntcy/marketing-strategy"). + WithLocator("docker_image:https://[a-z]hcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with negated range in path", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.io/agntcy/marketing-strateg[^0-9]"). + WithLocator("docker_image:https://ghcr.io/agntcy/marketing-strateg[^0-9]"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -481,14 +481,14 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("module list wildcards", func() { ginkgo.It("should find record with character list in module name", func() { output := cli.Search(). - WithQuery("module", "[l]icense"). + WithModule("[l]icense"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with alphabetic range in module name", func() { output := cli.Search(). - WithQuery("module", "[a-z]icense"). + WithModule("[a-z]icense"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -497,28 +497,28 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("mixed list wildcards with other patterns", func() { ginkgo.It("should find record with list and asterisk wildcards", func() { output := cli.Search(). - WithQuery("name", "*[c]isco*"). + WithName("*[c]isco*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with list and question mark wildcards", func() { output := cli.Search(). - WithQuery("version", "v[0-9].?.0"). + WithVersion("v[0-9].?.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with all wildcard types combined", func() { output := cli.Search(). - WithQuery("name", "*[c]isco/marketing-strategy-v?"). + WithName("*[c]isco/marketing-strategy-v?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with multiple list wildcards", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://[g]hcr.io/agntcy/marketing-strateg[y]"). + WithLocator("docker_image:https://[g]hcr.io/agntcy/marketing-strateg[y]"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -527,21 +527,21 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("complex list wildcard patterns", func() { ginkgo.It("should find record with alphanumeric range", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[a-zA-Z0-9]isco/marketing-strategy-v3"). + WithName("directory.agntcy.org/[a-zA-Z0-9]isco/marketing-strategy-v3"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with mixed character classes", func() { output := cli.Search(). - WithQuery("skill-name", "[A-Z]atural_[A-Z]anguage_[A-Z]rocessing/natural_language_generation/text_[A-Z]ompletion"). + WithSkillName("[A-Z]atural_[A-Z]anguage_[A-Z]rocessing/natural_language_generation/text_[A-Z]ompletion"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with complex negated pattern", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.io/agntcy/marketing-strateg[^0-9xz]"). + WithLocator("docker_image:https://ghcr.io/agntcy/marketing-strateg[^0-9xz]"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -551,25 +551,25 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("complex wildcard combinations", func() { ginkgo.It("should find record with multiple filter types using wildcards", func() { output := cli.Search(). - WithQuery("name", "*cisco*"). - WithQuery("version", "v3.*"). - WithQuery("skill-name", "*language*"). + WithName("*cisco*"). + WithVersion("v3.*"). + WithSkillName("*language*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record mixing exact and wildcard filters", func() { output := cli.Search(). - WithQuery("skill-id", "10201"). - WithQuery("name", "*marketing-strategy*"). - WithQuery("locator", "docker_image:*"). + WithSkillID("10201"). + WithName("*marketing-strategy*"). + WithLocator("docker_image:*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle search with limit and wildcard", func() { output := cli.Search(). - WithQuery("name", "*cisco*"). + WithName("*cisco*"). WithLimit(5). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) @@ -577,7 +577,7 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.It("should handle search with offset and wildcard", func() { output := cli.Search(). - WithQuery("version", "v*"). + WithVersion("v*"). WithOffset(0). WithLimit(10). ShouldSucceed() @@ -586,36 +586,36 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.It("should find record with question mark and asterisk wildcards combined", func() { output := cli.Search(). - WithQuery("name", "*cisco*"). - WithQuery("version", "v?.0.0"). - WithQuery("skill-name", "Natural*Completio?"). + WithName("*cisco*"). + WithVersion("v?.0.0"). + WithSkillName("Natural*Completio?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record mixing exact, asterisk and question mark filters", func() { output := cli.Search(). - WithQuery("skill-id", "10201"). - WithQuery("name", "*marketing-strategy-v?"). - WithQuery("locator", "docker_image:http?://*"). + WithSkillID("10201"). + WithName("*marketing-strategy-v?"). + WithLocator("docker_image:http?://*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record with all wildcard types combined", func() { output := cli.Search(). - WithQuery("name", "*[c]isco*"). - WithQuery("version", "v[0-9].?.0"). - WithQuery("skill-name", "[A-Z]atural*processing*"). + WithName("*[c]isco*"). + WithVersion("v[0-9].?.0"). + WithSkillName("[A-Z]atural*processing*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should find record mixing exact and list wildcard filters", func() { output := cli.Search(). - WithQuery("skill-id", "10201"). - WithQuery("name", "*marketing-strategy-v[0-9]"). - WithQuery("locator", "docker_image:https://[a-z]hcr.io/*"). + WithSkillID("10201"). + WithName("*marketing-strategy-v[0-9]"). + WithLocator("docker_image:https://[a-z]hcr.io/*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) @@ -624,65 +624,65 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("negative wildcard tests", func() { ginkgo.It("should return no results for non-matching wildcard pattern", func() { output := cli.Search(). - WithQuery("name", "nonexistent*pattern"). + WithName("nonexistent*pattern"). ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for wildcard with no matches", func() { output := cli.Search(). - WithQuery("version", "v99.*"). + WithVersion("v99.*"). ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results when combining conflicting filters", func() { output := cli.Search(). - WithQuery("name", "*cisco*"). - WithQuery("version", "v1.*"). // Record has v3.0.0 + WithName("*cisco*"). + WithVersion("v1.*"). // Record has v3.0.0 ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for non-matching question mark pattern", func() { output := cli.Search(). - WithQuery("version", "v?.9.9"). // Record has v3.0.0 + WithVersion("v?.9.9"). // Record has v3.0.0 ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for question mark requiring exact length", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v??"). // v3 is only 1 char + WithName("directory.agntcy.org/cisco/marketing-strategy-v??"). // v3 is only 1 char ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for conflicting question mark and exact filters", func() { output := cli.Search(). - WithQuery("version", "v?.0.0"). - WithQuery("version", "v2.0.0"). // Record has v3.0.0, not v2.0.0 + WithVersion("v?.0.0"). + WithVersion("v2.0.0"). // Record has v3.0.0, not v2.0.0 ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for non-matching list wildcard pattern", func() { output := cli.Search(). - WithQuery("version", "v[0-2].0.0"). // Record has v3.0.0, 3 is not in [0-2] + WithVersion("v[0-2].0.0"). // Record has v3.0.0, 3 is not in [0-2] ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for negated character class that excludes match", func() { output := cli.Search(). - WithQuery("version", "v[^3].0.0"). // Record has v3.0.0, but [^3] excludes 3 + WithVersion("v[^3].0.0"). // Record has v3.0.0, but [^3] excludes 3 ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should return no results for list wildcard with wrong character set", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[xyz]isco/marketing-strategy-v3"). // 'c' not in [xyz] + WithName("directory.agntcy.org/[xyz]isco/marketing-strategy-v3"). // 'c' not in [xyz] ShouldSucceed() gomega.Expect(output).NotTo(gomega.ContainSubstring(recordCID)) }) @@ -691,84 +691,84 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests to check search functio ginkgo.Context("edge cases and special characters", func() { ginkgo.It("should handle wildcard at the beginning and end", func() { output := cli.Search(). - WithQuery("name", "*marketing-strategy-v3*"). + WithName("*marketing-strategy-v3*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle single wildcard matching everything", func() { output := cli.Search(). - WithQuery("name", "*"). + WithName("*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle wildcards with special characters in URL", func() { output := cli.Search(). - WithQuery("locator", "*://ghcr.io/*"). + WithLocator("*://ghcr.io/*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle wildcards with dots and slashes", func() { output := cli.Search(). - WithQuery("module", "runtime/*"). + WithModule("runtime/*"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle question mark with dots in version", func() { output := cli.Search(). - WithQuery("version", "v3.?.0"). + WithVersion("v3.?.0"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle question mark with special characters in URLs", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://ghcr.i?/agntcy/marketing-strategy"). + WithLocator("docker_image:https://ghcr.i?/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle single question mark in various positions", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v?"). + WithName("directory.agntcy.org/cisco/marketing-strategy-v?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle mixed wildcards with complex patterns", func() { output := cli.Search(). - WithQuery("locator", "*://ghcr.i?/*/marketing-strateg?"). + WithLocator("*://ghcr.i?/*/marketing-strateg?"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle list wildcards with slashes", func() { output := cli.Search(). - WithQuery("module", "runtime/framework"). + WithModule("runtime/framework"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle list wildcards with special URL characters", func() { output := cli.Search(). - WithQuery("locator", "docker_image:https://[a-z]hcr.io/agntcy/marketing-strategy"). + WithLocator("docker_image:https://[a-z]hcr.io/agntcy/marketing-strategy"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle multiple list wildcards in single pattern", func() { output := cli.Search(). - WithQuery("name", "directory.agntcy.org/[c]isco/marketing-strategy-v[0-9]"). + WithName("directory.agntcy.org/[c]isco/marketing-strategy-v[0-9]"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) ginkgo.It("should handle list wildcards with all wildcard types", func() { output := cli.Search(). - WithQuery("locator", "*://[a-z]hcr.i?/*/marketing-strateg[y]"). + WithLocator("*://[a-z]hcr.i?/*/marketing-strateg[y]"). ShouldSucceed() gomega.Expect(output).To(gomega.ContainSubstring(recordCID)) }) diff --git a/e2e/network/02_sync_test.go b/e2e/network/02_sync_test.go index 1074318af..c3c9a0493 100644 --- a/e2e/network/02_sync_test.go +++ b/e2e/network/02_sync_test.go @@ -197,7 +197,7 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests for sync commands", fun ginkgo.It("should succeed to search for record_070_sync_v4.json from peer 2 after sync", func() { // Search should eventually return the cid in peer 2 (retry until monitor indexes the record) - output := cli.Search().WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v4").OnServer(utils.Peer2Addr).ShouldEventuallyContain(cid, 240*time.Second) + output := cli.Search().WithName("directory.agntcy.org/cisco/marketing-strategy-v4").OnServer(utils.Peer2Addr).ShouldEventuallyContain(cid, 240*time.Second) ginkgo.GinkgoWriter.Printf("Search found cid: %s", output) }) @@ -266,7 +266,7 @@ var _ = ginkgo.Describe("Running dirctl end-to-end tests for sync commands", fun ginkgo.It("should succeed to search for record_070_sync_v5.json from peer 3 after sync", func() { // Search should eventually return the cid in peer 2 (retry until monitor indexes the record) - output := cli.Search().WithQuery("name", "directory.agntcy.org/cisco/marketing-strategy-v5").OnServer(utils.Peer3Addr).ShouldEventuallyContain(cidV5, 240*time.Second) + output := cli.Search().WithName("directory.agntcy.org/cisco/marketing-strategy-v5").OnServer(utils.Peer3Addr).ShouldEventuallyContain(cidV5, 240*time.Second) ginkgo.GinkgoWriter.Printf("Search found cid: %s", output) }) diff --git a/e2e/shared/utils/cli.go b/e2e/shared/utils/cli.go index d91a49f93..54478e4c2 100644 --- a/e2e/shared/utils/cli.go +++ b/e2e/shared/utils/cli.go @@ -55,7 +55,14 @@ func (c *CLI) Delete(cid string) *CommandBuilder { func (c *CLI) Search() *SearchBuilder { return &SearchBuilder{ CommandBuilder: c.Command("search"), - queries: make(map[string]string), + names: []string{}, + versions: []string{}, + skillIDs: []string{}, + skillNames: []string{}, + locators: []string{}, + modules: []string{}, + limit: 0, + offset: 0, } } @@ -376,13 +383,48 @@ func (c *CommandBuilder) ShouldEventuallySucceed(timeout time.Duration) string { // SearchBuilder extends CommandBuilder with search-specific methods. type SearchBuilder struct { *CommandBuilder - queries map[string]string - limit int - offset int + names []string + versions []string + skillIDs []string + skillNames []string + locators []string + modules []string + limit int + offset int } -func (s *SearchBuilder) WithQuery(key, value string) *SearchBuilder { - s.queries[key] = value +func (s *SearchBuilder) WithName(name string) *SearchBuilder { + s.names = append(s.names, name) + + return s +} + +func (s *SearchBuilder) WithVersion(version string) *SearchBuilder { + s.versions = append(s.versions, version) + + return s +} + +func (s *SearchBuilder) WithSkillID(skillID string) *SearchBuilder { + s.skillIDs = append(s.skillIDs, skillID) + + return s +} + +func (s *SearchBuilder) WithSkillName(skillName string) *SearchBuilder { + s.skillNames = append(s.skillNames, skillName) + + return s +} + +func (s *SearchBuilder) WithLocator(locator string) *SearchBuilder { + s.locators = append(s.locators, locator) + + return s +} + +func (s *SearchBuilder) WithModule(module string) *SearchBuilder { + s.modules = append(s.modules, module) return s } @@ -406,9 +448,32 @@ func (s *SearchBuilder) WithArgs(args ...string) *SearchBuilder { } func (s *SearchBuilder) Execute() (string, error) { - // Build search arguments - for key, value := range s.queries { - s.args = append(s.args, "--query", fmt.Sprintf(`%s=%s`, key, value)) + // Clear existing arguments to prevent accumulation between test cases + s.args = nil + + // Build search arguments using new direct field flags + for _, name := range s.names { + s.args = append(s.args, "--name", name) + } + + for _, version := range s.versions { + s.args = append(s.args, "--version", version) + } + + for _, skillID := range s.skillIDs { + s.args = append(s.args, "--skill-id", skillID) + } + + for _, skillName := range s.skillNames { + s.args = append(s.args, "--skill", skillName) + } + + for _, locator := range s.locators { + s.args = append(s.args, "--locator", locator) + } + + for _, module := range s.modules { + s.args = append(s.args, "--module", module) } if s.limit > 0 { diff --git a/e2e/shared/utils/common.go b/e2e/shared/utils/common.go index faac21667..a45a7b8a4 100644 --- a/e2e/shared/utils/common.go +++ b/e2e/shared/utils/common.go @@ -167,14 +167,13 @@ func ResetSearchCommandState() { cmd.Flags().Set("limit", "100") cmd.Flags().Set("offset", "0") - // For the query flag, reset it by accessing the underlying value - if queryFlag := cmd.Flags().Lookup("query"); queryFlag != nil { - queryFlag.Changed = false - // Cast to the Query type and reset it - if queryValue, ok := queryFlag.Value.(*searchcmd.Query); ok { - *queryValue = searchcmd.Query{} - } - } + // Reset all string array flags + resetStringArrayFlag(cmd, "name") + resetStringArrayFlag(cmd, "version") + resetStringArrayFlag(cmd, "skill-id") + resetStringArrayFlag(cmd, "skill") + resetStringArrayFlag(cmd, "locator") + resetStringArrayFlag(cmd, "module") } }