Skip to content

Commit

Permalink
add ReadDomainsOrIPsOrURLs
Browse files Browse the repository at this point in the history
  • Loading branch information
devang-gaur committed Dec 19, 2024
1 parent 7ee3c48 commit e53d9b7
Show file tree
Hide file tree
Showing 2 changed files with 289 additions and 0 deletions.
34 changes: 34 additions & 0 deletions prompts/prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,40 @@ func ReadDomainOrIPNoPort(label, defaultVal, errMsg string, optional bool) (stri
return s, nil
}

// ReadDomainsOrIPsOrURLs prompts the user to enter a comma-separated string of FQDNs or IPv4/IPv6
// addresses or URLs, optionally with a maximum number of values.
func ReadDomainsOrIPsOrURLs(label, defaultVal, errMsg string, optional bool, maxVals int) (string, error) {
validate := func(input string) error {
if input == "" {
if !optional {
return ErrInputMandatory
}
return nil
}
vals := strings.Split(input, ",")
if maxVals > 0 && len(vals) > maxVals {
return fmt.Errorf("%s: maximum domains or IPs or URLs: %d", errMsg, maxVals)
}
for _, v := range vals {
ip := net.ParseIP(v)
isIPWithPort := ipPortRegex.Match([]byte(v))
isDomain := domainRegex.Match([]byte(v)) && validateDomain(v)
isURL := validateURL(input, errMsg) == nil
if ip != nil || isIPWithPort || isDomain || isURL {
continue
}
return fmt.Errorf("%s: %s is neither an IP, IP:port, an FQDN, nor a URL", errMsg, v)
}
return nil
}

s, err := Tui.GetText(label, defaultVal, "", optional, validate)
if err != nil {
return s, errors.Wrap(err, "failure in ReadDomainsOrIPsOrURLs")
}
return s, nil
}

// ReadCIDRs prompts the user to enter a comma-separated string of CIDR blocks,
// optionally with a maximum number of values.
func ReadCIDRs(label, defaultVal, errMsg string, optional bool, maxVals int) (string, error) {
Expand Down
255 changes: 255 additions & 0 deletions prompts/prompts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,261 @@ func TestReadDomains(t *testing.T) {
}
}

