Skip to content

Commit

Permalink
Add string comparison functions to Go template executors (#4560)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianyong authored Nov 7, 2023
1 parent 14673e9 commit 9a52e02
Show file tree
Hide file tree
Showing 5 changed files with 393 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,15 @@ If you'd like to use custom annotations with Mergeable Ingress resources, please
Helper functions can be used in the Ingress template to parse the values of custom annotations.
{{% table %}}
|Function | Input Arguments | Return Arguments | Description |
| Function | Input Arguments | Return Arguments | Description |
| ---| ---| ---| --- |
|``split`` | ``s, sep string`` | ``[]string`` | Splits the string ``s`` into a slice of strings separated by the ``sep``. |
|``trim`` | ``s string`` | ``string`` | Trims the trailing and leading whitespace from the string ``s``. |
| ``split`` | ``s, sep string`` | ``[]string`` | Splits the string ``s`` into a slice of strings separated by the ``sep``. |
| ``trim`` | ``s string`` | ``string`` | Trims the trailing and leading whitespace from the string ``s``. |
| ``contains`` | ``s, substr string`` | ``bool`` | Tests whether the string ``substr`` is a substring of the string ``s``. |
| ``hasPrefix`` | ``s, prefix string`` | ``bool`` | Tests whether the string ``prefix`` is a prefix of the string ``s``. |
| ``hasSuffix`` | ``s, suffix string`` | ``bool`` | Tests whether the string ``suffix`` is a suffix of the string ``s``. |
| ``toLower`` | ``s string`` | ``bool`` | Converts all letters in the string ``s`` to their lower case. |
| ``toUpper`` | ``s string`` | ``bool`` | Converts all letters in the string ``s`` to their upper case. |
{{% /table %}}
Consider the following custom annotation `custom.nginx.org/allowed-ips`, which expects a comma-separated list of IP addresses:
Expand Down
5 changes: 5 additions & 0 deletions internal/configs/version1/template_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,10 @@ func makePathWithRegex(path, regexType string) string {
var helperFunctions = template.FuncMap{
"split": split,
"trim": trim,
"contains": strings.Contains,
"hasPrefix": strings.HasPrefix,
"hasSuffix": strings.HasSuffix,
"toLower": strings.ToLower,
"toUpper": strings.ToUpper,
"makeLocationPath": makeLocationPath,
}
184 changes: 184 additions & 0 deletions internal/configs/version1/template_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,145 @@ func TestTrimWhiteSpaceFromInputString(t *testing.T) {
}
}

func TestContainsSubstring(t *testing.T) {
t.Parallel()

tmpl := newContainsTemplate(t)
testCases := []struct {
InputString string
Substring string
expected string
}{
{InputString: "foo", Substring: "foo", expected: "true"},
{InputString: "foobar", Substring: "foo", expected: "true"},
{InputString: "foo", Substring: "", expected: "true"},
{InputString: "foo", Substring: "bar", expected: "false"},
{InputString: "foo", Substring: "foobar", expected: "false"},
{InputString: "", Substring: "foo", expected: "false"},
}

for _, tc := range testCases {
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc)
if err != nil {
t.Fatalf("Failed to execute the template %v", err)
}
if buf.String() != tc.expected {
t.Errorf("Template generated wrong config, got %v but expected %v.", buf.String(), tc.expected)
}
}
}

func TestHasPrefix(t *testing.T) {
t.Parallel()

tmpl := newHasPrefixTemplate(t)
testCases := []struct {
InputString string
Prefix string
expected string
}{
{InputString: "foo", Prefix: "foo", expected: "true"},
{InputString: "foo", Prefix: "f", expected: "true"},
{InputString: "foo", Prefix: "", expected: "true"},
{InputString: "foo", Prefix: "oo", expected: "false"},
{InputString: "foo", Prefix: "bar", expected: "false"},
{InputString: "foo", Prefix: "foobar", expected: "false"},
}

for _, tc := range testCases {
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc)
if err != nil {
t.Fatalf("Failed to execute the template %v", err)
}
if buf.String() != tc.expected {
t.Errorf("Template generated wrong config, got %v but expected %v.", buf.String(), tc.expected)
}
}
}

