Very rough code that can helm install

The recommended way to test code that uses exec.Cmd involves setting up
a real exec.Cmd that invokes `go test` with additional arguments that
fire off a specially-constructed test that behaves the way the mocked-
out script would be expected to do. It's a sensible way to test exec.Cmd
itself, but for code that merely invokes it, I think it makes more sense
to use actual mocks.
This commit is contained in:
Erin Call 2019-12-04 11:26:05 -08:00
parent ba75a9b1d8
commit 990d1856d8
No known key found for this signature in database
GPG key ID: 4071FF6C15B8DAD1
6 changed files with 411 additions and 1 deletions

5
go.mod
View file

@ -2,4 +2,7 @@ module github.com/pelotech/drone-helm3
go 1.13
require github.com/urfave/cli v1.22.0
require (
github.com/golang/mock v1.3.1
github.com/urfave/cli v1.22.0
)

10
go.sum
View file

@ -1,9 +1,19 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/urfave/cli v1.22.0 h1:8nz/RUUotroXnOpYzT/Fy3sBp+2XEbXaY641/s3nbFI=
github.com/urfave/cli v1.22.0/go.mod h1:b3D7uWrF2GilkNgYpgcg6J+JMUw7ehmNkE8sZdliGLc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

55
internal/run/cmd.go Normal file
View file

@ -0,0 +1,55 @@
package run
import (
"io"
"os"
"os/exec"
"syscall"
)
// The cmd interface provides a generic form of exec.Cmd so that it can be mocked out in tests.
type cmd interface {
// methods that exist on exec.Cmd
Output() ([]byte, error)
Run() error
CombinedOutput() ([]byte, error)
Start() error
StderrPipe() (io.ReadCloser, error)
StdinPipe() (io.WriteCloser, error)
StdoutPipe() (io.ReadCloser, error)
String() string
Wait() error
// setters for struct fields set by callers of exec.Cmd
Path(string)
Args([]string)
Env([]string)
Dir(string)
Stdin(io.Reader)
Stdout(io.Writer)
Stderr(io.Writer)
ExtraFiles([]*os.File)
SysProcAttr(*syscall.SysProcAttr)
// getters for struct fields generated by exec.Cmd
Process() *os.Process
ProcessState() *os.ProcessState
}
// execCmd wraps exec.Cmd along with setters for exec.Cmd's struct fields, implementing the cmd interface.
type execCmd struct {
*exec.Cmd
}
func (c *execCmd) Path(p string) { c.Cmd.Path = p }
func (c *execCmd) Args(a []string) { c.Cmd.Args = a }
func (c *execCmd) Env(e []string) { c.Cmd.Env = e }
func (c *execCmd) Dir(d string) { c.Cmd.Dir = d }
func (c *execCmd) Stdin(s io.Reader) { c.Cmd.Stdin = s }
func (c *execCmd) Stdout(s io.Writer) { c.Cmd.Stdout = s }
func (c *execCmd) Stderr(s io.Writer) { c.Cmd.Stderr = s }
func (c *execCmd) ExtraFiles(f []*os.File) { c.Cmd.ExtraFiles = f }
func (c *execCmd) SysProcAttr(s *syscall.SysProcAttr) { c.Cmd.SysProcAttr = s }
func (c *execCmd) Process() *os.Process { return c.Cmd.Process }
func (c *execCmd) ProcessState() *os.ProcessState { return c.Cmd.ProcessState }

303
internal/run/cmd_test.go Normal file
View file

