From 6c6f30042313e012555bd27f5f4ab20ffd66eaaa Mon Sep 17 00:00:00 2001 From: Cedric Meury Date: Mon, 26 Mar 2018 00:06:05 +0200 Subject: [PATCH] describing current functionality as tests --- helmexec/exec.go | 30 ++++--- helmexec/exec_test.go | 178 ++++++++++++++++++++++++++++++++++++++++++ helmexec/helmexec.go | 9 +++ helmexec/runner.go | 30 +++++++ 4 files changed, 234 insertions(+), 13 deletions(-) create mode 100644 helmexec/exec_test.go create mode 100644 helmexec/runner.go diff --git a/helmexec/exec.go b/helmexec/exec.go index d43670c3..4d96d131 100644 --- a/helmexec/exec.go +++ b/helmexec/exec.go @@ -3,9 +3,6 @@ package helmexec import ( "fmt" "io" - "io/ioutil" - "os" - "os/exec" "strings" ) @@ -14,6 +11,7 @@ const ( ) type execer struct { + runner Runner writer io.Writer kubeContext string extra []string @@ -23,6 +21,7 @@ func NewHelmExec(writer io.Writer, kubeContext string) Interface { return &execer{ writer: writer, kubeContext: kubeContext, + runner: new(CliRunner), } } @@ -84,12 +83,6 @@ func (helm *execer) DeleteRelease(name string) error { } func (helm *execer) exec(args ...string) ([]byte, error) { - dir, err := ioutil.TempDir("", "helmfile-exec") - if err != nil { - return nil, err - } - defer os.RemoveAll(dir) - cmdargs := args if len(helm.extra) > 0 { cmdargs = append(cmdargs, helm.extra...) @@ -100,8 +93,19 @@ func (helm *execer) exec(args ...string) ([]byte, error) { if helm.writer != nil { helm.writer.Write([]byte(fmt.Sprintf("exec: helm %s\n", strings.Join(cmdargs, " ")))) } - - cmd := exec.Command(command, cmdargs...) - cmd.Dir = dir - return cmd.CombinedOutput() + return helm.runner.Execute(command, cmdargs) } + +// for unit testing +func (helm *execer) setRunner(runner Runner) { + helm.runner = runner +} +func (helm *execer) getExtra() []string { + return helm.extra +} +func (helm *execer) getKubeContent() string { + return helm.kubeContext +} +func (helm *execer) getWriter() io.Writer { + return helm.writer +} \ No newline at end of file diff --git a/helmexec/exec_test.go b/helmexec/exec_test.go new file mode 100644 index 00000000..90a43aa4 --- /dev/null +++ b/helmexec/exec_test.go @@ -0,0 +1,178 @@ +package helmexec + +import ( + "bytes" + "io" + "reflect" + "testing" +) + +// Mocking the command-line runner + +type MockRunner struct { + output []byte + err error +} + +func (mock *MockRunner) Execute(cmd string, args []string) ([]byte, error) { + return []byte{}, nil +} + +func NewMockExec(writer io.Writer, kubeContext string) Interface { + nhe := NewHelmExec(writer, kubeContext) + runner := &MockRunner{} + nhe.setRunner(runner) + return nhe +} + +// Test methods + +func TestNewHelmExec(t *testing.T) { + buffer := bytes.NewBufferString("something") + helm := NewHelmExec(buffer, "dev") + if helm.getKubeContent() != "dev" { + t.Error("helmexec.NewHelmExec() - kubeContext") + } + if buffer.String() != "something" { + t.Error("helmexec.NewHelmExec() - changed buffer") + } + if len(helm.getExtra()) != 0 { + t.Error("helmexec.NewHelmExec() - extra args not empty") + } +} + +func Test_SetExtraArgs(t *testing.T) { + helm := NewHelmExec(new(bytes.Buffer), "dev") + helm.SetExtraArgs() + if len(helm.getExtra()) != 0 { + t.Error("helmexec.SetExtraArgs() - passing no arguments should not change extra field") + } + helm.SetExtraArgs("foo") + if !reflect.DeepEqual(helm.getExtra(), []string{"foo"}) { + t.Error("helmexec.SetExtraArgs() - one extra argument missing") + } + helm.SetExtraArgs("alpha", "beta") + if !reflect.DeepEqual(helm.getExtra(), []string{"alpha", "beta"}) { + t.Error("helmexec.SetExtraArgs() - two extra arguments missing (overwriting the previous value)") + } +} + +func Test_AddRepo(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.AddRepo("myRepo", "https://repo.example.com/", "cert.pem", "key.pem") + expected := "exec: helm repo add myRepo https://repo.example.com/ --cert-file cert.pem --key-file key.pem --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + buffer.Reset() + helm.AddRepo("myRepo", "https://repo.example.com/", "", "") + expected = "exec: helm repo add myRepo https://repo.example.com/ --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_UpdateRepo(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.UpdateRepo() + expected := "exec: helm repo update --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.UpdateRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_SyncRelease(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.SyncRelease("release", "chart", "--timeout 10", "--wait") + expected := "exec: helm upgrade --install release chart --timeout 10 --wait --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.SyncRelease()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + buffer.Reset() + helm.SyncRelease("release", "chart") + expected = "exec: helm upgrade --install release chart --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_DecryptSecret(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.DecryptSecret("secretName") + expected := "exec: helm secrets dec secretName --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.DecryptSecret()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_DiffRelease(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.DiffRelease("release", "chart", "--timeout 10", "--wait") + expected := "exec: helm diff release chart --timeout 10 --wait --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.DiffRelease()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + buffer.Reset() + helm.DiffRelease("release", "chart") + expected = "exec: helm diff release chart --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.DiffRelease()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_DeleteRelease(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "dev") + helm.DeleteRelease("release") + expected := "exec: helm delete --purge release --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.DeleteRelease()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} + +func Test_exec(t *testing.T) { + var buffer bytes.Buffer + helm := NewMockExec(&buffer, "") + helm.exec("version") + expected := "exec: helm version\n" + if buffer.String() != expected { + t.Errorf("helmexec.exec()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + helm = NewMockExec(nil, "dev") + ret, _ := helm.exec("diff") + if len(ret) != 0 { + t.Error("helmexec.exec() - expected empty return value") + } + + buffer.Reset() + helm = NewMockExec(&buffer, "dev") + helm.exec("diff", "release", "chart", "--timeout 10", "--wait") + expected = "exec: helm diff release chart --timeout 10 --wait --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.exec()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + buffer.Reset() + helm.exec("version") + expected = "exec: helm version --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.exec()\nactual = %v\nexpect = %v", buffer.String(), expected) + } + + buffer.Reset() + helm.SetExtraArgs("foo") + helm.exec("version") + expected = "exec: helm version foo --kube-context dev\n" + if buffer.String() != expected { + t.Errorf("helmexec.exec()\nactual = %v\nexpect = %v", buffer.String(), expected) + } +} diff --git a/helmexec/helmexec.go b/helmexec/helmexec.go index 2786c67b..61036c9c 100644 --- a/helmexec/helmexec.go +++ b/helmexec/helmexec.go @@ -1,5 +1,7 @@ package helmexec +import "io" + type Interface interface { SetExtraArgs(args ...string) @@ -11,4 +13,11 @@ type Interface interface { DeleteRelease(name string) error DecryptSecret(name string) (string, error) + + // unit testing + exec(args ...string) ([]byte, error) + setRunner(runner Runner) + getExtra() []string + getKubeContent() string + getWriter() io.Writer } diff --git a/helmexec/runner.go b/helmexec/runner.go new file mode 100644 index 00000000..9ada527b --- /dev/null +++ b/helmexec/runner.go @@ -0,0 +1,30 @@ +package helmexec + +import ( + "io/ioutil" + "os" + "os/exec" +) + +const ( + tmpPrefix = "helmfile-" + tmpSuffix = "-exec" +) + +type Runner interface { + Execute(cmd string, args []string) ([]byte, error) +} + +type CliRunner struct {} + +func (cli CliRunner) Execute(cmd string, args []string) ([]byte, error) { + dir, err := ioutil.TempDir("", tmpPrefix + cmd + tmpSuffix) + if err != nil { + return nil, err + } + defer os.RemoveAll(dir) + + preparedCmd := exec.Command(cmd, args...) + preparedCmd.Dir = dir + return preparedCmd.CombinedOutput() +}