func TestReadDomainsOrIPsOrURLs(t *testing.T) {
subtests := []struct {
name string
tui *mocks.MockTUI
errMsg string
isOptional bool
maxVals int
expectedData string
expectedErr error
}{
{
name: "TestURL (pass)",
tui: &mocks.MockTUI{
Values: []string{"https://foo.com"},
Errs: nil,
},
maxVals: 1,
expectedData: "https://foo.com",
expectedErr: nil,
},
{
name: "ReadURL (fail)",
tui: &mocks.MockTUI{
Values: []string{"https://foo.com"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
expectedData: "https://foo.com",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: fail"),
},
{
name: "ReadDomainsOrIPsOrURLs (fail non-url)",
tui: &mocks.MockTUI{
Values: []string{"fff"},
},
maxVals: 1,
expectedData: "fff",
expectedErr: errors.New(`failure in ReadDomainsOrIPsOrURLs: : fff is neither an IP, IP:port, an FQDN, nor a URL`),
},
{
name: "ReadURLSlice (fail_optional)",
tui: &mocks.MockTUI{
Values: []string{""},
Errs: nil,
},
maxVals: 1,
isOptional: false,
expectedData: "",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: input is mandatory"),
},
{
name: "ReadIP (IP pass)",
tui: &mocks.MockTUI{
Values: []string{"10.10.10.10"},
},
maxVals: 1,
expectedData: "10.10.10.10",
},
{
name: "ReadIP (IP fail)",
tui: &mocks.MockTUI{
Values: []string{"10.10.10.10.10"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
expectedData: "10.10.10.10.10",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: fail"),
},
{
name: "ReadURL (Domain pass basic)",
tui: &mocks.MockTUI{
Values: []string{"http://vcenter.spectrocloud.dev"},
},
maxVals: 1,
expectedData: "http://vcenter.spectrocloud.dev",
},
{
name: "ReadDomain (Domain pass basic)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.spectrocloud.dev"},
},
maxVals: 1,
expectedData: "vcenter.spectrocloud.dev",
},
{
name: "ReadDomain (Domain pass long)",
tui: &mocks.MockTUI{
Values: []string{"0.lab.vcenter.spectrocloud.dev"},
},
maxVals: 1,
expectedData: "0.lab.vcenter.spectrocloud.dev",
},
{
name: "ReadDomain (Domain pass long with dashes)",
tui: &mocks.MockTUI{
Values: []string{"0.lab.v-center.spectro-cloud.dev"},
},
maxVals: 1,
expectedData: "0.lab.v-center.spectro-cloud.dev",
},
{
name: "ReadDomain (Domain pass short)",
tui: &mocks.MockTUI{
Values: []string{"to.io"},
},
maxVals: 1,
expectedData: "to.io",
},
{
name: "ReadDomain (Domain pass dashes)",
tui: &mocks.MockTUI{
Values: []string{"ps-vcenter-02.ps.labs.local"},
},
maxVals: 1,
expectedData: "ps-vcenter-02.ps.labs.local",
},
{
name: "ReadDomains (Domain pass multiple sub-domains)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.spectrocloud.foo.bar.baz.dev"},
},
maxVals: 1,
expectedData: "vcenter.spectrocloud.foo.bar.baz.dev",
},
{
name: "ReadDomain (Domain fail leading dash)",
tui: &mocks.MockTUI{
Values: []string{"-vcenter.spectrocloud.dev"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "-vcenter.spectrocloud.dev",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: -vcenter.spectrocloud.dev is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomain (Domain fail trailing dash)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.spectrocloud.dev-"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "vcenter.spectrocloud.dev-",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: vcenter.spectrocloud.dev- is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomain (Domain fail consecutive dashes)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.spectro--cloud.dev"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "vcenter.spectro--cloud.dev",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: vcenter.spectro--cloud.dev is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomain (Domain fail dot dash)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.-spectrocloud.dev"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "vcenter.-spectrocloud.dev",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: vcenter.-spectrocloud.dev is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomain (Domain fail dash dot)",
tui: &mocks.MockTUI{
Values: []string{"vcenter-.spectrocloud.dev"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "vcenter-.spectrocloud.dev",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: vcenter-.spectrocloud.dev is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomain (Domain fail invalid char)",
tui: &mocks.MockTUI{
Values: []string{"vcenter.spectro*cloud.dev"},
Errs: []error{errors.New("fail")},
},
maxVals: 1,
errMsg: "invalid domain",
expectedData: "vcenter.spectro*cloud.dev",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domain: vcenter.spectro*cloud.dev is neither an IP, IP:port, an FQDN, nor a URL"),
},
{
name: "ReadDomainsOrIPsOrURLs (fail_optional)",
tui: &mocks.MockTUI{
Values: []string{""},
},
maxVals: 1,
isOptional: false,
errMsg: ErrInputMandatory.Error(),
expectedData: "",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: input is mandatory"),
},
{
name: "ReadDomainsOrIPsOrURLs (pass_max_vals)",
tui: &mocks.MockTUI{
Values: []string{"foo.com,bar.io,baz.ca"},
},
maxVals: 3,
isOptional: false,
expectedData: "foo.com,bar.io,baz.ca",
},
{
name: "ReadDomainsOrIPsOrURLs (fail_max_vals)",
tui: &mocks.MockTUI{
Values: []string{"foo.com,bar.io"},
},
maxVals: 1,
isOptional: false,
errMsg: "invalid domains or IPs",
expectedData: "foo.com,bar.io",
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: invalid domains or IPs: maximum domains or IPs or URLs: 1"),
},
{
name: "ReadDomainsOrIPsOrURLs (fail_extra)",
tui: &mocks.MockTUI{
Values: []string{"", ""},
Errs: []error{errors.New("fail")},
},
isOptional: true,
maxVals: 1,
expectedErr: errors.New("failure in ReadDomainsOrIPsOrURLs: fail"),
},
{
name: "ReadDomainsOrIPs (pass_spectro)",
tui: &mocks.MockTUI{
Values: []string{"spectrocloud.dev"},
},
maxVals: 1,
expectedData: "spectrocloud.dev",
},
}
for _, subtest := range subtests {
t.Run(subtest.name, func(t *testing.T) {
Tui = subtest.tui

data, err := ReadDomainsOrIPsOrURLs("", "", subtest.errMsg, subtest.isOptional, subtest.maxVals)
if !reflect.DeepEqual(data, subtest.expectedData) {
t.Errorf("expected (%s), got (%s)", subtest.expectedData, data)
}
if err != nil && err.Error() != subtest.expectedErr.Error() {
t.Errorf("expected error (%v), got error (%v)", subtest.expectedErr, err)
}
})
}
}

func TestReadDomainsOrIPs(t *testing.T) {
subtests := []struct {
name string
Expand Down

0 comments on commit e53d9b7

Please sign in to comment.