@ -0,0 +1,303 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./internal/run/cmd.go
// Package run is a generated GoMock package.
package run
import (
gomock "github.com/golang/mock/gomock"
io "io"
os "os"
reflect "reflect"
syscall "syscall"
)
// Mockcmd is a mock of cmd interface
type Mockcmd struct {
ctrl *gomock.Controller
recorder *MockcmdMockRecorder
}
// MockcmdMockRecorder is the mock recorder for Mockcmd
type MockcmdMockRecorder struct {
mock *Mockcmd
}
// NewMockcmd creates a new mock instance
func NewMockcmd(ctrl *gomock.Controller) *Mockcmd {
mock := &Mockcmd{ctrl: ctrl}
mock.recorder = &MockcmdMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *Mockcmd) EXPECT() *MockcmdMockRecorder {
return m.recorder
}
// Output mocks base method
func (m *Mockcmd) Output() ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Output")
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Output indicates an expected call of Output
func (mr *MockcmdMockRecorder) Output() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Output", reflect.TypeOf((*Mockcmd)(nil).Output))
}
// Run mocks base method
func (m *Mockcmd) Run() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Run")
ret0, _ := ret[0].(error)
return ret0
}
// Run indicates an expected call of Run
func (mr *MockcmdMockRecorder) Run() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*Mockcmd)(nil).Run))
}
// CombinedOutput mocks base method
func (m *Mockcmd) CombinedOutput() ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CombinedOutput")
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CombinedOutput indicates an expected call of CombinedOutput
func (mr *MockcmdMockRecorder) CombinedOutput() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CombinedOutput", reflect.TypeOf((*Mockcmd)(nil).CombinedOutput))
}
// Start mocks base method
func (m *Mockcmd) Start() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Start")
ret0, _ := ret[0].(error)
return ret0
}
// Start indicates an expected call of Start
func (mr *MockcmdMockRecorder) Start() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*Mockcmd)(nil).Start))
}
// StderrPipe mocks base method
func (m *Mockcmd) StderrPipe() (io.ReadCloser, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StderrPipe")
ret0, _ := ret[0].(io.ReadCloser)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StderrPipe indicates an expected call of StderrPipe
func (mr *MockcmdMockRecorder) StderrPipe() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StderrPipe", reflect.TypeOf((*Mockcmd)(nil).StderrPipe))
}
// StdinPipe mocks base method
func (m *Mockcmd) StdinPipe() (io.WriteCloser, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StdinPipe")
ret0, _ := ret[0].(io.WriteCloser)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StdinPipe indicates an expected call of StdinPipe
func (mr *MockcmdMockRecorder) StdinPipe() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StdinPipe", reflect.TypeOf((*Mockcmd)(nil).StdinPipe))
}
// StdoutPipe mocks base method
func (m *Mockcmd) StdoutPipe() (io.ReadCloser, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StdoutPipe")
ret0, _ := ret[0].(io.ReadCloser)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StdoutPipe indicates an expected call of StdoutPipe
func (mr *MockcmdMockRecorder) StdoutPipe() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StdoutPipe", reflect.TypeOf((*Mockcmd)(nil).StdoutPipe))
}
// String mocks base method
func (m *Mockcmd) String() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "String")
ret0, _ := ret[0].(string)
return ret0
}
// String indicates an expected call of String
func (mr *MockcmdMockRecorder) String() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*Mockcmd)(nil).String))
}
// Wait mocks base method
func (m *Mockcmd) Wait() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Wait")
ret0, _ := ret[0].(error)
return ret0
}
// Wait indicates an expected call of Wait
func (mr *MockcmdMockRecorder) Wait() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wait", reflect.TypeOf((*Mockcmd)(nil).Wait))
}
// Path mocks base method
func (m *Mockcmd) Path(arg0 string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Path", arg0)
}
// Path indicates an expected call of Path
func (mr *MockcmdMockRecorder) Path(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Path", reflect.TypeOf((*Mockcmd)(nil).Path), arg0)
}
// Args mocks base method
func (m *Mockcmd) Args(arg0 []string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Args", arg0)
}
// Args indicates an expected call of Args
func (mr *MockcmdMockRecorder) Args(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Args", reflect.TypeOf((*Mockcmd)(nil).Args), arg0)
}
// Env mocks base method
func (m *Mockcmd) Env(arg0 []string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Env", arg0)
}
// Env indicates an expected call of Env
func (mr *MockcmdMockRecorder) Env(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Env", reflect.TypeOf((*Mockcmd)(nil).Env), arg0)
}
// Dir mocks base method
func (m *Mockcmd) Dir(arg0 string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Dir", arg0)
}
// Dir indicates an expected call of Dir
func (mr *MockcmdMockRecorder) Dir(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Dir", reflect.TypeOf((*Mockcmd)(nil).Dir), arg0)
}
// Stdin mocks base method
func (m *Mockcmd) Stdin(arg0 io.Reader) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Stdin", arg0)
}
// Stdin indicates an expected call of Stdin
func (mr *MockcmdMockRecorder) Stdin(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stdin", reflect.TypeOf((*Mockcmd)(nil).Stdin), arg0)
}
// Stdout mocks base method
func (m *Mockcmd) Stdout(arg0 io.Writer) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Stdout", arg0)
}
// Stdout indicates an expected call of Stdout
func (mr *MockcmdMockRecorder) Stdout(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stdout", reflect.TypeOf((*Mockcmd)(nil).Stdout), arg0)
}
// Stderr mocks base method
func (m *Mockcmd) Stderr(arg0 io.Writer) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Stderr", arg0)
}
// Stderr indicates an expected call of Stderr
func (mr *MockcmdMockRecorder) Stderr(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stderr", reflect.TypeOf((*Mockcmd)(nil).Stderr), arg0)
}
// ExtraFiles mocks base method
func (m *Mockcmd) ExtraFiles(arg0 []*os.File) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ExtraFiles", arg0)
}
// ExtraFiles indicates an expected call of ExtraFiles
func (mr *MockcmdMockRecorder) ExtraFiles(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExtraFiles", reflect.TypeOf((*Mockcmd)(nil).ExtraFiles), arg0)
}
// SysProcAttr mocks base method
func (m *Mockcmd) SysProcAttr(arg0 *syscall.SysProcAttr) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SysProcAttr", arg0)
}
// SysProcAttr indicates an expected call of SysProcAttr
func (mr *MockcmdMockRecorder) SysProcAttr(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SysProcAttr", reflect.TypeOf((*Mockcmd)(nil).SysProcAttr), arg0)
}
// Process mocks base method
func (m *Mockcmd) Process() *os.Process {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Process")
ret0, _ := ret[0].(*os.Process)
return ret0
}
// Process indicates an expected call of Process
func (mr *MockcmdMockRecorder) Process() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Process", reflect.TypeOf((*Mockcmd)(nil).Process))
}
// ProcessState mocks base method
func (m *Mockcmd) ProcessState() *os.ProcessState {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProcessState")
ret0, _ := ret[0].(*os.ProcessState)
return ret0
}
// ProcessState indicates an expected call of ProcessState
func (mr *MockcmdMockRecorder) ProcessState() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessState", reflect.TypeOf((*Mockcmd)(nil).ProcessState))
}

19
internal/run/install.go Normal file
View file

@ -0,0 +1,19 @@
package run
import ()
const HELM_BIN = "/usr/bin/helm"
func Install(args ...string) error {
cmd := &execCmd{}
cmd.Path(HELM_BIN)
return install(cmd, args)
}
func install(cmd cmd, args []string) error {
args = append([]string{"install"}, args...)
cmd.Args(args)
return cmd.Run()
}

View file

@ -0,0 +1,20 @@
package run
import (
"github.com/golang/mock/gomock"
"testing"
)
func TestInstall(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
cmd := NewMockcmd(ctrl)
cmd.EXPECT().
Args(gomock.Eq([]string{"install", "arg1", "arg2"}))
cmd.EXPECT().
Run().
Times(1)
install(cmd, []string{"arg1", "arg2"})
}