github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/caasapplicationprovisioner/worker_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasapplicationprovisioner_test 5 6 import ( 7 "time" 8 9 "github.com/juju/clock/testclock" 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 "github.com/juju/names/v5" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/worker/v3" 15 "github.com/juju/worker/v3/workertest" 16 "go.uber.org/mock/gomock" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/caas" 20 "github.com/juju/juju/core/life" 21 "github.com/juju/juju/core/watcher" 22 "github.com/juju/juju/core/watcher/watchertest" 23 "github.com/juju/juju/rpc/params" 24 coretesting "github.com/juju/juju/testing" 25 "github.com/juju/juju/worker/caasapplicationprovisioner" 26 "github.com/juju/juju/worker/caasapplicationprovisioner/mocks" 27 ) 28 29 var _ = gc.Suite(&CAASApplicationSuite{}) 30 31 type CAASApplicationSuite struct { 32 coretesting.BaseSuite 33 34 clock *testclock.Clock 35 modelTag names.ModelTag 36 logger loggo.Logger 37 } 38 39 func (s *CAASApplicationSuite) SetUpTest(c *gc.C) { 40 s.clock = testclock.NewClock(time.Now()) 41 s.modelTag = names.NewModelTag("ffffffff-ffff-ffff-ffff-ffffffffffff") 42 s.logger = loggo.GetLogger("test") 43 } 44 45 func (s *CAASApplicationSuite) TestWorkerStart(c *gc.C) { 46 ctrl := gomock.NewController(c) 47 defer ctrl.Finish() 48 49 appChan := make(chan []string, 1) 50 done := make(chan struct{}) 51 52 facade := mocks.NewMockCAASProvisionerFacade(ctrl) 53 runner := mocks.NewMockRunner(ctrl) 54 55 facade.EXPECT().WatchApplications().DoAndReturn(func() (watcher.StringsWatcher, error) { 56 appChan <- []string{"test"} 57 return watchertest.NewMockStringsWatcher(appChan), nil 58 }) 59 facade.EXPECT().ProvisionerConfig().Return(params.CAASApplicationProvisionerConfig{ 60 UnmanagedApplications: params.Entities{}, 61 }, nil) 62 facade.EXPECT().Life("test").Return(life.Alive, nil) 63 runner.EXPECT().Worker("test", gomock.Any()).Return(nil, errors.NotFoundf("")) 64 runner.EXPECT().StartWorker("test", gomock.Any()).DoAndReturn( 65 func(_ string, startFunc func() (worker.Worker, error)) error { 66 startFunc() 67 return nil 68 }, 69 ) 70 runner.EXPECT().Wait().AnyTimes().DoAndReturn(func() error { 71 <-done 72 return nil 73 }) 74 runner.EXPECT().Kill().AnyTimes() 75 76 called := false 77 newWorker := func(config caasapplicationprovisioner.AppWorkerConfig) func() (worker.Worker, error) { 78 c.Assert(called, jc.IsFalse) 79 called = true 80 mc := jc.NewMultiChecker() 81 mc.AddExpr("_.Facade", gc.NotNil) 82 mc.AddExpr("_.Broker", gc.NotNil) 83 mc.AddExpr("_.Clock", gc.NotNil) 84 mc.AddExpr("_.Logger", gc.NotNil) 85 mc.AddExpr("_.ShutDownCleanUpFunc", gc.NotNil) 86 c.Check(config, mc, caasapplicationprovisioner.AppWorkerConfig{ 87 Name: "test", 88 ModelTag: s.modelTag, 89 }) 90 return func() (worker.Worker, error) { 91 close(done) 92 return workertest.NewErrorWorker(nil), nil 93 } 94 } 95 config := caasapplicationprovisioner.Config{ 96 Facade: facade, 97 Broker: struct{ caas.Broker }{}, 98 ModelTag: s.modelTag, 99 Clock: s.clock, 100 Logger: s.logger, 101 NewAppWorker: newWorker, 102 } 103 provisioner, err := caasapplicationprovisioner.NewProvisionerWorkerForTest(config, runner) 104 c.Assert(err, jc.ErrorIsNil) 105 c.Assert(provisioner, gc.NotNil) 106 107 select { 108 case <-done: 109 c.Assert(called, jc.IsTrue) 110 case <-time.After(coretesting.LongWait): 111 c.Fatalf("timed out waiting for worker to start") 112 } 113 114 workertest.CleanKill(c, provisioner) 115 } 116 117 func (s *CAASApplicationSuite) TestWorkerStartUnmanaged(c *gc.C) { 118 ctrl := gomock.NewController(c) 119 defer ctrl.Finish() 120 121 appChan := make(chan []string, 1) 122 done := make(chan struct{}) 123 124 facade := mocks.NewMockCAASProvisionerFacade(ctrl) 125 runner := mocks.NewMockRunner(ctrl) 126 127 facade.EXPECT().WatchApplications().DoAndReturn(func() (watcher.StringsWatcher, error) { 128 appChan <- []string{"test"} 129 return watchertest.NewMockStringsWatcher(appChan), nil 130 }) 131 facade.EXPECT().ProvisionerConfig().Return(params.CAASApplicationProvisionerConfig{ 132 UnmanagedApplications: params.Entities{Entities: []params.Entity{{Tag: "application-test"}}}, 133 }, nil) 134 facade.EXPECT().Life("test").Return(life.Alive, nil) 135 runner.EXPECT().Worker("test", gomock.Any()).Return(nil, errors.NotFoundf("")) 136 runner.EXPECT().StartWorker("test", gomock.Any()).DoAndReturn( 137 func(_ string, startFunc func() (worker.Worker, error)) error { 138 startFunc() 139 return nil 140 }, 141 ) 142 runner.EXPECT().Wait().AnyTimes().DoAndReturn(func() error { 143 <-done 144 return nil 145 }) 146 runner.EXPECT().Kill().AnyTimes() 147 148 called := false 149 newWorker := func(config caasapplicationprovisioner.AppWorkerConfig) func() (worker.Worker, error) { 150 c.Assert(called, jc.IsFalse) 151 called = true 152 mc := jc.NewMultiChecker() 153 mc.AddExpr("_.Facade", gc.NotNil) 154 mc.AddExpr("_.Broker", gc.NotNil) 155 mc.AddExpr("_.Clock", gc.NotNil) 156 mc.AddExpr("_.Logger", gc.NotNil) 157 mc.AddExpr("_.ShutDownCleanUpFunc", gc.NotNil) 158 c.Check(config, mc, caasapplicationprovisioner.AppWorkerConfig{ 159 Name: "test", 160 ModelTag: s.modelTag, 161 StatusOnly: true, 162 }) 163 return func() (worker.Worker, error) { 164 close(done) 165 return workertest.NewErrorWorker(nil), nil 166 } 167 } 168 config := caasapplicationprovisioner.Config{ 169 Facade: facade, 170 Broker: struct{ caas.Broker }{}, 171 ModelTag: s.modelTag, 172 Clock: s.clock, 173 Logger: s.logger, 174 NewAppWorker: newWorker, 175 } 176 provisioner, err := caasapplicationprovisioner.NewProvisionerWorkerForTest(config, runner) 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(provisioner, gc.NotNil) 179 180 select { 181 case <-done: 182 c.Assert(called, jc.IsTrue) 183 case <-time.After(coretesting.LongWait): 184 c.Fatalf("timed out waiting for worker to start") 185 } 186 187 workertest.CleanKill(c, provisioner) 188 } 189 190 func (s *CAASApplicationSuite) TestWorkerStartOnceNotify(c *gc.C) { 191 ctrl := gomock.NewController(c) 192 defer ctrl.Finish() 193 194 appChan := make(chan []string, 5) 195 done := make(chan struct{}) 196 197 appChan <- []string{"test"} 198 appChan <- []string{"test"} 199 appChan <- []string{"test"} 200 appChan <- []string{"test"} 201 appChan <- []string{"test"} 202 facade := mocks.NewMockCAASProvisionerFacade(ctrl) 203 runner := mocks.NewMockRunner(ctrl) 204 205 var notifyWorker = &mockNotifyWorker{Worker: workertest.NewErrorWorker(nil)} 206 207 gomock.InOrder( 208 facade.EXPECT().WatchApplications().DoAndReturn(func() (watcher.StringsWatcher, error) { 209 return watchertest.NewMockStringsWatcher(appChan), nil 210 }), 211 facade.EXPECT().ProvisionerConfig().Return(params.CAASApplicationProvisionerConfig{}, nil), 212 facade.EXPECT().Life("test").Return(life.Alive, nil), 213 runner.EXPECT().Worker("test", gomock.Any()).Return(nil, errors.NotFoundf("")), 214 runner.EXPECT().StartWorker("test", gomock.Any()).DoAndReturn( 215 func(_ string, startFunc func() (worker.Worker, error)) error { 216 startFunc() 217 return nil 218 }, 219 ), 220 221 facade.EXPECT().Life("test").Return(life.Alive, nil), 222 runner.EXPECT().Worker("test", gomock.Any()).Return(notifyWorker, nil), 223 224 facade.EXPECT().Life("test").Return(life.Alive, nil), 225 runner.EXPECT().Worker("test", gomock.Any()).Return(notifyWorker, nil), 226 227 facade.EXPECT().Life("test").Return(life.Alive, nil), 228 runner.EXPECT().Worker("test", gomock.Any()).Return(notifyWorker, nil), 229 230 facade.EXPECT().Life("test").Return(life.Alive, nil), 231 runner.EXPECT().Worker("test", gomock.Any()).DoAndReturn( 232 func(_ string, abort <-chan struct{}) (worker.Worker, error) { 233 close(done) 234 return nil, worker.ErrDead 235 }, 236 ), 237 ) 238 runner.EXPECT().Wait().AnyTimes().DoAndReturn(func() error { 239 <-done 240 return nil 241 }) 242 runner.EXPECT().Kill().AnyTimes() 243 244 called := 0 245 newWorker := func(config caasapplicationprovisioner.AppWorkerConfig) func() (worker.Worker, error) { 246 called++ 247 mc := jc.NewMultiChecker() 248 mc.AddExpr("_.Facade", gc.NotNil) 249 mc.AddExpr("_.Broker", gc.NotNil) 250 mc.AddExpr("_.Clock", gc.NotNil) 251 mc.AddExpr("_.Logger", gc.NotNil) 252 mc.AddExpr("_.ShutDownCleanUpFunc", gc.NotNil) 253 c.Check(config, mc, caasapplicationprovisioner.AppWorkerConfig{ 254 Name: "test", 255 ModelTag: s.modelTag, 256 }) 257 return func() (worker.Worker, error) { 258 return notifyWorker, nil 259 } 260 } 261 config := caasapplicationprovisioner.Config{ 262 Facade: facade, 263 Broker: struct{ caas.Broker }{}, 264 ModelTag: s.modelTag, 265 Clock: s.clock, 266 Logger: s.logger, 267 NewAppWorker: newWorker, 268 } 269 provisioner, err := caasapplicationprovisioner.NewProvisionerWorkerForTest(config, runner) 270 c.Assert(err, jc.ErrorIsNil) 271 c.Assert(provisioner, gc.NotNil) 272 273 select { 274 case <-done: 275 case <-time.After(coretesting.LongWait): 276 c.Fatalf("timed out waiting for worker to start") 277 } 278 279 c.Assert(called, gc.Equals, 1) 280 c.Assert(notifyWorker, gc.NotNil) 281 select { 282 case <-time.After(coretesting.ShortWait): 283 workertest.CleanKill(c, provisioner) 284 notifyWorker.CheckCallNames(c, "Notify", "Notify", "Notify") 285 } 286 }