mirror of https://github.com/linkerd/linkerd2.git
389 lines
8.3 KiB
Go
389 lines
8.3 KiB
Go
package cmd
|
||
|
||
import (
|
||
"bytes"
|
||
"errors"
|
||
"path/filepath"
|
||
"reflect"
|
||
"testing"
|
||
|
||
"k8s.io/utils/exec"
|
||
fakeexec "k8s.io/utils/exec/testing"
|
||
)
|
||
|
||
func TestFindExtensions(t *testing.T) {
|
||
fakeGlob := func(path string) ([]string, error) {
|
||
dir, _ := filepath.Split(path)
|
||
return []string{
|
||
filepath.Join(dir, "linkerd-bar"),
|
||
filepath.Join(dir, "linkerd-baz"),
|
||
filepath.Join(dir, "linkerd-foo"),
|
||
}, nil
|
||
}
|
||
|
||
fcmd := fakeexec.FakeCmd{
|
||
RunScript: []fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(`{"name":"linkerd-baz","checks":"always"}`), nil, nil
|
||
},
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(`{"name":"linkerd-foo-no-match","checks":"always"}`), nil, nil
|
||
},
|
||
func() ([]byte, []byte, error) { return []byte(`{"name":"linkerd-bar","checks":"always"}`), nil, nil },
|
||
},
|
||
}
|
||
|
||
lookPathSuccess := false
|
||
|
||
fexec := &fakeexec.FakeExec{
|
||
CommandScript: []fakeexec.FakeCommandAction{
|
||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
|
||
},
|
||
LookPathFunc: func(cmd string) (string, error) {
|
||
if lookPathSuccess {
|
||
return cmd, nil
|
||
}
|
||
lookPathSuccess = true
|
||
return "", errors.New("fake-error")
|
||
},
|
||
}
|
||
|
||
extensions, missing := findExtensions("/path1:/this/is/a/fake/path2", fakeGlob, fexec, []string{"foo", "missing-cli"})
|
||
|
||
expExtensions := []extension{
|
||
{path: "/this/is/a/fake/path2/linkerd-bar"},
|
||
{path: "/path1/linkerd-baz"},
|
||
{path: "/path1/linkerd-foo"},
|
||
}
|
||
expMissing := []string{"linkerd-missing-cli"}
|
||
|
||
if !reflect.DeepEqual(expExtensions, extensions) {
|
||
t.Errorf("Expected [%+v] Got [%+v]", expExtensions, extensions)
|
||
}
|
||
if !reflect.DeepEqual(expMissing, missing) {
|
||
t.Errorf("Expected [%+v] Got [%+v]", expMissing, missing)
|
||
}
|
||
}
|
||
|
||
func TestRunExtensionsChecks(t *testing.T) {
|
||
successJSON := `
|
||
{
|
||
"success": true,
|
||
"categories": [
|
||
{
|
||
"categoryName": "success check name",
|
||
"checks": [
|
||
{
|
||
"description": "success check desc",
|
||
"result": "success"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
`
|
||
|
||
warningJSON := `
|
||
{
|
||
"success": true,
|
||
"categories": [
|
||
{
|
||
"categoryName": "warning check name",
|
||
"checks": [
|
||
{
|
||
"description": "warning check desc",
|
||
"hint": "https://example.com/warning",
|
||
"error": "this is the warning message",
|
||
"result": "warning"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
`
|
||
|
||
errorJSON := `
|
||
{
|
||
"success": false,
|
||
"categories": [
|
||
{
|
||
"categoryName": "error check name",
|
||
"checks": [
|
||
{
|
||
"description": "error check desc",
|
||
"hint": "https://example.com/error",
|
||
"error": "this is the error message",
|
||
"result": "error"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
`
|
||
|
||
multiJSON := `
|
||
{
|
||
"success": true,
|
||
"categories": [
|
||
{
|
||
"categoryName": "multi check name",
|
||
"checks": [
|
||
{
|
||
"description": "multi check desc success",
|
||
"result": "success"
|
||
},
|
||
{
|
||
"description": "multi check desc warning",
|
||
"hint": "https://example.com/multi",
|
||
"error": "this is the multi warning message",
|
||
"result": "warning"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
`
|
||
|
||
testCases := []struct {
|
||
name string
|
||
extensions []extension
|
||
missing []string
|
||
fakeActions []fakeexec.FakeAction
|
||
expSuccess bool
|
||
expWarning bool
|
||
expOutput string
|
||
}{
|
||
{
|
||
"no checks",
|
||
nil,
|
||
nil,
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return nil, nil, nil
|
||
},
|
||
},
|
||
true,
|
||
false,
|
||
"",
|
||
},
|
||
{
|
||
"invalid JSON",
|
||
[]extension{{path: "/path/linkerd-invalid"}},
|
||
nil,
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte("bad json"), nil, nil
|
||
},
|
||
},
|
||
false,
|
||
false,
|
||
`linkerd-invalid
|
||
---------------
|
||
× Running: /path/linkerd-invalid check
|
||
invalid extension check output from "/path/linkerd-invalid check" (JSON object expected):
|
||
bad json
|
||
[invalid character 'b' looking for beginning of value]
|
||
see https://linkerd.io/2/checks/#extensions for hints
|
||
|
||
`,
|
||
},
|
||
{
|
||
"one successful check",
|
||
[]extension{{path: "/path/linkerd-success"}},
|
||
nil,
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(successJSON), nil, nil
|
||
},
|
||
},
|
||
true,
|
||
false,
|
||
`success check name
|
||
------------------
|
||
√ success check desc
|
||
|
||
`,
|
||
},
|
||
{
|
||
"one warning check",
|
||
[]extension{{path: "/path/linkerd-warning"}},
|
||
nil,
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(warningJSON), nil, nil
|
||
},
|
||
},
|
||
true,
|
||
true,
|
||
`warning check name
|
||
------------------
|
||
‼ warning check desc
|
||
this is the warning message
|
||
see https://example.com/warning for hints
|
||
|
||
`,
|
||
},
|
||
{
|
||
"one error check",
|
||
[]extension{{path: "/path/linkerd-error"}},
|
||
nil,
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(errorJSON), nil, nil
|
||
},
|
||
},
|
||
false,
|
||
false,
|
||
`error check name
|
||
----------------
|
||
× error check desc
|
||
this is the error message
|
||
see https://example.com/error for hints
|
||
|
||
`,
|
||
},
|
||
{
|
||
"one missing check",
|
||
nil,
|
||
[]string{"missing"},
|
||
nil,
|
||
true,
|
||
true,
|
||
`missing
|
||
-------
|
||
‼ Linkerd extension command missing exists
|
||
exec: "missing": executable file not found in $PATH
|
||
see https://linkerd.io/2/checks/#extensions for hints
|
||
|
||
`,
|
||
},
|
||
{
|
||
"multiple checks with success, warnings, errors, and missing",
|
||
[]extension{{path: "/path/linkerd-success"}, {path: "/path/linkerd-warning"}, {path: "/path/linkerd-error"}, {path: "/path/linkerd-multi"}},
|
||
[]string{"missing1", "missing2"},
|
||
[]fakeexec.FakeAction{
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(successJSON), nil, nil
|
||
},
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(warningJSON), nil, nil
|
||
},
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(errorJSON), nil, nil
|
||
},
|
||
func() ([]byte, []byte, error) {
|
||
return []byte(multiJSON), nil, nil
|
||
},
|
||
},
|
||
false,
|
||
true,
|
||
`success check name
|
||
------------------
|
||
√ success check desc
|
||
|
||
warning check name
|
||
------------------
|
||
‼ warning check desc
|
||
this is the warning message
|
||
see https://example.com/warning for hints
|
||
|
||
error check name
|
||
----------------
|
||
× error check desc
|
||
this is the error message
|
||
see https://example.com/error for hints
|
||
|
||
multi check name
|
||
----------------
|
||
√ multi check desc success
|
||
‼ multi check desc warning
|
||
this is the multi warning message
|
||
see https://example.com/multi for hints
|
||
|
||
missing1
|
||
--------
|
||
‼ Linkerd extension command missing1 exists
|
||
exec: "missing1": executable file not found in $PATH
|
||
see https://linkerd.io/2/checks/#extensions for hints
|
||
|
||
missing2
|
||
--------
|
||
‼ Linkerd extension command missing2 exists
|
||
exec: "missing2": executable file not found in $PATH
|
||
see https://linkerd.io/2/checks/#extensions for hints
|
||
|
||
`,
|
||
},
|
||
}
|
||
|
||
for _, tc := range testCases {
|
||
tc := tc // pin
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
fcmd := fakeexec.FakeCmd{
|
||
RunScript: tc.fakeActions,
|
||
}
|
||
|
||
fakeCommandActions := make([]fakeexec.FakeCommandAction, len(tc.fakeActions))
|
||
for i := 0; i < len(tc.fakeActions); i++ {
|
||
fakeCommandActions[i] = func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }
|
||
}
|
||
fexec := &fakeexec.FakeExec{
|
||
CommandScript: fakeCommandActions,
|
||
}
|
||
|
||
var stdout, stderr bytes.Buffer
|
||
success, warning := runExtensionsChecks(&stdout, &stderr, tc.extensions, tc.missing, fexec, nil, "")
|
||
if tc.expSuccess != success {
|
||
t.Errorf("Expected success to be %t, got %t", tc.expSuccess, success)
|
||
}
|
||
if tc.expWarning != warning {
|
||
t.Errorf("Expected warning to be %t, got %t", tc.expWarning, warning)
|
||
}
|
||
output := stdout.String()
|
||
if tc.expOutput != output {
|
||
t.Errorf("Expected output to be:\n%s\nGot:\n%s", tc.expOutput, output)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestSuffix(t *testing.T) {
|
||
testCases := []*struct {
|
||
testName string
|
||
input string
|
||
exp string
|
||
}{
|
||
{
|
||
"empty",
|
||
"",
|
||
"",
|
||
},
|
||
{
|
||
"no path",
|
||
"linkerd-foo",
|
||
"foo",
|
||
},
|
||
{
|
||
"extra dash",
|
||
"linkerd-foo-bar",
|
||
"foo-bar",
|
||
},
|
||
{
|
||
"with path",
|
||
"/tmp/linkerd-foo",
|
||
"foo",
|
||
},
|
||
}
|
||
for _, tc := range testCases {
|
||
tc := tc // pin
|
||
t.Run(tc.testName, func(t *testing.T) {
|
||
result := suffix(tc.input)
|
||
if !reflect.DeepEqual(tc.exp, result) {
|
||
t.Fatalf("Expected [%s] Got [%s]", tc.exp, result)
|
||
}
|
||
})
|
||
}
|
||
}
|