mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-29 23:30:04 +01:00
43fc1183b9
This makes test code more clear and reduces the number of code lines by 500.
This also simplifies debugging tests. See https://itnext.io/f-tests-as-a-replacement-for-table-driven-tests-in-go-8814a8b19e9e
While at it, consistently use t.Fatal* instead of t.Error* across tests, since t.Error*
requires more boilerplate code, which can result in additional bugs inside tests.
While t.Error* allows writing logging errors for the same, this doesn't simplify fixing
broken tests most of the time.
This is a follow-up for a9525da8a4
349 lines
9.1 KiB
Go
349 lines
9.1 KiB
Go
package templates
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
textTpl "text/template"
|
|
)
|
|
|
|
func TestTemplateFuncs_StringConversion(t *testing.T) {
|
|
f := func(funcName, s, resultExpected string) {
|
|
t.Helper()
|
|
|
|
funcs := templateFuncs()
|
|
v := funcs[funcName]
|
|
fLocal := v.(func(s string) string)
|
|
result := fLocal(s)
|
|
if result != resultExpected {
|
|
t.Fatalf("unexpected result for %s(%q); got\n%s\nwant\n%s", funcName, s, result, resultExpected)
|
|
}
|
|
}
|
|
|
|
f("title", "foo bar", "Foo Bar")
|
|
f("toUpper", "foo", "FOO")
|
|
f("toLower", "FOO", "foo")
|
|
f("pathEscape", "foo/bar\n+baz", "foo%2Fbar%0A+baz")
|
|
f("queryEscape", "foo+bar\n+baz", "foo%2Bbar%0A%2Bbaz")
|
|
f("jsonEscape", `foo{bar="baz"}`+"\n + 1", `"foo{bar=\"baz\"}\n + 1"`)
|
|
f("quotesEscape", `foo{bar="baz"}`+"\n + 1", `foo{bar=\"baz\"}\n + 1`)
|
|
f("htmlEscape", "foo < 10\nabc", "foo < 10\nabc")
|
|
f("crlfEscape", "foo\nbar\rx", `foo\nbar\rx`)
|
|
f("stripPort", "foo", "foo")
|
|
f("stripPort", "foo:1234", "foo")
|
|
f("stripDomain", "foo.bar.baz", "foo")
|
|
f("stripDomain", "foo.bar:123", "foo:123")
|
|
}
|
|
|
|
func TestTemplateFuncs_Match(t *testing.T) {
|
|
funcs := templateFuncs()
|
|
// check "match" func
|
|
matchFunc := funcs["match"].(func(pattern, s string) (bool, error))
|
|
if _, err := matchFunc("invalid[regexp", "abc"); err == nil {
|
|
t.Fatalf("expecting non-nil error on invalid regexp")
|
|
}
|
|
ok, err := matchFunc("abc", "def")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error")
|
|
}
|
|
if ok {
|
|
t.Fatalf("unexpected match")
|
|
}
|
|
ok, err = matchFunc("a.+b", "acsdb")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error")
|
|
}
|
|
if !ok {
|
|
t.Fatalf("unexpected mismatch")
|
|
}
|
|
}
|
|
|
|
func TestTemplateFuncs_Formatting(t *testing.T) {
|
|
f := func(funcName string, p any, resultExpected string) {
|
|
t.Helper()
|
|
|
|
funcs := templateFuncs()
|
|
v := funcs[funcName]
|
|
fLocal := v.(func(s any) (string, error))
|
|
result, err := fLocal(p)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error for %s(%f): %s", funcName, p, err)
|
|
}
|
|
if result != resultExpected {
|
|
t.Fatalf("unexpected result for %s(%f); got\n%s\nwant\n%s", funcName, p, result, resultExpected)
|
|
}
|
|
}
|
|
|
|
f("humanize1024", float64(0), "0")
|
|
f("humanize1024", math.Inf(0), "+Inf")
|
|
f("humanize1024", math.NaN(), "NaN")
|
|
f("humanize1024", float64(127087), "124.1ki")
|
|
f("humanize1024", float64(130137088), "124.1Mi")
|
|
f("humanize1024", float64(133260378112), "124.1Gi")
|
|
f("humanize1024", float64(136458627186688), "124.1Ti")
|
|
f("humanize1024", float64(139733634239168512), "124.1Pi")
|
|
f("humanize1024", float64(143087241460908556288), "124.1Ei")
|
|
f("humanize1024", float64(146521335255970361638912), "124.1Zi")
|
|
f("humanize1024", float64(150037847302113650318245888), "124.1Yi")
|
|
f("humanize1024", float64(153638755637364377925883789312), "1.271e+05Yi")
|
|
|
|
f("humanize", float64(127087), "127.1k")
|
|
f("humanize", float64(136458627186688), "136.5T")
|
|
|
|
f("humanizeDuration", 1, "1s")
|
|
f("humanizeDuration", 0.2, "200ms")
|
|
f("humanizeDuration", 42000, "11h 40m 0s")
|
|
f("humanizeDuration", 16790555, "194d 8h 2m 35s")
|
|
|
|
f("humanizePercentage", 1, "100%")
|
|
f("humanizePercentage", 0.8, "80%")
|
|
f("humanizePercentage", 0.015, "1.5%")
|
|
|
|
f("humanizeTimestamp", 1679055557, "2023-03-17 12:19:17 +0000 UTC")
|
|
}
|
|
|
|
func mkTemplate(current, replacement any) textTemplate {
|
|
tmpl := textTemplate{}
|
|
if current != nil {
|
|
switch val := current.(type) {
|
|
case string:
|
|
tmpl.current = textTpl.Must(newTemplate().Parse(val))
|
|
}
|
|
}
|
|
if replacement != nil {
|
|
switch val := replacement.(type) {
|
|
case string:
|
|
tmpl.replacement = textTpl.Must(newTemplate().Parse(val))
|
|
}
|
|
}
|
|
return tmpl
|
|
}
|
|
|
|
func equalTemplates(tmpls ...*textTpl.Template) bool {
|
|
var cmp *textTpl.Template
|
|
for i, tmpl := range tmpls {
|
|
if i == 0 {
|
|
cmp = tmpl
|
|
} else {
|
|
if cmp == nil || tmpl == nil {
|
|
if cmp != tmpl {
|
|
return false
|
|
}
|
|
continue
|
|
}
|
|
if len(tmpl.Templates()) != len(cmp.Templates()) {
|
|
return false
|
|
}
|
|
for _, t := range tmpl.Templates() {
|
|
tp := cmp.Lookup(t.Name())
|
|
if tp == nil {
|
|
return false
|
|
}
|
|
if tp.Root.String() != t.Root.String() {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func TestTemplatesLoad_Failure(t *testing.T) {
|
|
f := func(pathPatterns []string, expectedErrStr string) {
|
|
t.Helper()
|
|
|
|
err := Load(pathPatterns, false)
|
|
if err == nil {
|
|
t.Fatalf("expecting non-nil error")
|
|
}
|
|
|
|
errStr := err.Error()
|
|
if !strings.Contains(errStr, expectedErrStr) {
|
|
t.Fatalf("the returned error %q doesn't contain %q", errStr, expectedErrStr)
|
|
}
|
|
}
|
|
|
|
// load template with syntax error
|
|
f([]string{
|
|
"templates/other/nested/bad0-*.tpl",
|
|
"templates/test/good0-*.tpl",
|
|
}, "failed to parse template glob")
|
|
}
|
|
|
|
func TestTemplatesLoad_Success(t *testing.T) {
|
|
f := func(initialTmpl textTemplate, pathPatterns []string, overwrite bool, expectedTmpl textTemplate) {
|
|
t.Helper()
|
|
|
|
masterTmplOrig := masterTmpl
|
|
masterTmpl = initialTmpl
|
|
defer func() {
|
|
masterTmpl = masterTmplOrig
|
|
}()
|
|
|
|
if err := Load(pathPatterns, overwrite); err != nil {
|
|
t.Fatalf("cannot load templates: %s", err)
|
|
}
|
|
|
|
if !equalTemplates(masterTmpl.replacement, expectedTmpl.replacement) {
|
|
t.Fatalf("unexpected replacement template\ngot\n%+v\nwant\n%+v", masterTmpl.replacement, expectedTmpl.replacement)
|
|
}
|
|
if !equalTemplates(masterTmpl.current, expectedTmpl.current) {
|
|
t.Fatalf("unexpected current template\ngot\n%+v\nwant\n%+v", masterTmpl.current, expectedTmpl.current)
|
|
}
|
|
}
|
|
|
|
// non existing path undefined template override
|
|
initialTmpl := mkTemplate(nil, nil)
|
|
pathPatterns := []string{
|
|
"templates/non-existing/good-*.tpl",
|
|
"templates/absent/good-*.tpl",
|
|
}
|
|
overwrite := true
|
|
expectedTmpl := mkTemplate(``, nil)
|
|
f(initialTmpl, pathPatterns, overwrite, expectedTmpl)
|
|
|
|
// non existing path defined template override
|
|
initialTmpl = mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
`, nil)
|
|
pathPatterns = []string{
|
|
"templates/non-existing/good-*.tpl",
|
|
"templates/absent/good-*.tpl",
|
|
}
|
|
overwrite = true
|
|
expectedTmpl = mkTemplate(``, nil)
|
|
f(initialTmpl, pathPatterns, overwrite, expectedTmpl)
|
|
|
|
// existing path undefined template override
|
|
initialTmpl = mkTemplate(nil, nil)
|
|
pathPatterns = []string{
|
|
"templates/other/nested/good0-*.tpl",
|
|
"templates/test/good0-*.tpl",
|
|
}
|
|
overwrite = false
|
|
expectedTmpl = mkTemplate(`
|
|
{{- define "good0-test.tpl" -}}{{- end -}}
|
|
{{- define "test.0" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.1" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.2" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.3" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
`, nil)
|
|
f(initialTmpl, pathPatterns, overwrite, expectedTmpl)
|
|
|
|
// existing path defined template override
|
|
initialTmpl = mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{ printf "Hello %s!" "world" }}
|
|
{{- end -}}
|
|
`, nil)
|
|
pathPatterns = []string{
|
|
"templates/other/nested/good0-*.tpl",
|
|
"templates/test/good0-*.tpl",
|
|
}
|
|
overwrite = false
|
|
expectedTmpl = mkTemplate(`
|
|
{{- define "good0-test.tpl" -}}{{- end -}}
|
|
{{- define "test.0" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.1" -}}
|
|
{{ printf "Hello %s!" "world" }}
|
|
{{- end -}}
|
|
{{- define "test.2" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.3" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
`, `
|
|
{{- define "good0-test.tpl" -}}{{- end -}}
|
|
{{- define "test.0" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.1" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.2" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
{{- define "test.3" -}}
|
|
{{ printf "Hello %s!" externalURL }}
|
|
{{- end -}}
|
|
`)
|
|
f(initialTmpl, pathPatterns, overwrite, expectedTmpl)
|
|
}
|
|
|
|
func TestTemplatesReload(t *testing.T) {
|
|
f := func(initialTmpl, expectedTmpl textTemplate) {
|
|
t.Helper()
|
|
|
|
masterTmplOrig := masterTmpl
|
|
masterTmpl = initialTmpl
|
|
defer func() {
|
|
masterTmpl = masterTmplOrig
|
|
}()
|
|
|
|
Reload()
|
|
|
|
if !equalTemplates(masterTmpl.replacement, expectedTmpl.replacement) {
|
|
t.Fatalf("unexpected replacement template\ngot\n%+v\nwant\n%+v", masterTmpl.replacement, expectedTmpl.replacement)
|
|
}
|
|
if !equalTemplates(masterTmpl.current, expectedTmpl.current) {
|
|
t.Fatalf("unexpected current template\ngot\n%+v\nwant\n%+v", masterTmpl.current, expectedTmpl.current)
|
|
}
|
|
}
|
|
|
|
// empty current and replacement templates
|
|
f(mkTemplate(nil, nil), mkTemplate(nil, nil))
|
|
|
|
// empty current template only
|
|
f(mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
`, nil), mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
`, nil))
|
|
|
|
// empty replacement template only
|
|
f(mkTemplate(nil, `
|
|
{{- define "test.1" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
`), mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
`, nil))
|
|
|
|
// defined both templates
|
|
f(mkTemplate(`
|
|
{{- define "test.0" -}}
|
|
{{- printf "value" -}}
|
|
{{- end -}}
|
|
{{- define "test.1" -}}
|
|
{{- printf "before" -}}
|
|
{{- end -}}
|
|
`, `
|
|
{{- define "test.1" -}}
|
|
{{- printf "after" -}}
|
|
{{- end -}}
|
|
`), mkTemplate(`
|
|
{{- define "test.1" -}}
|
|
{{- printf "after" -}}
|
|
{{- end -}}
|
|
`, nil))
|
|
}
|