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  }