github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/operation/util_test.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package operation_test 5 6 import ( 7 "sync" 8 9 "github.com/juju/charm/v12/hooks" 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 "github.com/juju/testing" 13 utilexec "github.com/juju/utils/v3/exec" 14 15 "github.com/juju/juju/api/agent/uniter" 16 "github.com/juju/juju/core/model" 17 "github.com/juju/juju/core/relation" 18 "github.com/juju/juju/core/secrets" 19 "github.com/juju/juju/worker/uniter/charm" 20 "github.com/juju/juju/worker/uniter/hook" 21 "github.com/juju/juju/worker/uniter/operation" 22 "github.com/juju/juju/worker/uniter/remotestate" 23 "github.com/juju/juju/worker/uniter/runner" 24 runnercontext "github.com/juju/juju/worker/uniter/runner/context" 25 "github.com/juju/juju/worker/uniter/runner/jujuc" 26 ) 27 28 type MockGetArchiveInfo struct { 29 gotCharmURL string 30 info charm.BundleInfo 31 err error 32 } 33 34 func (mock *MockGetArchiveInfo) Call(charmURL string) (charm.BundleInfo, error) { 35 mock.gotCharmURL = charmURL 36 return mock.info, mock.err 37 } 38 39 type MockSetCurrentCharm struct { 40 gotCharmURL string 41 err error 42 } 43 44 func (mock *MockSetCurrentCharm) Call(charmURL string) error { 45 mock.gotCharmURL = charmURL 46 return mock.err 47 } 48 49 type DeployCallbacks struct { 50 operation.Callbacks 51 *MockGetArchiveInfo 52 *MockSetCurrentCharm 53 MockInitializeMetricsTimers *MockNoArgs 54 } 55 56 func (cb *DeployCallbacks) GetArchiveInfo(charmURL string) (charm.BundleInfo, error) { 57 return cb.MockGetArchiveInfo.Call(charmURL) 58 } 59 60 func (cb *DeployCallbacks) SetCurrentCharm(charmURL string) error { 61 return cb.MockSetCurrentCharm.Call(charmURL) 62 } 63 64 func (cb *DeployCallbacks) InitializeMetricsTimers() error { 65 return cb.MockInitializeMetricsTimers.Call() 66 } 67 68 type MockBundleInfo struct { 69 charm.BundleInfo 70 } 71 72 type MockStage struct { 73 gotInfo *charm.BundleInfo 74 gotAbort *<-chan struct{} 75 err error 76 } 77 78 func (mock *MockStage) Call(info charm.BundleInfo, abort <-chan struct{}) error { 79 mock.gotInfo = &info 80 mock.gotAbort = &abort 81 return mock.err 82 } 83 84 type MockNoArgs struct { 85 called bool 86 err error 87 } 88 89 func (mock *MockNoArgs) Call() error { 90 mock.called = true 91 return mock.err 92 } 93 94 type MockDeployer struct { 95 charm.Deployer 96 *MockStage 97 MockDeploy *MockNoArgs 98 MockNotifyRevert *MockNoArgs 99 MockNotifyResolved *MockNoArgs 100 } 101 102 func (d *MockDeployer) Stage(info charm.BundleInfo, abort <-chan struct{}) error { 103 return d.MockStage.Call(info, abort) 104 } 105 106 func (d *MockDeployer) Deploy() error { 107 return d.MockDeploy.Call() 108 } 109 110 type MockFailAction struct { 111 gotActionId *string 112 gotMessage *string 113 err error 114 } 115 116 func (mock *MockFailAction) Call(actionId, message string) error { 117 mock.gotActionId = &actionId 118 mock.gotMessage = &message 119 return mock.err 120 } 121 122 type RunActionCallbacks struct { 123 operation.Callbacks 124 *MockFailAction 125 executingMessage string 126 actionStatus string 127 actionStatusErr error 128 mut sync.Mutex 129 } 130 131 func (cb *RunActionCallbacks) FailAction(actionId, message string) error { 132 return cb.MockFailAction.Call(actionId, message) 133 } 134 135 func (cb *RunActionCallbacks) SetExecutingStatus(message string) error { 136 cb.mut.Lock() 137 defer cb.mut.Unlock() 138 cb.executingMessage = message 139 return nil 140 } 141 142 func (cb *RunActionCallbacks) ActionStatus(actionId string) (string, error) { 143 cb.mut.Lock() 144 defer cb.mut.Unlock() 145 return cb.actionStatus, cb.actionStatusErr 146 } 147 148 func (cb *RunActionCallbacks) setActionStatus(status string, err error) { 149 cb.mut.Lock() 150 defer cb.mut.Unlock() 151 cb.actionStatus = status 152 cb.actionStatusErr = err 153 } 154 155 type RunCommandsCallbacks struct { 156 operation.Callbacks 157 executingMessage string 158 } 159 160 func (cb *RunCommandsCallbacks) SetExecutingStatus(message string) error { 161 cb.executingMessage = message 162 return nil 163 } 164 165 type MockPrepareHook struct { 166 gotHook *hook.Info 167 name string 168 err error 169 } 170 171 func (mock *MockPrepareHook) Call(hookInfo hook.Info) (string, error) { 172 mock.gotHook = &hookInfo 173 return mock.name, mock.err 174 } 175 176 type PrepareHookCallbacks struct { 177 operation.Callbacks 178 *MockPrepareHook 179 executingMessage string 180 } 181 182 func (cb *PrepareHookCallbacks) PrepareHook(hookInfo hook.Info) (string, error) { 183 return cb.MockPrepareHook.Call(hookInfo) 184 } 185 186 func (cb *PrepareHookCallbacks) SetExecutingStatus(message string) error { 187 cb.executingMessage = message 188 return nil 189 } 190 191 func (cb *PrepareHookCallbacks) SetUpgradeSeriesStatus(model.UpgradeSeriesStatus, string) error { 192 return nil 193 } 194 195 type MockNotify struct { 196 gotName *string 197 gotContext *runnercontext.Context 198 } 199 200 func (mock *MockNotify) Call(hookName string, ctx runnercontext.Context) { 201 mock.gotName = &hookName 202 mock.gotContext = &ctx 203 } 204 205 type ExecuteHookCallbacks struct { 206 *PrepareHookCallbacks 207 MockNotifyHookCompleted *MockNotify 208 MockNotifyHookFailed *MockNotify 209 } 210 211 func (cb *ExecuteHookCallbacks) NotifyHookCompleted(hookName string, ctx runnercontext.Context) { 212 cb.MockNotifyHookCompleted.Call(hookName, ctx) 213 } 214 215 func (cb *ExecuteHookCallbacks) NotifyHookFailed(hookName string, ctx runnercontext.Context) { 216 cb.MockNotifyHookFailed.Call(hookName, ctx) 217 } 218 219 type MockCommitHook struct { 220 gotHook *hook.Info 221 err error 222 } 223 224 func (mock *MockCommitHook) Call(hookInfo hook.Info) error { 225 mock.gotHook = &hookInfo 226 return mock.err 227 } 228 229 type CommitHookCallbacks struct { 230 operation.Callbacks 231 *MockCommitHook 232 233 rotatedSecretURI string 234 rotatedOldRevision int 235 } 236 237 func (cb *CommitHookCallbacks) PrepareHook(hookInfo hook.Info) (string, error) { 238 return "", nil 239 } 240 241 func (cb *CommitHookCallbacks) CommitHook(hookInfo hook.Info) error { 242 return cb.MockCommitHook.Call(hookInfo) 243 } 244 245 func (cb *CommitHookCallbacks) SetSecretRotated(url string, oldRevision int) error { 246 cb.rotatedSecretURI = url 247 cb.rotatedOldRevision = oldRevision 248 return nil 249 } 250 251 type MockNewActionRunner struct { 252 gotActionId *string 253 gotCancel <-chan struct{} 254 runner *MockRunner 255 err error 256 } 257 258 func (mock *MockNewActionRunner) Call(actionId string, cancel <-chan struct{}) (runner.Runner, error) { 259 mock.gotActionId = &actionId 260 mock.gotCancel = cancel 261 return mock.runner, mock.err 262 } 263 264 type MockNewActionWaitRunner struct { 265 gotActionId *string 266 gotCancel <-chan struct{} 267 runner *MockActionWaitRunner 268 err error 269 } 270 271 func (mock *MockNewActionWaitRunner) Call(actionId string, cancel <-chan struct{}) (runner.Runner, error) { 272 mock.gotActionId = &actionId 273 mock.gotCancel = cancel 274 mock.runner.context.(*MockContext).actionData.Cancel = cancel 275 return mock.runner, mock.err 276 } 277 278 type MockNewHookRunner struct { 279 gotHook *hook.Info 280 runner *MockRunner 281 err error 282 } 283 284 func (mock *MockNewHookRunner) Call(hookInfo hook.Info) (runner.Runner, error) { 285 mock.gotHook = &hookInfo 286 return mock.runner, mock.err 287 } 288 289 type MockNewCommandRunner struct { 290 gotInfo *runnercontext.CommandInfo 291 runner *MockRunner 292 err error 293 } 294 295 func (mock *MockNewCommandRunner) Call(info runnercontext.CommandInfo) (runner.Runner, error) { 296 mock.gotInfo = &info 297 return mock.runner, mock.err 298 } 299 300 type MockRunnerFactory struct { 301 *MockNewActionRunner 302 *MockNewHookRunner 303 *MockNewCommandRunner 304 } 305 306 func (f *MockRunnerFactory) NewActionRunner(action *uniter.Action, cancel <-chan struct{}) (runner.Runner, error) { 307 return f.MockNewActionRunner.Call(action.ID(), cancel) 308 } 309 310 func (f *MockRunnerFactory) NewHookRunner(hookInfo hook.Info) (runner.Runner, error) { 311 return f.MockNewHookRunner.Call(hookInfo) 312 } 313 314 func (f *MockRunnerFactory) NewCommandRunner(commandInfo runnercontext.CommandInfo) (runner.Runner, error) { 315 return f.MockNewCommandRunner.Call(commandInfo) 316 } 317 318 type MockRunnerActionWaitFactory struct { 319 runner.Factory 320 *MockNewActionWaitRunner 321 } 322 323 func (f *MockRunnerActionWaitFactory) NewActionRunner(action *uniter.Action, cancel <-chan struct{}) (runner.Runner, error) { 324 return f.MockNewActionWaitRunner.Call(action.ID(), cancel) 325 } 326 327 type MockContext struct { 328 runnercontext.Context 329 testing.Stub 330 actionData *runnercontext.ActionData 331 setStatusCalled bool 332 status jujuc.StatusInfo 333 isLeader bool 334 relation *MockRelation 335 } 336 337 func (mock *MockContext) SecretMetadata() (map[string]jujuc.SecretMetadata, error) { 338 return map[string]jujuc.SecretMetadata{ 339 "9m4e2mr0ui3e8a215n4g": { 340 Description: "description", 341 Label: "label", 342 Owner: names.NewApplicationTag("mariadb"), 343 RotatePolicy: secrets.RotateHourly, 344 LatestRevision: 666, 345 }, 346 }, nil 347 } 348 349 func (mock *MockContext) ActionData() (*runnercontext.ActionData, error) { 350 if mock.actionData == nil { 351 return nil, errors.New("not an action context") 352 } 353 return mock.actionData, nil 354 } 355 356 func (mock *MockContext) HasExecutionSetUnitStatus() bool { 357 return mock.setStatusCalled 358 } 359 360 func (mock *MockContext) ResetExecutionSetUnitStatus() { 361 mock.setStatusCalled = false 362 } 363 364 func (mock *MockContext) SetUnitStatus(status jujuc.StatusInfo) error { 365 mock.setStatusCalled = true 366 mock.status = status 367 return nil 368 } 369 370 func (mock *MockContext) UnitName() string { 371 return "unit/0" 372 } 373 374 func (mock *MockContext) UnitStatus() (*jujuc.StatusInfo, error) { 375 return &mock.status, nil 376 } 377 378 func (mock *MockContext) Prepare() error { 379 mock.MethodCall(mock, "Prepare") 380 return mock.NextErr() 381 } 382 383 func (mock *MockContext) IsLeader() (bool, error) { 384 return mock.isLeader, nil 385 } 386 387 func (mock *MockContext) Relation(id int) (jujuc.ContextRelation, error) { 388 return mock.relation, nil 389 } 390 391 type MockRelation struct { 392 jujuc.ContextRelation 393 suspended bool 394 status relation.Status 395 } 396 397 func (mock *MockRelation) Suspended() bool { 398 return mock.suspended 399 } 400 401 func (mock *MockRelation) SetStatus(status relation.Status) error { 402 mock.status = status 403 return nil 404 } 405 406 type MockRunAction struct { 407 gotName *string 408 err error 409 } 410 411 func (mock *MockRunAction) Call(actionName string) error { 412 mock.gotName = &actionName 413 return mock.err 414 } 415 416 type MockRunCommands struct { 417 gotCommands *string 418 gotRunLocation *runner.RunLocation 419 response *utilexec.ExecResponse 420 err error 421 } 422 423 func (mock *MockRunCommands) Call(commands string, runLocation runner.RunLocation) (*utilexec.ExecResponse, error) { 424 mock.gotCommands = &commands 425 mock.gotRunLocation = &runLocation 426 return mock.response, mock.err 427 } 428 429 type MockRunHook struct { 430 gotName *string 431 err error 432 setStatusCalled bool 433 } 434 435 func (mock *MockRunHook) Call(hookName string) error { 436 mock.gotName = &hookName 437 return mock.err 438 } 439 440 type MockRunner struct { 441 *MockRunAction 442 *MockRunCommands 443 *MockRunHook 444 context runnercontext.Context 445 } 446 447 func (r *MockRunner) Context() runnercontext.Context { 448 return r.context 449 } 450 451 func (r *MockRunner) RunAction(actionName string) (runner.HookHandlerType, error) { 452 return runner.ExplicitHookHandler, r.MockRunAction.Call(actionName) 453 } 454 455 func (r *MockRunner) RunCommands(commands string, runLocation runner.RunLocation) (*utilexec.ExecResponse, error) { 456 return r.MockRunCommands.Call(commands, runLocation) 457 } 458 459 func (r *MockRunner) RunHook(hookName string) (runner.HookHandlerType, error) { 460 r.Context().(*MockContext).setStatusCalled = r.MockRunHook.setStatusCalled 461 return runner.ExplicitHookHandler, r.MockRunHook.Call(hookName) 462 } 463 464 type MockActionWaitRunner struct { 465 runner.Runner 466 467 context runnercontext.Context 468 actionChan <-chan error 469 470 actionName string 471 } 472 473 func (r *MockActionWaitRunner) Context() runnercontext.Context { 474 return r.context 475 } 476 477 func (r *MockActionWaitRunner) RunAction(actionName string) (runner.HookHandlerType, error) { 478 r.actionName = actionName 479 return runner.ExplicitHookHandler, <-r.actionChan 480 } 481 482 func NewDeployCallbacks() *DeployCallbacks { 483 return &DeployCallbacks{ 484 MockGetArchiveInfo: &MockGetArchiveInfo{info: &MockBundleInfo{}}, 485 MockSetCurrentCharm: &MockSetCurrentCharm{}, 486 } 487 } 488 489 func NewDeployCommitCallbacks(err error) *DeployCallbacks { 490 return &DeployCallbacks{ 491 MockInitializeMetricsTimers: &MockNoArgs{err: err}, 492 } 493 } 494 func NewMockDeployer() *MockDeployer { 495 return &MockDeployer{ 496 MockStage: &MockStage{}, 497 MockDeploy: &MockNoArgs{}, 498 MockNotifyRevert: &MockNoArgs{}, 499 MockNotifyResolved: &MockNoArgs{}, 500 } 501 } 502 503 func NewPrepareHookCallbacks(kind hooks.Kind) *PrepareHookCallbacks { 504 return &PrepareHookCallbacks{ 505 MockPrepareHook: &MockPrepareHook{nil, string(kind), nil}, 506 } 507 } 508 509 func NewRunActionRunnerFactory(runErr error) *MockRunnerFactory { 510 return &MockRunnerFactory{ 511 MockNewActionRunner: &MockNewActionRunner{ 512 runner: &MockRunner{ 513 MockRunAction: &MockRunAction{err: runErr}, 514 context: &MockContext{ 515 actionData: &runnercontext.ActionData{Name: "some-action-name"}, 516 }, 517 }, 518 }, 519 } 520 } 521 522 func NewRunActionWaitRunnerFactory(actionChan <-chan error) *MockRunnerActionWaitFactory { 523 return &MockRunnerActionWaitFactory{ 524 MockNewActionWaitRunner: &MockNewActionWaitRunner{ 525 runner: &MockActionWaitRunner{ 526 actionChan: actionChan, 527 context: &MockContext{ 528 actionData: &runnercontext.ActionData{ 529 Name: "some-action-name", 530 }, 531 }, 532 }, 533 }, 534 } 535 } 536 537 func NewRunCommandsRunnerFactory(runResponse *utilexec.ExecResponse, runErr error) *MockRunnerFactory { 538 return &MockRunnerFactory{ 539 MockNewCommandRunner: &MockNewCommandRunner{ 540 runner: &MockRunner{ 541 MockRunCommands: &MockRunCommands{response: runResponse, err: runErr}, 542 context: &MockContext{}, 543 }, 544 }, 545 } 546 } 547 548 func NewRunHookRunnerFactory(runErr error, contextOps ...func(*MockContext)) *MockRunnerFactory { 549 ctx := &MockContext{isLeader: true} 550 for _, op := range contextOps { 551 op(ctx) 552 } 553 554 return &MockRunnerFactory{ 555 MockNewHookRunner: &MockNewHookRunner{ 556 runner: &MockRunner{ 557 MockRunHook: &MockRunHook{err: runErr}, 558 context: ctx, 559 }, 560 }, 561 } 562 } 563 564 type MockSendResponse struct { 565 gotResponse **utilexec.ExecResponse 566 gotErr *error 567 eatError bool 568 } 569 570 func (mock *MockSendResponse) Call(response *utilexec.ExecResponse, err error) bool { 571 mock.gotResponse = &response 572 mock.gotErr = &err 573 return mock.eatError 574 } 575 576 var someActionId = "f47ac10b-58cc-4372-a567-0e02b2c3d479" 577 var randomActionId = "9f484882-2f18-4fd2-967d-db9663db7bea" 578 var overwriteState = operation.State{ 579 Kind: operation.Continue, 580 Step: operation.Pending, 581 Started: true, 582 CharmURL: "ch:quantal/wordpress-2", 583 ActionId: &randomActionId, 584 Hook: &hook.Info{Kind: hooks.Install}, 585 } 586 var someCommandArgs = operation.CommandArgs{ 587 Commands: "do something", 588 RelationId: 123, 589 RemoteUnitName: "foo/456", 590 ForceRemoteUnit: true, 591 RunLocation: runner.Workload, 592 } 593 594 type RemoteInitCallbacks struct { 595 operation.Callbacks 596 MockRemoteInit *MockRemoteInit 597 } 598 599 func (cb *RemoteInitCallbacks) RemoteInit(runningStatus remotestate.ContainerRunningStatus, abort <-chan struct{}) error { 600 return cb.MockRemoteInit.Call(runningStatus, abort) 601 } 602 603 type MockRemoteInit struct { 604 gotRunningStatus *remotestate.ContainerRunningStatus 605 gotAbort <-chan struct{} 606 err error 607 } 608 609 func (mock *MockRemoteInit) Call(runningStatus remotestate.ContainerRunningStatus, abort <-chan struct{}) error { 610 mock.gotRunningStatus = &runningStatus 611 mock.gotAbort = abort 612 return mock.err 613 }