github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/caasoperator/action_test.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperator_test 5 6 import ( 7 "bytes" 8 "os" 9 "path/filepath" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "github.com/juju/names/v5" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils/v3" 16 utilexec "github.com/juju/utils/v3/exec" 17 "go.uber.org/mock/gomock" 18 gc "gopkg.in/check.v1" 19 k8sexec "k8s.io/client-go/util/exec" 20 21 "github.com/juju/juju/caas/kubernetes/provider/exec" 22 "github.com/juju/juju/testing" 23 "github.com/juju/juju/worker/caasoperator" 24 "github.com/juju/juju/worker/caasoperator/mocks" 25 "github.com/juju/juju/worker/uniter" 26 "github.com/juju/juju/worker/uniter/runner" 27 ) 28 29 type actionSuite struct { 30 testing.BaseSuite 31 32 executor *mocks.MockExecutor 33 unitAPI *mocks.MockProviderIDGetter 34 } 35 36 var _ = gc.Suite(&actionSuite{}) 37 38 func (s *actionSuite) setupExecClient(c *gc.C) *gomock.Controller { 39 ctrl := gomock.NewController(c) 40 s.executor = mocks.NewMockExecutor(ctrl) 41 s.unitAPI = mocks.NewMockProviderIDGetter(ctrl) 42 return ctrl 43 } 44 45 func (s *actionSuite) TestRunnerExecFunc(c *gc.C) { 46 s.assertRunnerExecFunc(c, "") 47 } 48 49 func (s *actionSuite) TestRunnerExecFuncWithError(c *gc.C) { 50 s.assertRunnerExecFunc(c, "boom") 51 } 52 53 func (s *actionSuite) assertRunnerExecFunc(c *gc.C, errMsg string) { 54 ctrl := s.setupExecClient(c) 55 defer ctrl.Finish() 56 57 baseDir := c.MkDir() 58 operatorPaths := caasoperator.NewPaths(baseDir, names.NewApplicationTag("gitlab-k8s")) 59 unitPaths := uniter.NewPaths(baseDir, names.NewUnitTag("gitlab-k8s/0"), &uniter.SocketConfig{}) 60 for _, p := range []string{ 61 operatorPaths.GetCharmDir(), 62 unitPaths.GetCharmDir(), 63 64 operatorPaths.GetToolsDir(), 65 unitPaths.GetToolsDir(), 66 } { 67 err := os.MkdirAll(p, 0700) 68 c.Check(err, jc.ErrorIsNil) 69 } 70 err := utils.AtomicWriteFile(filepath.Join(operatorPaths.GetToolsDir(), "jujud"), []byte(""), 0600) 71 c.Assert(err, jc.ErrorIsNil) 72 73 logger := loggo.GetLogger("test") 74 runnerExecFunc := caasoperator.GetNewRunnerExecutor(logger, s.executor)(s.unitAPI, unitPaths) 75 cancel := make(<-chan struct{}, 1) 76 stdout := bytes.NewBufferString("") 77 stderr := bytes.NewBufferString("") 78 expectedCode := 0 79 var exitErr error 80 if errMsg != "" { 81 exitErr = errors.Trace(k8sexec.CodeExitError{Code: 3, Err: errors.New(errMsg)}) 82 expectedCode = 3 83 } 84 gomock.InOrder( 85 s.unitAPI.EXPECT().Refresh().Return(nil), 86 s.unitAPI.EXPECT().ProviderID().Return("gitlab-xxxx"), 87 s.unitAPI.EXPECT().Name().Return("gitlab-k8s/0"), 88 s.executor.EXPECT().Exec( 89 exec.ExecParams{ 90 PodName: "gitlab-xxxx", 91 Commands: []string{"storage-list"}, 92 Env: []string{"AAAA=1111"}, 93 Stdout: stdout, 94 Stderr: stderr, 95 }, cancel, 96 ).DoAndReturn(func(exec.ExecParams, <-chan struct{}) error { 97 stdout.WriteString("some message") 98 stderr.WriteString("some err message") 99 return exitErr 100 }), 101 ) 102 103 outLogger := &mockHookLogger{} 104 errLogger := &mockHookLogger{} 105 result, err := runnerExecFunc( 106 runner.ExecParams{ 107 Commands: []string{"storage-list"}, 108 Env: []string{"AAAA=1111"}, 109 Stdout: stdout, 110 StdoutLogger: outLogger, 111 Stderr: stdout, 112 StderrLogger: errLogger, 113 Cancel: cancel, 114 }, 115 ) 116 c.Assert(outLogger.stopped, jc.IsTrue) 117 c.Assert(errLogger.stopped, jc.IsTrue) 118 c.Assert(result, jc.DeepEquals, &utilexec.ExecResponse{ 119 Code: expectedCode, 120 Stdout: []byte("some message"), 121 }) 122 if exitErr == nil { 123 c.Assert(err, jc.ErrorIsNil) 124 } else { 125 c.Assert(err, gc.ErrorMatches, "boom") 126 } 127 } 128 129 type exitError struct { 130 code int 131 err string 132 } 133 134 var _ exec.ExitError = exitError{} 135 136 func (e exitError) String() string { 137 return e.err 138 } 139 140 func (e exitError) Error() string { 141 return e.err 142 } 143 144 func (e exitError) ExitStatus() int { 145 return e.code 146 }