github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/operation/runaction_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package operation_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/testing" 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/charm.v6-unstable/hooks" 12 13 "github.com/juju/juju/worker/uniter/hook" 14 "github.com/juju/juju/worker/uniter/operation" 15 "github.com/juju/juju/worker/uniter/runner" 16 "github.com/juju/juju/worker/uniter/runner/context" 17 ) 18 19 type RunActionSuite struct { 20 testing.IsolationSuite 21 } 22 23 var _ = gc.Suite(&RunActionSuite{}) 24 25 func (s *RunActionSuite) TestPrepareErrorBadActionAndFailSucceeds(c *gc.C) { 26 errBadAction := runner.NewBadActionError("some-action-id", "splat") 27 runnerFactory := &MockRunnerFactory{ 28 MockNewActionRunner: &MockNewActionRunner{err: errBadAction}, 29 } 30 callbacks := &RunActionCallbacks{ 31 MockFailAction: &MockFailAction{err: errors.New("squelch")}, 32 } 33 factory := operation.NewFactory(operation.FactoryParams{ 34 RunnerFactory: runnerFactory, 35 Callbacks: callbacks, 36 }) 37 op, err := factory.NewAction(someActionId) 38 c.Assert(err, jc.ErrorIsNil) 39 40 newState, err := op.Prepare(operation.State{}) 41 c.Assert(newState, gc.IsNil) 42 c.Assert(err, gc.ErrorMatches, "squelch") 43 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 44 c.Assert(*callbacks.MockFailAction.gotActionId, gc.Equals, someActionId) 45 c.Assert(*callbacks.MockFailAction.gotMessage, gc.Equals, errBadAction.Error()) 46 } 47 48 func (s *RunActionSuite) TestPrepareErrorBadActionAndFailErrors(c *gc.C) { 49 errBadAction := runner.NewBadActionError("some-action-id", "foof") 50 runnerFactory := &MockRunnerFactory{ 51 MockNewActionRunner: &MockNewActionRunner{err: errBadAction}, 52 } 53 callbacks := &RunActionCallbacks{ 54 MockFailAction: &MockFailAction{}, 55 } 56 factory := operation.NewFactory(operation.FactoryParams{ 57 RunnerFactory: runnerFactory, 58 Callbacks: callbacks, 59 }) 60 op, err := factory.NewAction(someActionId) 61 c.Assert(err, jc.ErrorIsNil) 62 63 newState, err := op.Prepare(operation.State{}) 64 c.Assert(newState, gc.IsNil) 65 c.Assert(err, gc.Equals, operation.ErrSkipExecute) 66 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 67 c.Assert(*callbacks.MockFailAction.gotActionId, gc.Equals, someActionId) 68 c.Assert(*callbacks.MockFailAction.gotMessage, gc.Equals, errBadAction.Error()) 69 } 70 71 func (s *RunActionSuite) TestPrepareErrorActionNotAvailable(c *gc.C) { 72 runnerFactory := &MockRunnerFactory{ 73 MockNewActionRunner: &MockNewActionRunner{err: runner.ErrActionNotAvailable}, 74 } 75 factory := operation.NewFactory(operation.FactoryParams{ 76 RunnerFactory: runnerFactory, 77 }) 78 op, err := factory.NewAction(someActionId) 79 c.Assert(err, jc.ErrorIsNil) 80 81 newState, err := op.Prepare(operation.State{}) 82 c.Assert(newState, gc.IsNil) 83 c.Assert(err, gc.Equals, operation.ErrSkipExecute) 84 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 85 } 86 87 func (s *RunActionSuite) TestPrepareErrorOther(c *gc.C) { 88 runnerFactory := &MockRunnerFactory{ 89 MockNewActionRunner: &MockNewActionRunner{err: errors.New("foop")}, 90 } 91 factory := operation.NewFactory(operation.FactoryParams{ 92 RunnerFactory: runnerFactory, 93 }) 94 op, err := factory.NewAction(someActionId) 95 c.Assert(err, jc.ErrorIsNil) 96 97 newState, err := op.Prepare(operation.State{}) 98 c.Assert(newState, gc.IsNil) 99 c.Assert(err, gc.ErrorMatches, `cannot create runner for action ".*": foop`) 100 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 101 } 102 103 func (s *RunActionSuite) TestPrepareCtxCalled(c *gc.C) { 104 ctx := &MockContext{actionData: &context.ActionData{Name: "some-action-name"}} 105 runnerFactory := &MockRunnerFactory{ 106 MockNewActionRunner: &MockNewActionRunner{ 107 runner: &MockRunner{ 108 context: ctx, 109 }, 110 }, 111 } 112 factory := operation.NewFactory(operation.FactoryParams{ 113 RunnerFactory: runnerFactory, 114 }) 115 op, err := factory.NewAction(someActionId) 116 c.Assert(err, jc.ErrorIsNil) 117 118 newState, err := op.Prepare(operation.State{}) 119 c.Assert(err, jc.ErrorIsNil) 120 c.Assert(newState, gc.NotNil) 121 ctx.CheckCall(c, 0, "Prepare") 122 } 123 124 func (s *RunActionSuite) TestPrepareCtxError(c *gc.C) { 125 ctx := &MockContext{actionData: &context.ActionData{Name: "some-action-name"}} 126 ctx.SetErrors(errors.New("ctx prepare error")) 127 runnerFactory := &MockRunnerFactory{ 128 MockNewActionRunner: &MockNewActionRunner{ 129 runner: &MockRunner{ 130 context: ctx, 131 }, 132 }, 133 } 134 factory := operation.NewFactory(operation.FactoryParams{ 135 RunnerFactory: runnerFactory, 136 }) 137 op, err := factory.NewAction(someActionId) 138 c.Assert(err, jc.ErrorIsNil) 139 140 newState, err := op.Prepare(operation.State{}) 141 c.Assert(err, gc.ErrorMatches, `ctx prepare error`) 142 c.Assert(newState, gc.IsNil) 143 ctx.CheckCall(c, 0, "Prepare") 144 } 145 146 func (s *RunActionSuite) TestPrepareSuccessCleanState(c *gc.C) { 147 runnerFactory := NewRunActionRunnerFactory(errors.New("should not call")) 148 factory := operation.NewFactory(operation.FactoryParams{ 149 RunnerFactory: runnerFactory, 150 }) 151 op, err := factory.NewAction(someActionId) 152 c.Assert(err, jc.ErrorIsNil) 153 154 newState, err := op.Prepare(operation.State{}) 155 c.Assert(err, jc.ErrorIsNil) 156 c.Assert(newState, jc.DeepEquals, &operation.State{ 157 Kind: operation.RunAction, 158 Step: operation.Pending, 159 ActionId: &someActionId, 160 }) 161 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 162 } 163 164 func (s *RunActionSuite) TestPrepareSuccessDirtyState(c *gc.C) { 165 runnerFactory := NewRunActionRunnerFactory(errors.New("should not call")) 166 factory := operation.NewFactory(operation.FactoryParams{ 167 RunnerFactory: runnerFactory, 168 }) 169 op, err := factory.NewAction(someActionId) 170 c.Assert(err, jc.ErrorIsNil) 171 172 newState, err := op.Prepare(overwriteState) 173 c.Assert(err, jc.ErrorIsNil) 174 c.Assert(newState, jc.DeepEquals, &operation.State{ 175 Kind: operation.RunAction, 176 Step: operation.Pending, 177 ActionId: &someActionId, 178 Started: true, 179 Hook: &hook.Info{Kind: hooks.Install}, 180 }) 181 c.Assert(*runnerFactory.MockNewActionRunner.gotActionId, gc.Equals, someActionId) 182 } 183 184 func (s *RunActionSuite) TestExecuteSuccess(c *gc.C) { 185 var stateChangeTests = []struct { 186 description string 187 before operation.State 188 after operation.State 189 }{{ 190 description: "empty state", 191 after: operation.State{ 192 Kind: operation.RunAction, 193 Step: operation.Done, 194 ActionId: &someActionId, 195 }, 196 }, { 197 description: "preserves appropriate fields", 198 before: overwriteState, 199 after: operation.State{ 200 Kind: operation.RunAction, 201 Step: operation.Done, 202 ActionId: &someActionId, 203 Hook: &hook.Info{Kind: hooks.Install}, 204 Started: true, 205 }, 206 }} 207 208 for i, test := range stateChangeTests { 209 c.Logf("test %d: %s", i, test.description) 210 runnerFactory := NewRunActionRunnerFactory(nil) 211 callbacks := &RunActionCallbacks{} 212 factory := operation.NewFactory(operation.FactoryParams{ 213 RunnerFactory: runnerFactory, 214 Callbacks: callbacks, 215 }) 216 op, err := factory.NewAction(someActionId) 217 c.Assert(err, jc.ErrorIsNil) 218 midState, err := op.Prepare(test.before) 219 c.Assert(midState, gc.NotNil) 220 c.Assert(err, jc.ErrorIsNil) 221 222 newState, err := op.Execute(*midState) 223 c.Assert(err, jc.ErrorIsNil) 224 c.Assert(newState, jc.DeepEquals, &test.after) 225 c.Assert(callbacks.executingMessage, gc.Equals, "running action some-action-name") 226 c.Assert(*runnerFactory.MockNewActionRunner.runner.MockRunAction.gotName, gc.Equals, "some-action-name") 227 } 228 } 229 230 func (s *RunActionSuite) TestCommit(c *gc.C) { 231 var stateChangeTests = []struct { 232 description string 233 before operation.State 234 after operation.State 235 }{{ 236 description: "empty state", 237 after: operation.State{ 238 Kind: operation.Continue, 239 Step: operation.Pending, 240 }, 241 }, { 242 description: "preserves only appropriate fields, no hook", 243 before: operation.State{ 244 Kind: operation.Continue, 245 Step: operation.Pending, 246 Started: true, 247 CharmURL: curl("cs:quantal/wordpress-2"), 248 ActionId: &randomActionId, 249 }, 250 after: operation.State{ 251 Kind: operation.Continue, 252 Step: operation.Pending, 253 Started: true, 254 }, 255 }, { 256 description: "preserves only appropriate fields, with hook", 257 before: operation.State{ 258 Kind: operation.Continue, 259 Step: operation.Pending, 260 Started: true, 261 CharmURL: curl("cs:quantal/wordpress-2"), 262 ActionId: &randomActionId, 263 Hook: &hook.Info{Kind: hooks.Install}, 264 }, 265 after: operation.State{ 266 Kind: operation.RunHook, 267 Step: operation.Pending, 268 Hook: &hook.Info{Kind: hooks.Install}, 269 Started: true, 270 }, 271 }} 272 273 for i, test := range stateChangeTests { 274 c.Logf("test %d: %s", i, test.description) 275 factory := operation.NewFactory(operation.FactoryParams{}) 276 op, err := factory.NewAction(someActionId) 277 c.Assert(err, jc.ErrorIsNil) 278 279 newState, err := op.Commit(test.before) 280 c.Assert(newState, jc.DeepEquals, &test.after) 281 } 282 } 283 284 func (s *RunActionSuite) TestNeedsGlobalMachineLock(c *gc.C) { 285 factory := operation.NewFactory(operation.FactoryParams{}) 286 op, err := factory.NewAction(someActionId) 287 c.Assert(err, jc.ErrorIsNil) 288 c.Assert(op.NeedsGlobalMachineLock(), jc.IsTrue) 289 }