github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/uniter/operation/runhook_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 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v5/hooks" 14 15 "github.com/juju/juju/worker/uniter/hook" 16 "github.com/juju/juju/worker/uniter/operation" 17 "github.com/juju/juju/worker/uniter/runner" 18 "github.com/juju/juju/worker/uniter/runner/jujuc" 19 ) 20 21 type RunHookSuite struct { 22 testing.IsolationSuite 23 } 24 25 var _ = gc.Suite(&RunHookSuite{}) 26 27 type newHook func(operation.Factory, hook.Info) (operation.Operation, error) 28 29 func (s *RunHookSuite) testClearResolvedFlagError(c *gc.C, newHook newHook) { 30 callbacks := &PrepareHookCallbacks{ 31 MockClearResolvedFlag: &MockNoArgs{err: errors.New("biff")}, 32 } 33 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 34 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 35 c.Assert(err, jc.ErrorIsNil) 36 37 newState, err := op.Prepare(operation.State{}) 38 c.Check(newState, gc.IsNil) 39 c.Check(callbacks.MockClearResolvedFlag.called, jc.IsTrue) 40 c.Check(err, gc.ErrorMatches, "biff") 41 } 42 43 func (s *RunHookSuite) TestClearResolvedFlagError_Retry(c *gc.C) { 44 s.testClearResolvedFlagError(c, (operation.Factory).NewRetryHook) 45 } 46 47 func (s *RunHookSuite) TestClearResolvedFlagError_Skip(c *gc.C) { 48 s.testClearResolvedFlagError(c, (operation.Factory).NewSkipHook) 49 } 50 51 func (s *RunHookSuite) testPrepareHookError( 52 c *gc.C, newHook newHook, expectClearResolvedFlag, expectSkip bool, 53 ) { 54 callbacks := &PrepareHookCallbacks{ 55 MockPrepareHook: &MockPrepareHook{err: errors.New("pow")}, 56 MockClearResolvedFlag: &MockNoArgs{}, 57 } 58 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 59 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 60 c.Assert(err, jc.ErrorIsNil) 61 62 newState, err := op.Prepare(operation.State{}) 63 c.Check(newState, gc.IsNil) 64 c.Check(callbacks.MockClearResolvedFlag.called, gc.Equals, expectClearResolvedFlag) 65 if expectSkip { 66 c.Check(err, gc.Equals, operation.ErrSkipExecute) 67 c.Check(callbacks.MockPrepareHook.gotHook, gc.IsNil) 68 return 69 } 70 c.Check(err, gc.ErrorMatches, "pow") 71 c.Check(callbacks.MockPrepareHook.gotHook, gc.DeepEquals, &hook.Info{ 72 Kind: hooks.ConfigChanged, 73 }) 74 } 75 76 func (s *RunHookSuite) TestPrepareHookError_Run(c *gc.C) { 77 s.testPrepareHookError(c, (operation.Factory).NewRunHook, false, false) 78 } 79 80 func (s *RunHookSuite) TestPrepareHookError_Retry(c *gc.C) { 81 s.testPrepareHookError(c, (operation.Factory).NewRetryHook, true, false) 82 } 83 84 func (s *RunHookSuite) TestPrepareHookError_Skip(c *gc.C) { 85 s.testPrepareHookError(c, (operation.Factory).NewSkipHook, true, true) 86 } 87 88 func (s *RunHookSuite) testPrepareRunnerError(c *gc.C, newHook newHook) { 89 callbacks := NewPrepareHookCallbacks() 90 runnerFactory := &MockRunnerFactory{ 91 MockNewHookRunner: &MockNewHookRunner{err: errors.New("splat")}, 92 } 93 factory := operation.NewFactory(nil, runnerFactory, callbacks, nil, nil) 94 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 95 c.Assert(err, jc.ErrorIsNil) 96 97 newState, err := op.Prepare(operation.State{}) 98 c.Check(newState, gc.IsNil) 99 c.Check(err, gc.ErrorMatches, "splat") 100 c.Check(runnerFactory.MockNewHookRunner.gotHook, gc.DeepEquals, &hook.Info{ 101 Kind: hooks.ConfigChanged, 102 }) 103 } 104 105 func (s *RunHookSuite) TestPrepareRunnerError_Run(c *gc.C) { 106 s.testPrepareRunnerError(c, (operation.Factory).NewRunHook) 107 } 108 109 func (s *RunHookSuite) TestPrepareRunnerError_Retry(c *gc.C) { 110 s.testPrepareRunnerError(c, (operation.Factory).NewRetryHook) 111 } 112 113 func (s *RunHookSuite) testPrepareSuccess( 114 c *gc.C, newHook newHook, before, after operation.State, 115 ) { 116 runnerFactory := NewRunHookRunnerFactory(errors.New("should not call")) 117 callbacks := NewPrepareHookCallbacks() 118 factory := operation.NewFactory(nil, runnerFactory, callbacks, nil, nil) 119 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 120 c.Assert(err, jc.ErrorIsNil) 121 122 newState, err := op.Prepare(before) 123 c.Check(err, jc.ErrorIsNil) 124 c.Check(newState, gc.DeepEquals, &after) 125 } 126 127 func (s *RunHookSuite) TestPrepareSuccess_BlankSlate(c *gc.C) { 128 for i, newHook := range []newHook{ 129 (operation.Factory).NewRunHook, 130 (operation.Factory).NewRetryHook, 131 } { 132 c.Logf("variant %d", i) 133 s.testPrepareSuccess(c, 134 newHook, 135 operation.State{}, 136 operation.State{ 137 Kind: operation.RunHook, 138 Step: operation.Pending, 139 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 140 }, 141 ) 142 } 143 } 144 145 func (s *RunHookSuite) TestPrepareSuccess_Preserve(c *gc.C) { 146 for i, newHook := range []newHook{ 147 (operation.Factory).NewRunHook, 148 (operation.Factory).NewRetryHook, 149 } { 150 c.Logf("variant %d", i) 151 s.testPrepareSuccess(c, 152 newHook, 153 overwriteState, 154 operation.State{ 155 Started: true, 156 CollectMetricsTime: 1234567, 157 UpdateStatusTime: 1234567, 158 Kind: operation.RunHook, 159 Step: operation.Pending, 160 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 161 }, 162 ) 163 } 164 } 165 166 func (s *RunHookSuite) getExecuteRunnerTest(c *gc.C, newHook newHook, kind hooks.Kind, runErr error) (operation.Operation, *ExecuteHookCallbacks, *MockRunnerFactory) { 167 runnerFactory := NewRunHookRunnerFactory(runErr) 168 callbacks := &ExecuteHookCallbacks{ 169 PrepareHookCallbacks: NewPrepareHookCallbacks(), 170 MockNotifyHookCompleted: &MockNotify{}, 171 MockNotifyHookFailed: &MockNotify{}, 172 } 173 factory := operation.NewFactory(nil, runnerFactory, callbacks, nil, nil) 174 op, err := newHook(factory, hook.Info{Kind: kind}) 175 c.Assert(err, jc.ErrorIsNil) 176 return op, callbacks, runnerFactory 177 } 178 179 func (s *RunHookSuite) testExecuteMissingHookError(c *gc.C, newHook newHook) { 180 runErr := runner.NewMissingHookError("blah-blah") 181 for _, kind := range hooks.UnitHooks() { 182 c.Logf("hook %v", kind) 183 op, callbacks, runnerFactory := s.getExecuteRunnerTest(c, newHook, kind, runErr) 184 _, err := op.Prepare(operation.State{}) 185 c.Assert(err, jc.ErrorIsNil) 186 187 newState, err := op.Execute(operation.State{}) 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(newState, gc.DeepEquals, &operation.State{ 190 Kind: operation.RunHook, 191 Step: operation.Done, 192 Hook: &hook.Info{Kind: kind}, 193 }) 194 c.Assert(*runnerFactory.MockNewHookRunner.runner.MockRunHook.gotName, gc.Equals, "some-hook-name") 195 c.Assert(callbacks.MockNotifyHookCompleted.gotName, gc.IsNil) 196 c.Assert(callbacks.MockNotifyHookFailed.gotName, gc.IsNil) 197 198 status, err := runnerFactory.MockNewHookRunner.runner.Context().UnitStatus() 199 c.Assert(err, jc.ErrorIsNil) 200 testAfterHookStatus(c, kind, status, false) 201 } 202 } 203 204 func (s *RunHookSuite) TestExecuteMissingHookError_Run(c *gc.C) { 205 s.testExecuteMissingHookError(c, (operation.Factory).NewRunHook) 206 } 207 208 func (s *RunHookSuite) TestExecuteMissingHookError_Retry(c *gc.C) { 209 s.testExecuteMissingHookError(c, (operation.Factory).NewRetryHook) 210 } 211 212 func (s *RunHookSuite) testExecuteRequeueRebootError(c *gc.C, newHook newHook) { 213 runErr := runner.ErrRequeueAndReboot 214 op, callbacks, runnerFactory := s.getExecuteRunnerTest(c, newHook, hooks.ConfigChanged, runErr) 215 _, err := op.Prepare(operation.State{}) 216 c.Assert(err, jc.ErrorIsNil) 217 218 newState, err := op.Execute(operation.State{}) 219 c.Assert(err, gc.Equals, operation.ErrNeedsReboot) 220 c.Assert(newState, gc.DeepEquals, &operation.State{ 221 Kind: operation.RunHook, 222 Step: operation.Queued, 223 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 224 }) 225 c.Assert(*runnerFactory.MockNewHookRunner.runner.MockRunHook.gotName, gc.Equals, "some-hook-name") 226 c.Assert(*callbacks.MockNotifyHookCompleted.gotName, gc.Equals, "some-hook-name") 227 c.Assert(*callbacks.MockNotifyHookCompleted.gotContext, gc.Equals, runnerFactory.MockNewHookRunner.runner.context) 228 c.Assert(callbacks.MockNotifyHookFailed.gotName, gc.IsNil) 229 } 230 231 func (s *RunHookSuite) TestExecuteRequeueRebootError_Run(c *gc.C) { 232 s.testExecuteRequeueRebootError(c, (operation.Factory).NewRunHook) 233 } 234 235 func (s *RunHookSuite) TestExecuteRequeueRebootError_Retry(c *gc.C) { 236 s.testExecuteRequeueRebootError(c, (operation.Factory).NewRetryHook) 237 } 238 239 func (s *RunHookSuite) testExecuteRebootError(c *gc.C, newHook newHook) { 240 runErr := runner.ErrReboot 241 op, callbacks, runnerFactory := s.getExecuteRunnerTest(c, newHook, hooks.ConfigChanged, runErr) 242 _, err := op.Prepare(operation.State{}) 243 c.Assert(err, jc.ErrorIsNil) 244 245 newState, err := op.Execute(operation.State{}) 246 c.Assert(err, gc.Equals, operation.ErrNeedsReboot) 247 c.Assert(newState, gc.DeepEquals, &operation.State{ 248 Kind: operation.RunHook, 249 Step: operation.Done, 250 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 251 }) 252 c.Assert(*runnerFactory.MockNewHookRunner.runner.MockRunHook.gotName, gc.Equals, "some-hook-name") 253 c.Assert(*callbacks.MockNotifyHookCompleted.gotName, gc.Equals, "some-hook-name") 254 c.Assert(*callbacks.MockNotifyHookCompleted.gotContext, gc.Equals, runnerFactory.MockNewHookRunner.runner.context) 255 c.Assert(callbacks.MockNotifyHookFailed.gotName, gc.IsNil) 256 } 257 258 func (s *RunHookSuite) TestExecuteRebootError_Run(c *gc.C) { 259 s.testExecuteRebootError(c, (operation.Factory).NewRunHook) 260 } 261 262 func (s *RunHookSuite) TestExecuteRebootError_Retry(c *gc.C) { 263 s.testExecuteRebootError(c, (operation.Factory).NewRetryHook) 264 } 265 266 func (s *RunHookSuite) testExecuteOtherError(c *gc.C, newHook newHook) { 267 runErr := errors.New("graaargh") 268 op, callbacks, runnerFactory := s.getExecuteRunnerTest(c, newHook, hooks.ConfigChanged, runErr) 269 _, err := op.Prepare(operation.State{}) 270 c.Assert(err, jc.ErrorIsNil) 271 272 newState, err := op.Execute(operation.State{}) 273 c.Assert(err, gc.Equals, operation.ErrHookFailed) 274 c.Assert(newState, gc.IsNil) 275 c.Assert(*runnerFactory.MockNewHookRunner.runner.MockRunHook.gotName, gc.Equals, "some-hook-name") 276 c.Assert(*callbacks.MockNotifyHookFailed.gotName, gc.Equals, "some-hook-name") 277 c.Assert(*callbacks.MockNotifyHookFailed.gotContext, gc.Equals, runnerFactory.MockNewHookRunner.runner.context) 278 c.Assert(callbacks.MockNotifyHookCompleted.gotName, gc.IsNil) 279 } 280 281 func (s *RunHookSuite) TestExecuteOtherError_Run(c *gc.C) { 282 s.testExecuteOtherError(c, (operation.Factory).NewRunHook) 283 } 284 285 func (s *RunHookSuite) TestExecuteOtherError_Retry(c *gc.C) { 286 s.testExecuteOtherError(c, (operation.Factory).NewRetryHook) 287 } 288 289 func (s *RunHookSuite) testExecuteSuccess( 290 c *gc.C, newHook newHook, before, after operation.State, setStatusCalled bool, 291 ) { 292 op, callbacks, f := s.getExecuteRunnerTest(c, newHook, hooks.ConfigChanged, nil) 293 f.MockNewHookRunner.runner.MockRunHook.setStatusCalled = setStatusCalled 294 midState, err := op.Prepare(before) 295 c.Assert(err, jc.ErrorIsNil) 296 c.Assert(midState, gc.NotNil) 297 298 newState, err := op.Execute(*midState) 299 c.Assert(err, jc.ErrorIsNil) 300 c.Assert(newState, gc.DeepEquals, &after) 301 c.Check(callbacks.executingMessage, gc.Equals, "running some-hook-name hook") 302 } 303 304 func (s *RunHookSuite) TestExecuteSuccess_BlankSlate(c *gc.C) { 305 for i, newHook := range []newHook{ 306 (operation.Factory).NewRunHook, 307 (operation.Factory).NewRetryHook, 308 } { 309 c.Logf("variant %d", i) 310 s.testExecuteSuccess(c, 311 newHook, 312 operation.State{}, 313 operation.State{ 314 Kind: operation.RunHook, 315 Step: operation.Done, 316 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 317 StatusSet: true, 318 }, 319 true, 320 ) 321 } 322 } 323 324 func (s *RunHookSuite) TestExecuteSuccess_Preserve(c *gc.C) { 325 for i, newHook := range []newHook{ 326 (operation.Factory).NewRunHook, 327 (operation.Factory).NewRetryHook, 328 } { 329 c.Logf("variant %d", i) 330 s.testExecuteSuccess(c, 331 newHook, 332 overwriteState, 333 operation.State{ 334 Started: true, 335 CollectMetricsTime: 1234567, 336 UpdateStatusTime: 1234567, 337 Kind: operation.RunHook, 338 Step: operation.Done, 339 Hook: &hook.Info{Kind: hooks.ConfigChanged}, 340 StatusSet: true, 341 }, 342 true, 343 ) 344 } 345 } 346 347 func (s *RunHookSuite) testExecuteThenCharmStatus( 348 c *gc.C, newHook newHook, before, after operation.State, kind hooks.Kind, setStatusCalled bool, 349 ) { 350 op, _, f := s.getExecuteRunnerTest(c, newHook, kind, nil) 351 f.MockNewHookRunner.runner.MockRunHook.setStatusCalled = setStatusCalled 352 midState, err := op.Prepare(before) 353 c.Assert(err, jc.ErrorIsNil) 354 c.Assert(midState, gc.NotNil) 355 356 status, err := f.MockNewHookRunner.runner.Context().UnitStatus() 357 c.Assert(err, jc.ErrorIsNil) 358 359 newState, err := op.Execute(*midState) 360 c.Assert(err, jc.ErrorIsNil) 361 c.Assert(newState, gc.DeepEquals, &after) 362 363 status, err = f.MockNewHookRunner.runner.Context().UnitStatus() 364 c.Assert(err, jc.ErrorIsNil) 365 testAfterHookStatus(c, kind, status, after.StatusSet) 366 } 367 368 func testBeforeHookStatus(c *gc.C, kind hooks.Kind, status *jujuc.StatusInfo) { 369 switch kind { 370 case hooks.Install: 371 c.Assert(status.Status, gc.Equals, "maintenance") 372 c.Assert(status.Info, gc.Equals, "installing charm software") 373 case hooks.Stop: 374 c.Assert(string(status.Status), gc.Equals, "maintenance") 375 c.Assert(status.Info, gc.Equals, "cleaning up prior to charm deletion") 376 default: 377 c.Assert(string(status.Status), gc.Equals, "") 378 } 379 } 380 381 func testAfterHookStatus(c *gc.C, kind hooks.Kind, status *jujuc.StatusInfo, statusSetCalled bool) { 382 switch kind { 383 case hooks.Install: 384 c.Assert(status.Status, gc.Equals, "maintenance") 385 c.Assert(status.Info, gc.Equals, "installing charm software") 386 case hooks.Start: 387 if statusSetCalled { 388 c.Assert(string(status.Status), gc.Equals, "") 389 } else { 390 c.Assert(status.Status, gc.Equals, "unknown") 391 } 392 case hooks.Stop: 393 c.Assert(status.Status, gc.Equals, "terminated") 394 default: 395 c.Assert(string(status.Status), gc.Equals, "") 396 } 397 } 398 399 func (s *RunHookSuite) testBeforeHookExecute(c *gc.C, newHook newHook, kind hooks.Kind) { 400 // To check what happens in the beforeHook() call, we run a hook with an error 401 // so that it does not complete successfully and thus afterHook() does not run, 402 // overwriting the values. 403 runErr := errors.New("graaargh") 404 op, _, runnerFactory := s.getExecuteRunnerTest(c, newHook, kind, runErr) 405 _, err := op.Prepare(operation.State{}) 406 c.Assert(err, jc.ErrorIsNil) 407 408 newState, err := op.Execute(operation.State{}) 409 c.Assert(err, gc.Equals, operation.ErrHookFailed) 410 c.Assert(newState, gc.IsNil) 411 412 status, err := runnerFactory.MockNewHookRunner.runner.Context().UnitStatus() 413 c.Assert(err, jc.ErrorIsNil) 414 testBeforeHookStatus(c, kind, status) 415 } 416 417 func (s *RunHookSuite) TestBeforeHookStatus(c *gc.C) { 418 for _, kind := range hooks.UnitHooks() { 419 c.Logf("hook %v", kind) 420 for i, newHook := range []newHook{ 421 (operation.Factory).NewRunHook, 422 (operation.Factory).NewRetryHook, 423 } { 424 c.Logf("variant %d", i) 425 s.testBeforeHookExecute(c, newHook, kind) 426 } 427 } 428 } 429 430 func (s *RunHookSuite) testExecuteHookWithSetStatus(c *gc.C, kind hooks.Kind, setStatusCalled bool) { 431 for i, newHook := range []newHook{ 432 (operation.Factory).NewRunHook, 433 (operation.Factory).NewRetryHook, 434 } { 435 c.Logf("variant %d", i) 436 s.testExecuteThenCharmStatus(c, 437 newHook, 438 overwriteState, 439 operation.State{ 440 Started: true, 441 CollectMetricsTime: 1234567, 442 UpdateStatusTime: 1234567, 443 Kind: operation.RunHook, 444 Step: operation.Done, 445 Hook: &hook.Info{Kind: kind}, 446 StatusSet: setStatusCalled, 447 }, 448 kind, 449 setStatusCalled, 450 ) 451 } 452 } 453 454 func (s *RunHookSuite) TestExecuteHookWithSetStatus(c *gc.C) { 455 for _, kind := range hooks.UnitHooks() { 456 c.Logf("hook %v", kind) 457 s.testExecuteHookWithSetStatus(c, kind, true) 458 s.testExecuteHookWithSetStatus(c, kind, false) 459 } 460 } 461 462 func (s *RunHookSuite) testCommitError(c *gc.C, newHook newHook) { 463 callbacks := &CommitHookCallbacks{ 464 MockCommitHook: &MockCommitHook{nil, errors.New("pow")}, 465 } 466 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 467 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 468 c.Assert(err, jc.ErrorIsNil) 469 470 newState, err := op.Commit(operation.State{}) 471 c.Assert(newState, gc.IsNil) 472 c.Assert(err, gc.ErrorMatches, "pow") 473 } 474 475 func (s *RunHookSuite) TestCommitError_Run(c *gc.C) { 476 s.testCommitError(c, (operation.Factory).NewRunHook) 477 } 478 479 func (s *RunHookSuite) TestCommitError_Retry(c *gc.C) { 480 s.testCommitError(c, (operation.Factory).NewRetryHook) 481 } 482 483 func (s *RunHookSuite) TestCommitError_Skip(c *gc.C) { 484 s.testCommitError(c, (operation.Factory).NewSkipHook) 485 } 486 487 func (s *RunHookSuite) testCommitSuccess(c *gc.C, newHook newHook, hookInfo hook.Info, before, after operation.State) { 488 callbacks := &CommitHookCallbacks{ 489 MockCommitHook: &MockCommitHook{}, 490 } 491 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 492 op, err := newHook(factory, hookInfo) 493 c.Assert(err, jc.ErrorIsNil) 494 495 newState, err := op.Commit(before) 496 c.Assert(err, jc.ErrorIsNil) 497 c.Assert(newState, gc.DeepEquals, &after) 498 } 499 500 func (s *RunHookSuite) TestCommitSuccess_ConfigChanged_QueueStartHook(c *gc.C) { 501 for i, newHook := range []newHook{ 502 (operation.Factory).NewRunHook, 503 (operation.Factory).NewRetryHook, 504 (operation.Factory).NewSkipHook, 505 } { 506 c.Logf("variant %d", i) 507 s.testCommitSuccess(c, 508 newHook, 509 hook.Info{Kind: hooks.ConfigChanged}, 510 operation.State{}, 511 operation.State{ 512 Kind: operation.RunHook, 513 Step: operation.Queued, 514 Hook: &hook.Info{Kind: hooks.Start}, 515 }, 516 ) 517 } 518 } 519 520 func (s *RunHookSuite) TestCommitSuccess_ConfigChanged_Preserve(c *gc.C) { 521 for i, newHook := range []newHook{ 522 (operation.Factory).NewRunHook, 523 (operation.Factory).NewRetryHook, 524 (operation.Factory).NewSkipHook, 525 } { 526 c.Logf("variant %d", i) 527 s.testCommitSuccess(c, 528 newHook, 529 hook.Info{Kind: hooks.ConfigChanged}, 530 overwriteState, 531 operation.State{ 532 Started: true, 533 CollectMetricsTime: 1234567, 534 UpdateStatusTime: 1234567, 535 Kind: operation.Continue, 536 Step: operation.Pending, 537 }, 538 ) 539 } 540 } 541 542 func (s *RunHookSuite) TestCommitSuccess_Start_SetStarted(c *gc.C) { 543 for i, newHook := range []newHook{ 544 (operation.Factory).NewRunHook, 545 (operation.Factory).NewRetryHook, 546 (operation.Factory).NewSkipHook, 547 } { 548 c.Logf("variant %d", i) 549 s.testCommitSuccess(c, 550 newHook, 551 hook.Info{Kind: hooks.Start}, 552 operation.State{}, 553 operation.State{ 554 Started: true, 555 Kind: operation.Continue, 556 Step: operation.Pending, 557 }, 558 ) 559 } 560 } 561 562 func (s *RunHookSuite) TestCommitSuccess_Start_Preserve(c *gc.C) { 563 for i, newHook := range []newHook{ 564 (operation.Factory).NewRunHook, 565 (operation.Factory).NewRetryHook, 566 (operation.Factory).NewSkipHook, 567 } { 568 c.Logf("variant %d", i) 569 s.testCommitSuccess(c, 570 newHook, 571 hook.Info{Kind: hooks.Start}, 572 overwriteState, 573 operation.State{ 574 Started: true, 575 CollectMetricsTime: 1234567, 576 UpdateStatusTime: 1234567, 577 Kind: operation.Continue, 578 Step: operation.Pending, 579 }, 580 ) 581 } 582 } 583 584 func (s *RunHookSuite) testQueueHook_BlankSlate(c *gc.C, cause hooks.Kind) { 585 for i, newHook := range []newHook{ 586 (operation.Factory).NewRunHook, 587 (operation.Factory).NewRetryHook, 588 (operation.Factory).NewSkipHook, 589 } { 590 c.Logf("variant %d", i) 591 var hi *hook.Info 592 switch cause { 593 case hooks.UpgradeCharm: 594 hi = &hook.Info{Kind: hooks.ConfigChanged} 595 default: 596 hi = nil 597 } 598 s.testCommitSuccess(c, 599 newHook, 600 hook.Info{Kind: cause}, 601 operation.State{}, 602 operation.State{ 603 Kind: operation.RunHook, 604 Step: operation.Queued, 605 Stopped: cause == hooks.Stop, 606 Hook: hi, 607 }, 608 ) 609 } 610 } 611 612 func (s *RunHookSuite) testQueueHook_Preserve(c *gc.C, cause hooks.Kind) { 613 for i, newHook := range []newHook{ 614 (operation.Factory).NewRunHook, 615 (operation.Factory).NewRetryHook, 616 (operation.Factory).NewSkipHook, 617 } { 618 c.Logf("variant %d", i) 619 var hi *hook.Info 620 switch cause { 621 case hooks.UpgradeCharm: 622 hi = &hook.Info{Kind: hooks.ConfigChanged} 623 default: 624 hi = nil 625 } 626 s.testCommitSuccess(c, 627 newHook, 628 hook.Info{Kind: cause}, 629 overwriteState, 630 operation.State{ 631 Kind: operation.RunHook, 632 Step: operation.Queued, 633 Started: true, 634 Stopped: cause == hooks.Stop, 635 Hook: hi, 636 CollectMetricsTime: 1234567, 637 UpdateStatusTime: 1234567, 638 }, 639 ) 640 } 641 } 642 643 func (s *RunHookSuite) TestQueueHook_UpgradeCharm_BlankSlate(c *gc.C) { 644 s.testQueueHook_BlankSlate(c, hooks.UpgradeCharm) 645 } 646 647 func (s *RunHookSuite) TestQueueHook_UpgradeCharm_Preserve(c *gc.C) { 648 s.testQueueHook_Preserve(c, hooks.UpgradeCharm) 649 } 650 651 func (s *RunHookSuite) testQueueNothing_BlankSlate(c *gc.C, hookInfo hook.Info) { 652 for i, newHook := range []newHook{ 653 (operation.Factory).NewRunHook, 654 (operation.Factory).NewRetryHook, 655 (operation.Factory).NewSkipHook, 656 } { 657 c.Logf("variant %d", i) 658 s.testCommitSuccess(c, 659 newHook, 660 hookInfo, 661 operation.State{}, 662 operation.State{ 663 Kind: operation.Continue, 664 Step: operation.Pending, 665 Stopped: hookInfo.Kind == hooks.Stop, 666 }, 667 ) 668 } 669 } 670 671 func (s *RunHookSuite) testQueueNothing_Preserve(c *gc.C, hookInfo hook.Info) { 672 for i, newHook := range []newHook{ 673 (operation.Factory).NewRunHook, 674 (operation.Factory).NewRetryHook, 675 (operation.Factory).NewSkipHook, 676 } { 677 c.Logf("variant %d", i) 678 s.testCommitSuccess(c, 679 newHook, 680 hookInfo, 681 overwriteState, 682 operation.State{ 683 Kind: operation.Continue, 684 Step: operation.Pending, 685 Started: true, 686 Stopped: hookInfo.Kind == hooks.Stop, 687 CollectMetricsTime: 1234567, 688 UpdateStatusTime: 1234567, 689 }, 690 ) 691 } 692 } 693 694 func (s *RunHookSuite) TestQueueNothing_Install_BlankSlate(c *gc.C) { 695 s.testQueueNothing_BlankSlate(c, hook.Info{ 696 Kind: hooks.Install, 697 }) 698 } 699 700 func (s *RunHookSuite) TestQueueNothing_Install_Preserve(c *gc.C) { 701 s.testQueueNothing_Preserve(c, hook.Info{ 702 Kind: hooks.Install, 703 }) 704 } 705 706 func (s *RunHookSuite) TestQueueNothing_Stop_BlankSlate(c *gc.C) { 707 s.testQueueNothing_BlankSlate(c, hook.Info{ 708 Kind: hooks.Stop, 709 }) 710 } 711 712 func (s *RunHookSuite) TestQueueNothing_Stop_Preserve(c *gc.C) { 713 s.testQueueNothing_Preserve(c, hook.Info{ 714 Kind: hooks.Stop, 715 }) 716 } 717 718 func (s *RunHookSuite) TestQueueNothing_RelationJoined_BlankSlate(c *gc.C) { 719 s.testQueueNothing_BlankSlate(c, hook.Info{ 720 Kind: hooks.RelationJoined, 721 RemoteUnit: "u/0", 722 }) 723 } 724 725 func (s *RunHookSuite) TestQueueNothing_RelationJoined_Preserve(c *gc.C) { 726 s.testQueueNothing_Preserve(c, hook.Info{ 727 Kind: hooks.RelationJoined, 728 RemoteUnit: "u/0", 729 }) 730 } 731 732 func (s *RunHookSuite) TestQueueNothing_RelationChanged_BlankSlate(c *gc.C) { 733 s.testQueueNothing_BlankSlate(c, hook.Info{ 734 Kind: hooks.RelationChanged, 735 RemoteUnit: "u/0", 736 }) 737 } 738 739 func (s *RunHookSuite) TestQueueNothing_RelationChanged_Preserve(c *gc.C) { 740 s.testQueueNothing_Preserve(c, hook.Info{ 741 Kind: hooks.RelationChanged, 742 RemoteUnit: "u/0", 743 }) 744 } 745 746 func (s *RunHookSuite) TestQueueNothing_RelationDeparted_BlankSlate(c *gc.C) { 747 s.testQueueNothing_BlankSlate(c, hook.Info{ 748 Kind: hooks.RelationDeparted, 749 RemoteUnit: "u/0", 750 }) 751 } 752 753 func (s *RunHookSuite) TestQueueNothing_RelationDeparted_Preserve(c *gc.C) { 754 s.testQueueNothing_Preserve(c, hook.Info{ 755 Kind: hooks.RelationDeparted, 756 RemoteUnit: "u/0", 757 }) 758 } 759 760 func (s *RunHookSuite) TestQueueNothing_RelationBroken_BlankSlate(c *gc.C) { 761 s.testQueueNothing_BlankSlate(c, hook.Info{ 762 Kind: hooks.RelationBroken, 763 }) 764 } 765 766 func (s *RunHookSuite) TestQueueNothing_RelationBroken_Preserve(c *gc.C) { 767 s.testQueueNothing_Preserve(c, hook.Info{ 768 Kind: hooks.RelationBroken, 769 }) 770 } 771 772 func (s *RunHookSuite) testCommitSuccess_UpdateStatusTime(c *gc.C, newHook newHook) { 773 callbacks := &CommitHookCallbacks{ 774 MockCommitHook: &MockCommitHook{}, 775 } 776 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 777 op, err := newHook(factory, hook.Info{Kind: hooks.UpdateStatus}) 778 c.Assert(err, jc.ErrorIsNil) 779 780 nowBefore := time.Now().Unix() 781 newState, err := op.Commit(overwriteState) 782 c.Assert(err, jc.ErrorIsNil) 783 784 nowAfter := time.Now().Unix() 785 nowWritten := newState.UpdateStatusTime 786 c.Logf("%d <= %d <= %d", nowBefore, nowWritten, nowAfter) 787 c.Check(nowBefore <= nowWritten, jc.IsTrue) 788 c.Check(nowWritten <= nowAfter, jc.IsTrue) 789 790 // Check the other fields match. 791 newState.UpdateStatusTime = 0 792 c.Check(newState, gc.DeepEquals, &operation.State{ 793 Started: true, 794 Kind: operation.Continue, 795 Step: operation.Pending, 796 CollectMetricsTime: 1234567, 797 }) 798 } 799 800 func (s *RunHookSuite) TestCommitSuccess_UpdateStatusTime_Run(c *gc.C) { 801 s.testCommitSuccess_UpdateStatusTime(c, (operation.Factory).NewRunHook) 802 } 803 804 func (s *RunHookSuite) TestCommitSuccess_UpdateStatusTime_Retry(c *gc.C) { 805 s.testCommitSuccess_UpdateStatusTime(c, (operation.Factory).NewRetryHook) 806 } 807 808 func (s *RunHookSuite) TestCommitSuccess_UpdateStatusTime_Skip(c *gc.C) { 809 s.testCommitSuccess_UpdateStatusTime(c, (operation.Factory).NewSkipHook) 810 } 811 812 func (s *RunHookSuite) testCommitSuccess_CollectMetricsTime(c *gc.C, newHook newHook) { 813 callbacks := &CommitHookCallbacks{ 814 MockCommitHook: &MockCommitHook{}, 815 } 816 factory := operation.NewFactory(nil, nil, callbacks, nil, nil) 817 op, err := newHook(factory, hook.Info{Kind: hooks.CollectMetrics}) 818 c.Assert(err, jc.ErrorIsNil) 819 820 nowBefore := time.Now().Unix() 821 newState, err := op.Commit(overwriteState) 822 c.Assert(err, jc.ErrorIsNil) 823 824 nowAfter := time.Now().Unix() 825 nowWritten := newState.CollectMetricsTime 826 c.Logf("%d <= %d <= %d", nowBefore, nowWritten, nowAfter) 827 c.Check(nowBefore <= nowWritten, jc.IsTrue) 828 c.Check(nowWritten <= nowAfter, jc.IsTrue) 829 830 // Check the other fields match. 831 newState.CollectMetricsTime = 0 832 c.Check(newState, gc.DeepEquals, &operation.State{ 833 Started: true, 834 Kind: operation.Continue, 835 Step: operation.Pending, 836 UpdateStatusTime: 1234567, 837 }) 838 } 839 840 func (s *RunHookSuite) TestCommitSuccess_CollectMetricsTime_Run(c *gc.C) { 841 s.testCommitSuccess_CollectMetricsTime(c, (operation.Factory).NewRunHook) 842 } 843 844 func (s *RunHookSuite) TestCommitSuccess_CollectMetricsTime_Retry(c *gc.C) { 845 s.testCommitSuccess_CollectMetricsTime(c, (operation.Factory).NewRetryHook) 846 } 847 848 func (s *RunHookSuite) TestCommitSuccess_CollectMetricsTime_Skip(c *gc.C) { 849 s.testCommitSuccess_CollectMetricsTime(c, (operation.Factory).NewSkipHook) 850 } 851 852 func (s *RunHookSuite) testNeedsGlobalMachineLock(c *gc.C, newHook newHook, expected bool) { 853 factory := operation.NewFactory(nil, nil, nil, nil, nil) 854 op, err := newHook(factory, hook.Info{Kind: hooks.ConfigChanged}) 855 c.Assert(err, jc.ErrorIsNil) 856 c.Assert(op.NeedsGlobalMachineLock(), gc.Equals, expected) 857 } 858 859 func (s *RunHookSuite) TestNeedsGlobalMachineLock_Run(c *gc.C) { 860 s.testNeedsGlobalMachineLock(c, (operation.Factory).NewRunHook, true) 861 } 862 863 func (s *RunHookSuite) TestNeedsGlobalMachineLock_Retry(c *gc.C) { 864 s.testNeedsGlobalMachineLock(c, (operation.Factory).NewRetryHook, true) 865 } 866 867 func (s *RunHookSuite) TestNeedsGlobalMachineLock_Skip(c *gc.C) { 868 s.testNeedsGlobalMachineLock(c, (operation.Factory).NewSkipHook, false) 869 }