handler: tests for exec.Cmd and templating
This commit is contained in:
parent
315a334732
commit
26485ab1e8
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_runTemplate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Template *template.Template
|
||||||
|
Env TemplateEnv
|
||||||
|
Expected string
|
||||||
|
ShouldError bool
|
||||||
|
HandlerFunc func(t *testing.T, expected, actual string) bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Empty",
|
||||||
|
Template: s2t(""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "TextOnly",
|
||||||
|
Template: s2t("hello, this is a text only template"),
|
||||||
|
Expected: "hello, this is a text only template",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithEvent",
|
||||||
|
Template: s2t("{{.Event.Instance}}:{{.Event.State}}:{{.Event.Type}}"),
|
||||||
|
Expected: "foo_instance:MASTER:INSTANCE",
|
||||||
|
Env: TemplateEnv{
|
||||||
|
Event: MessageEvent{
|
||||||
|
Instance: "foo_instance",
|
||||||
|
Type: "INSTANCE",
|
||||||
|
State: "MASTER",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithCxt",
|
||||||
|
Template: s2t("{{.Cxt.key1}}:{{.Cxt.key2.subkey1}}:{{.Cxt.UpCase.Key}}"),
|
||||||
|
Expected: "value1:value2:value3",
|
||||||
|
Env: TemplateEnv{
|
||||||
|
Cxt: map[string]any{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": map[string]string{
|
||||||
|
"subkey1": "value2",
|
||||||
|
},
|
||||||
|
"UpCase": map[string]string{
|
||||||
|
"Key": "value3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithCxtAndEvent",
|
||||||
|
Template: s2t("{{.Event.Instance}}->{{.Cxt.key1}}:{{.Cxt.key2.subkey1}}:{{.Cxt.UpCase.Key}}"),
|
||||||
|
Expected: "baz_instance->value1:value2:value3",
|
||||||
|
Env: TemplateEnv{
|
||||||
|
Cxt: map[string]any{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": map[string]string{
|
||||||
|
"subkey1": "value2",
|
||||||
|
},
|
||||||
|
"UpCase": map[string]string{
|
||||||
|
"Key": "value3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Event: MessageEvent{
|
||||||
|
Instance: "baz_instance",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range cases {
|
||||||
|
test := test // Avoid closure capture by ref
|
||||||
|
tname := fmt.Sprintf("%s@%d:%d", test.Name, i+1, len(cases))
|
||||||
|
|
||||||
|
t.Run(tname, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if test.HandlerFunc == nil {
|
||||||
|
test.HandlerFunc = Noop[string]
|
||||||
|
if test.Expected != "" {
|
||||||
|
test.HandlerFunc = ExpectEqual[string]
|
||||||
|
if test.ShouldError {
|
||||||
|
test.HandlerFunc = ExpectNotEqual[string]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := runTemplate(test.Template, &test.Env)
|
||||||
|
if test.ShouldError && err != nil {
|
||||||
|
return
|
||||||
|
} else if assert.NoError(t, err) {
|
||||||
|
test.HandlerFunc(t, test.Expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_mkCmd(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Cmdline string
|
||||||
|
Expected *exec.Cmd
|
||||||
|
ShouldError bool
|
||||||
|
HandlerFunc func(t *testing.T, expected, actual *exec.Cmd) bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Empty",
|
||||||
|
Cmdline: "",
|
||||||
|
ShouldError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "CmdOnly",
|
||||||
|
Cmdline: "/bin/echo",
|
||||||
|
Expected: exec.Command("/bin/echo"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithArgsSimple",
|
||||||
|
Cmdline: "/bin/echo hello, world!",
|
||||||
|
Expected: exec.Command("/bin/echo", "hello,", "world!"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithArgsEscape",
|
||||||
|
Cmdline: `/bin/echo \$ESCAPED $VAR`,
|
||||||
|
Expected: exec.Command("/bin/echo", `$ESCAPED`, "$VAR"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WithArgsQuoted",
|
||||||
|
Cmdline: `/bin/echo "hello, world" ... 'these have spaces'`,
|
||||||
|
Expected: exec.Command("/bin/echo", "hello, world", "...", "these have spaces"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range cases {
|
||||||
|
test := test // Avoid closure capture by ref
|
||||||
|
tname := fmt.Sprintf("%s@%d:%d", test.Name, i+1, len(cases))
|
||||||
|
|
||||||
|
t.Run(tname, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if test.HandlerFunc == nil {
|
||||||
|
test.HandlerFunc = Noop[*exec.Cmd]
|
||||||
|
if test.Expected != nil {
|
||||||
|
test.HandlerFunc = ExpectEqual[*exec.Cmd]
|
||||||
|
if test.ShouldError {
|
||||||
|
test.HandlerFunc = ExpectNotEqual[*exec.Cmd]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := mkCmd(test.Cmdline)
|
||||||
|
if test.ShouldError && err != nil {
|
||||||
|
return
|
||||||
|
} else if assert.NoError(t, err) {
|
||||||
|
test.HandlerFunc(t, test.Expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExpectEqual[T any](t *testing.T, expected, actual T) bool {
|
||||||
|
return assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExpectNotEqual[T any](t *testing.T, expected, actual T) bool {
|
||||||
|
return assert.NotEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Noop[T any](_ *testing.T, _, _ T) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func s2t(s string) *template.Template {
|
||||||
|
return template.Must(template.New("TestHandler").Parse(s))
|
||||||
|
}
|
Loading…
Reference in New Issue