func TestHasSuffix(t *testing.T) {
t.Parallel()

tmpl := newHasSuffixTemplate(t)
testCases := []struct {
InputString string
Suffix string
expected string
}{
{InputString: "bar", Suffix: "bar", expected: "true"},
{InputString: "bar", Suffix: "r", expected: "true"},
{InputString: "bar", Suffix: "", expected: "true"},
{InputString: "bar", Suffix: "ba", expected: "false"},
{InputString: "bar", Suffix: "foo", expected: "false"},
{InputString: "bar", Suffix: "foobar", expected: "false"},
}

for _, tc := range testCases {
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc)
if err != nil {
t.Fatalf("Failed to execute the template %v", err)
}
if buf.String() != tc.expected {
t.Errorf("Template generated wrong config, got %v but expected %v.", buf.String(), tc.expected)
}
}
}

func TestToLowerInputString(t *testing.T) {
t.Parallel()

tmpl := newToLowerTemplate(t)
testCases := []struct {
InputString string
expected string
}{
{InputString: "foobar", expected: "foobar"},
{InputString: "FOOBAR", expected: "foobar"},
{InputString: "fOoBaR", expected: "foobar"},
{InputString: "", expected: ""},
}

for _, tc := range testCases {
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc)
if err != nil {
t.Fatalf("Failed to execute the template %v", err)
}
if buf.String() != tc.expected {
t.Errorf("Template generated wrong config, got %v but expected %v.", buf.String(), tc.expected)
}
}
}

func TestToUpperInputString(t *testing.T) {
t.Parallel()

tmpl := newToUpperTemplate(t)
testCases := []struct {
InputString string
expected string
}{
{InputString: "foobar", expected: "FOOBAR"},
{InputString: "FOOBAR", expected: "FOOBAR"},
{InputString: "fOoBaR", expected: "FOOBAR"},
{InputString: "", expected: ""},
}

for _, tc := range testCases {
var buf bytes.Buffer
err := tmpl.Execute(&buf, tc)
if err != nil {
t.Fatalf("Failed to execute the template %v", err)
}
if buf.String() != tc.expected {
t.Errorf("Template generated wrong config, got %v but expected %v.", buf.String(), tc.expected)
}
}
}

func newSplitTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{range $n := split . ","}}{{$n}} {{end}}`)
Expand All @@ -291,3 +430,48 @@ func newTrimTemplate(t *testing.T) *template.Template {
}
return tmpl
}

func newContainsTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{contains .InputString .Substring}}`)
if err != nil {
t.Fatalf("Failed to parse template: %v", err)
}
return tmpl
}

func newHasPrefixTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{hasPrefix .InputString .Prefix}}`)
if err != nil {
t.Fatalf("Failed to parse template: %v", err)
}
return tmpl
}

func newHasSuffixTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{hasSuffix .InputString .Suffix}}`)
if err != nil {
t.Fatalf("Failed to parse template: %v", err)
}
return tmpl
}

func newToLowerTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{toLower .InputString}}`)
if err != nil {
t.Fatalf("Failed to parse template: %v", err)
}
return tmpl
}

func newToUpperTemplate(t *testing.T) *template.Template {
t.Helper()
tmpl, err := template.New("testTemplate").Funcs(helperFunctions).Parse(`{{toUpper .InputString}}`)
if err != nil {
t.Fatalf("Failed to parse template: %v", err)
}
return tmpl
}
15 changes: 5 additions & 10 deletions internal/configs/version2/template_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@ func hasCIKey(key string, d map[string]string) bool {
return ok
}

// toLower takes a string and make it lowercase.
//
// Example:
//
// {{ if .SameSite}} samesite={{.SameSite | toLower }}{{ end }}
func toLower(s string) string {
return strings.ToLower(s)
}

var helperFunctions = template.FuncMap{
"headerListToCIMap": headerListToCIMap,
"hasCIKey": hasCIKey,
"toLower": toLower,
"contains": strings.Contains,
"hasPrefix": strings.HasPrefix,
"hasSuffix": strings.HasSuffix,
"toLower": strings.ToLower,
"toUpper": strings.ToUpper,
}
Loading

0 comments on commit 9a52e02

Please sign in to comment.