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