github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/caasoperator/manifold_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperator_test 5 6 import ( 7 "os" 8 "sync" 9 "time" 10 11 "github.com/juju/clock/testclock" 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 "github.com/juju/names/v5" 15 "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/worker/v3" 18 "github.com/juju/worker/v3/dependency" 19 dt "github.com/juju/worker/v3/dependency/testing" 20 "github.com/juju/worker/v3/workertest" 21 "go.uber.org/mock/gomock" 22 gc "gopkg.in/check.v1" 23 24 "github.com/juju/juju/api/agent/secretsmanager" 25 "github.com/juju/juju/api/base" 26 "github.com/juju/juju/caas" 27 "github.com/juju/juju/caas/kubernetes/provider/exec" 28 "github.com/juju/juju/core/machinelock" 29 "github.com/juju/juju/rpc/params" 30 _ "github.com/juju/juju/secrets/provider/all" 31 coretesting "github.com/juju/juju/testing" 32 "github.com/juju/juju/worker/caasoperator" 33 "github.com/juju/juju/worker/caasoperator/mocks" 34 "github.com/juju/juju/worker/uniter" 35 ) 36 37 type ManifoldSuite struct { 38 testing.IsolationSuite 39 40 manifold dependency.Manifold 41 agent fakeAgent 42 apiCaller *mocks.MockAPICaller 43 charmDownloader fakeDownloader 44 client fakeClient 45 clock *testclock.Clock 46 dataDir string 47 stub testing.Stub 48 } 49 50 var _ = gc.Suite(&ManifoldSuite{}) 51 52 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 53 s.IsolationSuite.SetUpTest(c) 54 55 os.Setenv("JUJU_OPERATOR_SERVICE_IP", "127.0.0.1") 56 os.Setenv("JUJU_OPERATOR_POD_IP", "127.0.0.2") 57 58 s.dataDir = c.MkDir() 59 s.agent = fakeAgent{ 60 config: fakeAgentConfig{ 61 tag: names.NewApplicationTag("gitlab"), 62 dataDir: s.dataDir, 63 }, 64 } 65 s.clock = testclock.NewClock(time.Time{}) 66 s.stub.ResetCalls() 67 } 68 69 func (s *ManifoldSuite) TearDownTest(c *gc.C) { 70 os.Setenv("JUJU_OPERATOR_SERVICE_IP", "") 71 os.Setenv("JUJU_OPERATOR_POD_IP", "") 72 73 s.IsolationSuite.TearDownTest(c) 74 } 75 76 func (s *ManifoldSuite) setupManifold(c *gc.C) *gomock.Controller { 77 ctrl := gomock.NewController(c) 78 s.apiCaller = mocks.NewMockAPICaller(ctrl) 79 80 s.manifold = caasoperator.Manifold(caasoperator.ManifoldConfig{ 81 AgentName: "agent", 82 APICallerName: "api-caller", 83 ClockName: "clock", 84 CharmDirName: "charm-dir", 85 HookRetryStrategyName: "hook-retry-strategy", 86 ProfileDir: "profile-dir", 87 MachineLock: &fakemachinelock{}, 88 NewWorker: s.newWorker, 89 NewClient: s.newClient, 90 NewCharmDownloader: s.newCharmDownloader, 91 LeadershipGuarantee: 30 * time.Second, 92 NewExecClient: func(modelName string) (exec.Executor, error) { 93 return mocks.NewMockExecutor(ctrl), nil 94 }, 95 LoadOperatorInfo: func(paths caasoperator.Paths) (*caas.OperatorInfo, error) { 96 return &caas.OperatorInfo{ 97 CACert: coretesting.CACert, 98 Cert: coretesting.ServerCert, 99 PrivateKey: coretesting.ServerKey, 100 }, nil 101 }, 102 Logger: loggo.GetLogger("test"), 103 }) 104 return ctrl 105 } 106 107 func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context { 108 resources := map[string]interface{}{ 109 "agent": &s.agent, 110 "api-caller": s.apiCaller, 111 "clock": s.clock, 112 "charm-dir": &mockCharmDirGuard{}, 113 "hook-retry-strategy": params.RetryStrategy{}, 114 } 115 for k, v := range overlay { 116 resources[k] = v 117 } 118 return dt.StubContext(nil, resources) 119 } 120 121 func (s *ManifoldSuite) newWorker(config caasoperator.Config) (worker.Worker, error) { 122 s.stub.MethodCall(s, "NewWorker", config) 123 if err := s.stub.NextErr(); err != nil { 124 return nil, err 125 } 126 w := worker.NewRunner(worker.RunnerParams{}) 127 s.AddCleanup(func(c *gc.C) { workertest.DirtyKill(c, w) }) 128 return w, nil 129 } 130 131 func (s *ManifoldSuite) newClient(caller base.APICaller) caasoperator.Client { 132 s.stub.MethodCall(s, "NewClient", caller) 133 return &s.client 134 } 135 136 func (s *ManifoldSuite) newCharmDownloader(caller base.APICaller) caasoperator.Downloader { 137 s.stub.MethodCall(s, "NewCharmDownloader", caller) 138 return &s.charmDownloader 139 } 140 141 var expectedInputs = []string{"agent", "api-caller", "clock", "charm-dir", "hook-retry-strategy"} 142 143 func (s *ManifoldSuite) TestInputs(c *gc.C) { 144 ctrl := s.setupManifold(c) 145 defer ctrl.Finish() 146 147 c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs) 148 } 149 150 func (s *ManifoldSuite) TestMissingInputs(c *gc.C) { 151 ctrl := s.setupManifold(c) 152 defer ctrl.Finish() 153 154 for _, input := range expectedInputs { 155 context := s.newContext(map[string]interface{}{ 156 input: dependency.ErrMissing, 157 }) 158 _, err := s.manifold.Start(context) 159 c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing) 160 } 161 } 162 163 func (s *ManifoldSuite) TestStart(c *gc.C) { 164 w := s.startWorkerClean(c) 165 workertest.CleanKill(c, w) 166 167 s.stub.CheckCallNames(c, "NewClient", "NewCharmDownloader", "NewWorker") 168 s.stub.CheckCall(c, 0, "NewClient", s.apiCaller) 169 s.stub.CheckCall(c, 1, "NewCharmDownloader", s.apiCaller) 170 171 args := s.stub.Calls()[2].Args 172 c.Assert(args, gc.HasLen, 1) 173 c.Assert(args[0], gc.FitsTypeOf, caasoperator.Config{}) 174 config := args[0].(caasoperator.Config) 175 176 // Don't care about some helper funcs. 177 c.Assert(config.UniterParams, gc.NotNil) 178 c.Assert(config.LeadershipTrackerFunc, gc.NotNil) 179 c.Assert(config.UniterFacadeFunc, gc.NotNil) 180 c.Assert(config.StartUniterFunc, gc.NotNil) 181 c.Assert(config.RunListenerSocketFunc, gc.NotNil) 182 c.Assert(config.UniterParams.UpdateStatusSignal, gc.NotNil) 183 c.Assert(config.UniterParams.NewOperationExecutor, gc.NotNil) 184 c.Assert(config.UniterParams.NewProcessRunner, gc.NotNil) 185 c.Assert(config.UniterParams.NewDeployer, gc.NotNil) 186 c.Assert(config.UniterParams.SecretRotateWatcherFunc, gc.NotNil) 187 c.Assert(config.UniterParams.SecretsBackendGetter, gc.NotNil) 188 c.Assert(config.Logger, gc.NotNil) 189 c.Assert(config.ExecClientGetter, gc.NotNil) 190 config.LeadershipTrackerFunc = nil 191 config.StartUniterFunc = nil 192 config.UniterFacadeFunc = nil 193 config.ResourcesFacadeFunc = nil 194 config.PayloadFacadeFunc = nil 195 config.RunListenerSocketFunc = nil 196 config.UniterParams.UpdateStatusSignal = nil 197 config.UniterParams.NewOperationExecutor = nil 198 config.UniterParams.NewDeployer = nil 199 config.UniterParams.NewProcessRunner = nil 200 config.UniterParams.SecretRotateWatcherFunc = nil 201 config.UniterParams.SecretExpiryWatcherFunc = nil 202 config.UniterParams.SecretsBackendGetter = nil 203 config.Logger = nil 204 config.ExecClientGetter = nil 205 206 c.Assert(config.UniterParams.SocketConfig.TLSConfig, gc.NotNil) 207 config.UniterParams.SocketConfig.TLSConfig = nil 208 209 jujuSecretsAPI := secretsmanager.NewClient(s.apiCaller) 210 c.Assert(config, jc.DeepEquals, caasoperator.Config{ 211 ModelUUID: coretesting.ModelTag.Id(), 212 ModelName: "gitlab-model", 213 Application: "gitlab", 214 ProfileDir: "profile-dir", 215 DataDir: s.dataDir, 216 CharmGetter: &s.client, 217 Clock: s.clock, 218 Downloader: &s.charmDownloader, 219 StatusSetter: &s.client, 220 UnitGetter: &s.client, 221 UnitRemover: &s.client, 222 ContainerStartWatcher: &s.client, 223 ApplicationWatcher: &s.client, 224 VersionSetter: &s.client, 225 UniterParams: &uniter.UniterParams{ 226 DataDir: s.dataDir, 227 MachineLock: &fakemachinelock{}, 228 SecretsClient: jujuSecretsAPI, 229 CharmDirGuard: &mockCharmDirGuard{}, 230 Clock: s.clock, 231 SocketConfig: &uniter.SocketConfig{ 232 ServiceAddress: "127.0.0.1", 233 OperatorAddress: "127.0.0.2", 234 }, 235 Logger: loggo.GetLogger("test.uniter"), 236 }, 237 OperatorInfo: caas.OperatorInfo{ 238 CACert: coretesting.CACert, 239 Cert: coretesting.ServerCert, 240 PrivateKey: coretesting.ServerKey, 241 }, 242 }) 243 } 244 245 func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker { 246 ctrl := s.setupManifold(c) 247 defer ctrl.Finish() 248 249 s.apiCaller.EXPECT().BestFacadeVersion("SecretsManager").AnyTimes().Return(1) 250 251 w, err := s.manifold.Start(s.newContext(nil)) 252 c.Assert(err, jc.ErrorIsNil) 253 workertest.CheckAlive(c, w) 254 return w 255 } 256 257 type fakemachinelock struct { 258 mu sync.Mutex 259 } 260 261 func (f *fakemachinelock) Acquire(spec machinelock.Spec) (func(), error) { 262 f.mu.Lock() 263 return func() { 264 f.mu.Unlock() 265 }, nil 266 } 267 func (f *fakemachinelock) Report(opts ...machinelock.ReportOption) (string, error) { 268 return "", nil 269 }