extract kubeconfig test utils to a type

Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
Ahmet Alp Balkan 2020-04-16 21:00:00 -07:00
parent 49539fbcb3
commit 7b96a338a3
No known key found for this signature in database
GPG Key ID: 441833503E604E2C
10 changed files with 95 additions and 96 deletions

View File

@ -8,22 +8,9 @@ import (
"testing"
"github.com/ahmetb/kubectx/internal/kubeconfig"
"github.com/ahmetb/kubectx/internal/testutil"
)
func withTestVar(key, value string) func() {
// TODO(ahmetb) this method is currently duplicated
// consider extracting to internal/testutil or something
orig, ok := os.LookupEnv(key)
os.Setenv(key, value)
return func() {
if ok {
os.Setenv(key, orig)
} else {
os.Unsetenv(key)
}
}
}
func Test_homeDir(t *testing.T) {
type env struct{ k, v string }
@ -72,7 +59,7 @@ func Test_homeDir(t *testing.T) {
t.Run(c.name, func(tt *testing.T) {
var unsets []func()
for _, e := range c.envs {
unsets = append(unsets, withTestVar(e.k, e.v))
unsets = append(unsets, testutil.WithEnvVar(e.k, e.v))
}
got := homeDir()
@ -87,7 +74,7 @@ func Test_homeDir(t *testing.T) {
}
func Test_kubeconfigPath(t *testing.T) {
defer withTestVar("HOME", "/x/y/z")()
defer testutil.WithEnvVar("HOME", "/x/y/z")()
expected := filepath.FromSlash("/x/y/z/.kube/config")
got, err := kubeconfigPath()
@ -100,9 +87,9 @@ func Test_kubeconfigPath(t *testing.T) {
}
func Test_kubeconfigPath_noEnvVars(t *testing.T) {
defer withTestVar("XDG_CACHE_HOME", "")()
defer withTestVar("HOME", "")()
defer withTestVar("USERPROFILE", "")()
defer testutil.WithEnvVar("XDG_CACHE_HOME", "")()
defer testutil.WithEnvVar("HOME", "")()
defer testutil.WithEnvVar("USERPROFILE", "")()
_, err := kubeconfigPath()
if err == nil {
@ -111,7 +98,7 @@ func Test_kubeconfigPath_noEnvVars(t *testing.T) {
}
func Test_kubeconfigPath_envOvveride(t *testing.T) {
defer withTestVar("KUBECONFIG", "foo")()
defer testutil.WithEnvVar("KUBECONFIG", "foo")()
v, err := kubeconfigPath()
if err != nil {
@ -124,7 +111,7 @@ func Test_kubeconfigPath_envOvveride(t *testing.T) {
func Test_kubeconfigPath_envOvverideDoesNotSupportPathSeparator(t *testing.T) {
path := strings.Join([]string{"file1", "file2"}, string(os.PathListSeparator))
defer withTestVar("KUBECONFIG", path)()
defer testutil.WithEnvVar("KUBECONFIG", path)()
_, err := kubeconfigPath()
if err == nil {
@ -133,7 +120,7 @@ func Test_kubeconfigPath_envOvverideDoesNotSupportPathSeparator(t *testing.T) {
}
func TestStandardKubeconfigLoader_returnsNotFoundErr(t *testing.T) {
defer withTestVar("KUBECONFIG", "foo")()
defer testutil.WithEnvVar("KUBECONFIG", "foo")()
kc := new(kubeconfig.Kubeconfig).WithLoader(defaultLoader)
err := kc.Parse()
if err == nil {

View File

@ -1,28 +1,27 @@
package kubeconfig
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestKubeconfig_DeleteContextEntry_errors(t *testing.T) {
kc := new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`[1, 2, 3]`)})
kc := new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`[1, 2, 3]`))
_ = kc.Parse()
err := kc.DeleteContextEntry("foo")
if err == nil {
t.Fatal("supposed to fail on non-mapping nodes")
}
kc = new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`a: b`)})
kc = new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`a: b`))
_ = kc.Parse()
err = kc.DeleteContextEntry("foo")
if err == nil {
t.Fatal("supposed to fail if contexts key does not exist")
}
kc = new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`contexts: "some string"`)})
kc = new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`contexts: "some string"`))
_ = kc.Parse()
err = kc.DeleteContextEntry("foo")
if err == nil {
@ -31,8 +30,8 @@ func TestKubeconfig_DeleteContextEntry_errors(t *testing.T) {
}
func TestKubeconfig_DeleteContextEntry(t *testing.T) {
test := &testLoader{in: strings.NewReader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)}
test := WithMockKubeconfigLoader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -45,16 +44,15 @@ func TestKubeconfig_DeleteContextEntry(t *testing.T) {
}
expected := "contexts: [{name: c2}, {name: c3}]\n"
out := test.out.String()
out := test.Output()
if diff := cmp.Diff(expected, out); diff != "" {
t.Fatalf("diff: %s", diff)
}
}
func TestKubeconfig_ModifyCurrentContext_fieldExists(t *testing.T) {
test := &testLoader{in: strings.NewReader(
`current-context: abc
field1: value1`)}
test := WithMockKubeconfigLoader(`current-context: abc
field1: value1`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -68,15 +66,15 @@ field1: value1`)}
expected := `current-context: foo
field1: value1` + "\n"
out := test.out.String()
out := test.Output()
if diff := cmp.Diff(expected, out); diff != "" {
t.Fatalf("diff: %s", diff)
}
}
func TestKubeconfig_ModifyCurrentContext_fieldMissing(t *testing.T) {
test := &testLoader{in: strings.NewReader(
`field1: value1`)}
test := WithMockKubeconfigLoader(
`field1: value1`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -89,7 +87,7 @@ func TestKubeconfig_ModifyCurrentContext_fieldMissing(t *testing.T) {
}
expected := `field1: value1` + "\n" + "current-context: foo\n"
out := test.out.String()
out := test.Output()
if diff := cmp.Diff(expected, out); diff != "" {
t.Fatalf("diff: %s", diff)
}
@ -97,8 +95,8 @@ func TestKubeconfig_ModifyCurrentContext_fieldMissing(t *testing.T) {
func TestKubeconfig_ModifyContextName_noContextsEntryError(t *testing.T) {
// no context entries
test := &testLoader{in: strings.NewReader(
`a: b`)}
test := WithMockKubeconfigLoader(
`a: b`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -111,8 +109,8 @@ func TestKubeconfig_ModifyContextName_noContextsEntryError(t *testing.T) {
func TestKubeconfig_ModifyContextName_contextsEntryNotSequenceError(t *testing.T) {
// no context entries
test := &testLoader{in: strings.NewReader(
`contexts: "hello"`)}
test := WithMockKubeconfigLoader(
`contexts: "hello"`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -124,8 +122,8 @@ func TestKubeconfig_ModifyContextName_contextsEntryNotSequenceError(t *testing.T
func TestKubeconfig_ModifyContextName_noChange(t *testing.T) {
test := &testLoader{in: strings.NewReader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)}
test := WithMockKubeconfigLoader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -136,8 +134,8 @@ func TestKubeconfig_ModifyContextName_noChange(t *testing.T) {
}
func TestKubeconfig_ModifyContextName(t *testing.T) {
test := &testLoader{in: strings.NewReader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)}
test := WithMockKubeconfigLoader(
`contexts: [{name: c1}, {name: c2}, {name: c3}]`)
kc := new(Kubeconfig).WithLoader(test)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -150,7 +148,7 @@ func TestKubeconfig_ModifyContextName(t *testing.T) {
}
expected := "contexts: [{name: ccc}, {name: c2}, {name: c3}]\n"
out := test.out.String()
out := test.Output()
if diff := cmp.Diff(expected, out); diff != "" {
t.Fatalf("diff: %s", diff)
}

View File

@ -1,21 +1,20 @@
package kubeconfig
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestKubeconfig_ContextNames(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`
tl := WithMockKubeconfigLoader(`
contexts:
- name: abc
- name: def
field1: value1
- name: ghi
foo:
bar: zoo`)}
bar: zoo`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
@ -30,7 +29,7 @@ contexts:
}
func TestKubeconfig_ContextNames_noContextsEntry(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`a: b`)}
tl := WithMockKubeconfigLoader(`a: b`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -43,7 +42,7 @@ func TestKubeconfig_ContextNames_noContextsEntry(t *testing.T) {
}
func TestKubeconfig_ContextNames_nonArrayContextsEntry(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`contexts: "hello"`)}
tl := WithMockKubeconfigLoader(`contexts: "hello"`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -56,9 +55,9 @@ func TestKubeconfig_ContextNames_nonArrayContextsEntry(t *testing.T) {
}
func TestKubeconfig_CheckContextExists(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`contexts:
tl := WithMockKubeconfigLoader(`contexts:
- name: c1
- name: c2`)}
- name: c2`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {

View File

@ -1,12 +1,11 @@
package kubeconfig
import (
"strings"
"testing"
)
func TestKubeconfig_GetCurrentContext(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`current-context: foo`)}
tl := WithMockKubeconfigLoader(`current-context: foo`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -20,7 +19,7 @@ func TestKubeconfig_GetCurrentContext(t *testing.T) {
}
func TestKubeconfig_GetCurrentContext_missingField(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`abc: def`)}
tl := WithMockKubeconfigLoader(`abc: def`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -34,7 +33,7 @@ func TestKubeconfig_GetCurrentContext_missingField(t *testing.T) {
}
func TestKubeconfig_UnsetCurrentContext(t *testing.T) {
tl := &testLoader{in: strings.NewReader(`current-context: foo`)}
tl := WithMockKubeconfigLoader(`current-context: foo`)
kc := new(Kubeconfig).WithLoader(tl)
if err := kc.Parse(); err != nil {
t.Fatal(err)
@ -46,7 +45,7 @@ func TestKubeconfig_UnsetCurrentContext(t *testing.T) {
t.Fatal(err)
}
out := tl.out.String()
out := tl.Output()
expected := `current-context: ""
`
if out != expected {

View File

@ -0,0 +1,23 @@
package kubeconfig
import (
"bytes"
"io"
"strings"
)
type MockKubeconfigLoader struct {
in io.Reader
out bytes.Buffer
}
func (t *MockKubeconfigLoader) Read(p []byte) (n int, err error) { return t.in.Read(p) }
func (t *MockKubeconfigLoader) Write(p []byte) (n int, err error) { return t.out.Write(p) }
func (t *MockKubeconfigLoader) Close() error { return nil }
func (t *MockKubeconfigLoader) Reset() error { return nil }
func (t *MockKubeconfigLoader) Load() (ReadWriteResetCloser, error) { return t, nil }
func (t *MockKubeconfigLoader) Output() string { return t.out.String() }
func WithMockKubeconfigLoader(kubecfg string) *MockKubeconfigLoader {
return &MockKubeconfigLoader{in: strings.NewReader(kubecfg)}
}

View File

@ -1,17 +1,2 @@
package kubeconfig
import (
"bytes"
"strings"
)
type testLoader struct {
in *strings.Reader
out bytes.Buffer
}
func (t *testLoader) Read(p []byte) (n int, err error) { return t.in.Read(p) }
func (t *testLoader) Write(p []byte) (n int, err error) { return t.out.Write(p) }
func (t *testLoader) Close() error { return nil }
func (t *testLoader) Reset() error { return nil }
func (t *testLoader) Load() (ReadWriteResetCloser, error) { return t, nil }

View File

@ -1,24 +1,23 @@
package kubeconfig
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestParse(t *testing.T) {
err := new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`a: [1, 2`)}).Parse()
err := new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`a: [1, 2`)).Parse()
if err == nil {
t.Fatal("expected error from bad yaml")
}
err = new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`[1, 2, 3]`)}).Parse()
err = new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`[1, 2, 3]`)).Parse()
if err == nil {
t.Fatal("expected error from not-mapping root node")
}
err = new(Kubeconfig).WithLoader(&testLoader{in: strings.NewReader(`current-context: foo`)}).Parse()
err = new(Kubeconfig).WithLoader(WithMockKubeconfigLoader(`current-context: foo`)).Parse()
if err != nil {
t.Fatal(err)
}
@ -26,7 +25,7 @@ func TestParse(t *testing.T) {
func TestSave(t *testing.T) {
in := `a: [1, 2, 3]` + "\n"
test := &testLoader{in: strings.NewReader(in)}
test := WithMockKubeconfigLoader(in)
kc := new(Kubeconfig).WithLoader(test)
defer kc.Close()
if err := kc.Parse(); err != nil {
@ -37,7 +36,7 @@ func TestSave(t *testing.T) {
t.Fatal(err)
}
expected := in+"current-context: hello\n"
if diff := cmp.Diff(expected, test.out.String()); diff != "" {
if diff := cmp.Diff(expected, test.Output()); diff != "" {
t.Fatal(diff)
}
}

View File

@ -1,31 +1,20 @@
package printer
import (
"os"
"testing"
"github.com/google/go-cmp/cmp"
)
func withTestVar(key, value string) func() {
orig, ok := os.LookupEnv(key)
os.Setenv(key, value)
return func() {
if ok {
os.Setenv(key, orig)
} else {
os.Unsetenv(key)
}
}
}
"github.com/ahmetb/kubectx/internal/testutil"
)
var (
tr, fa = true, false
)
func Test_useColors_forceColors(t *testing.T) {
defer withTestVar("_KUBECTX_FORCE_COLOR", "1")()
defer withTestVar("NO_COLOR", "1")()
defer testutil.WithEnvVar("_KUBECTX_FORCE_COLOR", "1")()
defer testutil.WithEnvVar("NO_COLOR", "1")()
if v := UseColors(); !cmp.Equal(v, &tr) {
t.Fatalf("expected UseColors() = true; got = %v", v)
@ -33,7 +22,7 @@ func Test_useColors_forceColors(t *testing.T) {
}
func Test_useColors_disableColors(t *testing.T) {
defer withTestVar("NO_COLOR", "1")()
defer testutil.WithEnvVar("NO_COLOR", "1")()
if v := UseColors(); !cmp.Equal(v, &fa) {
t.Fatalf("expected UseColors() = false; got = %v", v)
@ -41,8 +30,8 @@ func Test_useColors_disableColors(t *testing.T) {
}
func Test_useColors_default(t *testing.T) {
defer withTestVar("NO_COLOR", "")()
defer withTestVar("_KUBECTX_FORCE_COLOR", "")()
defer testutil.WithEnvVar("NO_COLOR", "")()
defer testutil.WithEnvVar("_KUBECTX_FORCE_COLOR", "")()
if v := UseColors(); v != nil {
t.Fatalf("expected UseColors() = nil; got=%v", *v)

View File

@ -0,0 +1,2 @@
package testutil

View File

@ -0,0 +1,18 @@
package testutil
import "os"
// WithEnvVar sets an env var temporarily. Call its return value
// in defer to restore original value in env (if exists).
func WithEnvVar(key, value string) func() {
orig, ok := os.LookupEnv(key)
os.Setenv(key, value)
return func() {
if ok {
os.Setenv(key, orig)
} else {
os.Unsetenv(key)
}
}
}