From 066ecd0ee47305a92f390a2fded9aa3acb9615cd Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Thu, 13 Jun 2024 22:43:07 +0000 Subject: [PATCH] Add validators and improve validator testing The new validator will serve auto-generated resources based on formats specified in NSX spec Signed-off-by: Anna Khmelnitsky --- nsxt/validator_test.go | 162 +++++++++++++++++++++++++++++++++++++++++ nsxt/validators.go | 26 ++++++- 2 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 nsxt/validator_test.go diff --git a/nsxt/validator_test.go b/nsxt/validator_test.go new file mode 100644 index 000000000..64880b4ea --- /dev/null +++ b/nsxt/validator_test.go @@ -0,0 +1,162 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: MPL-2.0 */ + +package nsxt + +import ( + "testing" +) + +func TestValidateCidrOrIPOrRange(t *testing.T) { + + cases := map[string]struct { + value interface{} + result bool + }{ + "NotString": { + value: 777, + result: false, + }, + "Empty": { + value: "", + result: false, + }, + "IpRangeCidrMix": { + value: "1.1.1.1,3.3.3.0/25, 2.2.2.3-2.2.2.21", + result: false, + }, + "Range": { + value: "2.2.2.3 - 2.2.2.21", + result: true, + }, + "NotIP": { + value: "1.2.3.no", + result: false, + }, + "Text": { + value: "frog", + result: false, + }, + "ipv4": { + value: "192.218.3.1", + result: true, + }, + "ipv6": { + value: "1231:3213:abcd::15", + result: true, + }, + "withSpaces": { + value: "20.2.5.5 ", + result: true, + }, + } + + validator := validateCidrOrIPOrRange() + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + _, errors := validator(tc.value, tn) + + if len(errors) > 0 && tc.result { + t.Errorf("validateCidrOrIPOrRange (%s) produced an unexpected error %s", tc.value, errors) + } else if len(errors) == 0 && !tc.result { + t.Errorf("validateCidrOrIPOrRange (%s) did not error", tc.value) + } + }) + } +} + +func TestValidateCidrOrIPOrRangeList(t *testing.T) { + + cases := map[string]struct { + value interface{} + result bool + }{ + "NotString": { + value: 777, + result: false, + }, + "Empty": { + value: "", + result: false, + }, + "IpRangeCidrMix": { + value: "1.1.1.1,3.3.3.0/25, 2.2.2.3-2.2.2.21", + result: true, + }, + "NotIP": { + value: "1.2.3.no", + result: false, + }, + "Text": { + value: "frog", + result: false, + }, + "ipv6": { + value: "9870::2-9870::5, 1231:3213:abcd::15", + result: true, + }, + "ipVersionMix": { + value: "1.1.1.1,3.3.3.0/25, 2.2.2.3-2.2.2.21", + result: true, + }, + } + + validator := validateCidrOrIPOrRangeList() + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + _, errors := validator(tc.value, tn) + + if len(errors) > 0 && tc.result { + t.Errorf("validateCidrOrIPOrRangeList (%s) produced an unexpected error %s", tc.value, errors) + } else if len(errors) == 0 && !tc.result { + t.Errorf("validateCidrOrIPOrRangeList (%s) did not error", tc.value) + } + }) + } +} + +func TestValidateSingleIP(t *testing.T) { + + cases := map[string]struct { + value interface{} + result bool + }{ + "NotString": { + value: 777, + result: false, + }, + "Empty": { + value: "", + result: false, + }, + "ipv4": { + value: "192.218.3.1", + result: true, + }, + "ipv6": { + value: "1231:3213:abcd::15", + result: true, + }, + "withSpaces": { + value: "20.2.5.5 ", + result: true, + }, + "badIP": { + value: "192.278.3.1", + result: true, + }, + } + + validator := validateSingleIP() + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + _, errors := validator(tc.value, tn) + + if len(errors) > 0 && tc.result { + t.Errorf("validateSingleIP (%s) produced an unexpected error %s", tc.value, errors) + } else if len(errors) == 0 && !tc.result { + t.Errorf("validateSingleIP (%s) did not error", tc.value) + } + }) + } +} diff --git a/nsxt/validators.go b/nsxt/validators.go index 98e5f2732..0e86152e1 100644 --- a/nsxt/validators.go +++ b/nsxt/validators.go @@ -73,8 +73,8 @@ func isIPRange(v string) bool { if len(s) != 2 { return false } - ip1 := net.ParseIP(s[0]) - ip2 := net.ParseIP(s[1]) + ip1 := net.ParseIP(strings.TrimSpace(s[0])) + ip2 := net.ParseIP(strings.TrimSpace(s[1])) if ip1 == nil || ip2 == nil { return false } @@ -82,11 +82,13 @@ func isIPRange(v string) bool { } func isSingleIP(v string) bool { + v = strings.TrimSpace(v) ip := net.ParseIP(v) return ip != nil } func isCidr(v string, allowMaxPrefix bool, isIP bool) bool { + v = strings.TrimSpace(v) _, ipnet, err := net.ParseCIDR(v) if err != nil { return false @@ -142,6 +144,26 @@ func validateCidrOrIPOrRange() schema.SchemaValidateFunc { } } +func validateCidrOrIPOrRangeList() schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + tokens := strings.Split(v, ",") + for _, t := range tokens { + if !isCidr(t, true, false) && !isSingleIP(t) && !isIPRange(t) { + es = append(es, fmt.Errorf( + "expected %s to contain a list of valid CIDRs or IPs or Ranges, got: %s", k, t)) + return + } + } + return + } +} + func validateIPOrRange() schema.SchemaValidateFunc { return func(i interface{}, k string) (s []string, es []error) { v, ok := i.(string)