github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/uniter/operation/deploy_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  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	corecharm "gopkg.in/juju/charm.v5"
    12  	"gopkg.in/juju/charm.v5/hooks"
    13  
    14  	"github.com/juju/juju/worker/uniter/charm"
    15  	"github.com/juju/juju/worker/uniter/hook"
    16  	"github.com/juju/juju/worker/uniter/operation"
    17  )
    18  
    19  type DeploySuite struct {
    20  	testing.IsolationSuite
    21  }
    22  
    23  var _ = gc.Suite(&DeploySuite{})
    24  
    25  type newDeploy func(operation.Factory, *corecharm.URL) (operation.Operation, error)
    26  
    27  func (s *DeploySuite) testPrepareAlreadyDone(
    28  	c *gc.C, newDeploy newDeploy, kind operation.Kind, expectClearResolvedFlag bool,
    29  ) {
    30  	callbacks := &DeployCallbacks{
    31  		MockClearResolvedFlag: &MockNoArgs{},
    32  	}
    33  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
    34  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
    35  	c.Assert(err, jc.ErrorIsNil)
    36  	newState, err := op.Prepare(operation.State{
    37  		Kind:     kind,
    38  		Step:     operation.Done,
    39  		CharmURL: curl("cs:quantal/hive-23"),
    40  	})
    41  	c.Check(newState, gc.IsNil)
    42  	c.Check(errors.Cause(err), gc.Equals, operation.ErrSkipExecute)
    43  	c.Check(callbacks.MockClearResolvedFlag.called, gc.Equals, expectClearResolvedFlag)
    44  }
    45  
    46  func (s *DeploySuite) TestPrepareAlreadyDone_Install(c *gc.C) {
    47  	s.testPrepareAlreadyDone(c,
    48  		(operation.Factory).NewInstall,
    49  		operation.Install,
    50  		false,
    51  	)
    52  }
    53  
    54  func (s *DeploySuite) TestPrepareAlreadyDone_Upgrade(c *gc.C) {
    55  	s.testPrepareAlreadyDone(c,
    56  		(operation.Factory).NewUpgrade,
    57  		operation.Upgrade,
    58  		false,
    59  	)
    60  }
    61  
    62  func (s *DeploySuite) TestPrepareAlreadyDone_RevertUpgrade(c *gc.C) {
    63  	s.testPrepareAlreadyDone(c,
    64  		(operation.Factory).NewRevertUpgrade,
    65  		operation.Upgrade,
    66  		true,
    67  	)
    68  }
    69  
    70  func (s *DeploySuite) TestPrepareAlreadyDone_ResolvedUpgrade(c *gc.C) {
    71  	s.testPrepareAlreadyDone(c,
    72  		(operation.Factory).NewResolvedUpgrade,
    73  		operation.Upgrade,
    74  		true,
    75  	)
    76  }
    77  
    78  func (s *DeploySuite) testClearResolvedFlagError(c *gc.C, newDeploy newDeploy) {
    79  	callbacks := &DeployCallbacks{
    80  		MockClearResolvedFlag: &MockNoArgs{err: errors.New("blort")},
    81  	}
    82  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
    83  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
    84  	c.Assert(err, jc.ErrorIsNil)
    85  	newState, err := op.Prepare(operation.State{})
    86  	c.Check(newState, gc.IsNil)
    87  	c.Check(err, gc.ErrorMatches, "blort")
    88  	c.Check(callbacks.MockClearResolvedFlag.called, jc.IsTrue)
    89  }
    90  
    91  func (s *DeploySuite) TestClearResolvedFlagError_RevertUpgrade(c *gc.C) {
    92  	s.testClearResolvedFlagError(c, (operation.Factory).NewRevertUpgrade)
    93  }
    94  
    95  func (s *DeploySuite) TestClearResolvedFlagError_ResolvedUpgrade(c *gc.C) {
    96  	s.testClearResolvedFlagError(c, (operation.Factory).NewResolvedUpgrade)
    97  }
    98  
    99  func (s *DeploySuite) testNotifyDeployerError(
   100  	c *gc.C, newDeploy newDeploy, expectNotifyRevert bool,
   101  ) {
   102  	callbacks := &DeployCallbacks{
   103  		MockClearResolvedFlag: &MockNoArgs{},
   104  	}
   105  	deployer := &MockDeployer{}
   106  	expectCall := &MockNoArgs{err: errors.New("snh")}
   107  	if expectNotifyRevert {
   108  		deployer.MockNotifyRevert = expectCall
   109  	} else {
   110  		deployer.MockNotifyResolved = expectCall
   111  	}
   112  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   113  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	newState, err := op.Prepare(operation.State{})
   117  	c.Check(newState, gc.IsNil)
   118  	c.Check(err, gc.ErrorMatches, "snh")
   119  	c.Check(expectCall.called, jc.IsTrue)
   120  }
   121  
   122  func (s *DeploySuite) TestNotifyDeployerError_RevertUpgrade(c *gc.C) {
   123  	s.testNotifyDeployerError(c, (operation.Factory).NewRevertUpgrade, true)
   124  }
   125  
   126  func (s *DeploySuite) TestNotifyDeployerError_ResolvedUpgrade(c *gc.C) {
   127  	s.testNotifyDeployerError(c, (operation.Factory).NewResolvedUpgrade, false)
   128  }
   129  
   130  func (s *DeploySuite) testPrepareArchiveInfoError(c *gc.C, newDeploy newDeploy) {
   131  	callbacks := &DeployCallbacks{
   132  		MockClearResolvedFlag: &MockNoArgs{},
   133  		MockGetArchiveInfo:    &MockGetArchiveInfo{err: errors.New("pew")},
   134  	}
   135  	deployer := &MockDeployer{
   136  		MockNotifyRevert:   &MockNoArgs{},
   137  		MockNotifyResolved: &MockNoArgs{},
   138  	}
   139  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   140  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
   141  	c.Assert(err, jc.ErrorIsNil)
   142  
   143  	newState, err := op.Prepare(operation.State{})
   144  	c.Check(newState, gc.IsNil)
   145  	c.Check(err, gc.ErrorMatches, "pew")
   146  	c.Check(callbacks.MockGetArchiveInfo.gotCharmURL, gc.DeepEquals, curl("cs:quantal/hive-23"))
   147  }
   148  
   149  func (s *DeploySuite) TestPrepareArchiveInfoError_Install(c *gc.C) {
   150  	s.testPrepareArchiveInfoError(c, (operation.Factory).NewInstall)
   151  }
   152  
   153  func (s *DeploySuite) TestPrepareArchiveInfoError_Upgrade(c *gc.C) {
   154  	s.testPrepareArchiveInfoError(c, (operation.Factory).NewUpgrade)
   155  }
   156  
   157  func (s *DeploySuite) TestPrepareArchiveInfoError_RevertUpgrade(c *gc.C) {
   158  	s.testPrepareArchiveInfoError(c, (operation.Factory).NewRevertUpgrade)
   159  }
   160  
   161  func (s *DeploySuite) TestPrepareArchiveInfoError_ResolvedUpgrade(c *gc.C) {
   162  	s.testPrepareArchiveInfoError(c, (operation.Factory).NewResolvedUpgrade)
   163  }
   164  
   165  func (s *DeploySuite) testPrepareStageError(c *gc.C, newDeploy newDeploy) {
   166  	callbacks := &DeployCallbacks{
   167  		MockClearResolvedFlag: &MockNoArgs{},
   168  		MockGetArchiveInfo:    &MockGetArchiveInfo{info: &MockBundleInfo{}},
   169  	}
   170  	deployer := &MockDeployer{
   171  		MockNotifyRevert:   &MockNoArgs{},
   172  		MockNotifyResolved: &MockNoArgs{},
   173  		MockStage:          &MockStage{err: errors.New("squish")},
   174  	}
   175  	var abort <-chan struct{} = make(chan struct{})
   176  	factory := operation.NewFactory(deployer, nil, callbacks, nil, abort)
   177  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
   178  	c.Assert(err, jc.ErrorIsNil)
   179  
   180  	newState, err := op.Prepare(operation.State{})
   181  	c.Check(newState, gc.IsNil)
   182  	c.Check(err, gc.ErrorMatches, "squish")
   183  	c.Check(*deployer.MockStage.gotInfo, gc.Equals, callbacks.MockGetArchiveInfo.info)
   184  	c.Check(*deployer.MockStage.gotAbort, gc.Equals, abort)
   185  }
   186  
   187  func (s *DeploySuite) TestPrepareStageError_Install(c *gc.C) {
   188  	s.testPrepareStageError(c, (operation.Factory).NewInstall)
   189  }
   190  
   191  func (s *DeploySuite) TestPrepareStageError_Upgrade(c *gc.C) {
   192  	s.testPrepareStageError(c, (operation.Factory).NewUpgrade)
   193  }
   194  
   195  func (s *DeploySuite) TestPrepareStageError_RevertUpgrade(c *gc.C) {
   196  	s.testPrepareStageError(c, (operation.Factory).NewRevertUpgrade)
   197  }
   198  
   199  func (s *DeploySuite) TestPrepareStageError_ResolvedUpgrade(c *gc.C) {
   200  	s.testPrepareStageError(c, (operation.Factory).NewResolvedUpgrade)
   201  }
   202  
   203  func (s *DeploySuite) testPrepareSetCharmError(c *gc.C, newDeploy newDeploy) {
   204  	callbacks := &DeployCallbacks{
   205  		MockClearResolvedFlag: &MockNoArgs{},
   206  		MockGetArchiveInfo:    &MockGetArchiveInfo{},
   207  		MockSetCurrentCharm:   &MockSetCurrentCharm{err: errors.New("blargh")},
   208  	}
   209  	deployer := &MockDeployer{
   210  		MockNotifyRevert:   &MockNoArgs{},
   211  		MockNotifyResolved: &MockNoArgs{},
   212  		MockStage:          &MockStage{},
   213  	}
   214  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   215  	op, err := newDeploy(factory, curl("cs:quantal/hive-23"))
   216  	c.Assert(err, jc.ErrorIsNil)
   217  
   218  	newState, err := op.Prepare(operation.State{})
   219  	c.Check(newState, gc.IsNil)
   220  	c.Check(err, gc.ErrorMatches, "blargh")
   221  	c.Check(callbacks.MockSetCurrentCharm.gotCharmURL, gc.DeepEquals, curl("cs:quantal/hive-23"))
   222  }
   223  
   224  func (s *DeploySuite) TestPrepareSetCharmError_Install(c *gc.C) {
   225  	s.testPrepareSetCharmError(c, (operation.Factory).NewInstall)
   226  }
   227  
   228  func (s *DeploySuite) TestPrepareSetCharmError_Upgrade(c *gc.C) {
   229  	s.testPrepareSetCharmError(c, (operation.Factory).NewUpgrade)
   230  }
   231  
   232  func (s *DeploySuite) TestPrepareSetCharmError_RevertUpgrade(c *gc.C) {
   233  	s.testPrepareSetCharmError(c, (operation.Factory).NewRevertUpgrade)
   234  }
   235  
   236  func (s *DeploySuite) TestPrepareSetCharmError_ResolvedUpgrade(c *gc.C) {
   237  	s.testPrepareSetCharmError(c, (operation.Factory).NewResolvedUpgrade)
   238  }
   239  
   240  func (s *DeploySuite) testPrepareSuccess(c *gc.C, newDeploy newDeploy, before, after operation.State) {
   241  	callbacks := NewDeployCallbacks()
   242  	deployer := &MockDeployer{
   243  		MockNotifyRevert:   &MockNoArgs{},
   244  		MockNotifyResolved: &MockNoArgs{},
   245  		MockStage:          &MockStage{},
   246  	}
   247  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   248  	op, err := newDeploy(factory, curl("cs:quantal/nyancat-4"))
   249  	c.Assert(err, jc.ErrorIsNil)
   250  
   251  	newState, err := op.Prepare(before)
   252  	c.Check(err, jc.ErrorIsNil)
   253  	c.Check(newState, gc.DeepEquals, &after)
   254  	c.Check(callbacks.MockSetCurrentCharm.gotCharmURL, gc.DeepEquals, curl("cs:quantal/nyancat-4"))
   255  }
   256  
   257  func (s *DeploySuite) TestPrepareSuccess_Install_BlankSlate(c *gc.C) {
   258  	s.testPrepareSuccess(c,
   259  		(operation.Factory).NewInstall,
   260  		operation.State{},
   261  		operation.State{
   262  			Kind:     operation.Install,
   263  			Step:     operation.Pending,
   264  			CharmURL: curl("cs:quantal/nyancat-4"),
   265  		},
   266  	)
   267  }
   268  
   269  func (s *DeploySuite) TestPrepareSuccess_Install_Queued(c *gc.C) {
   270  	s.testPrepareSuccess(c,
   271  		(operation.Factory).NewInstall,
   272  		operation.State{
   273  			Kind:     operation.Install,
   274  			Step:     operation.Queued,
   275  			CharmURL: curl("cs:quantal/nyancat-4"),
   276  		},
   277  		operation.State{
   278  			Kind:     operation.Install,
   279  			Step:     operation.Pending,
   280  			CharmURL: curl("cs:quantal/nyancat-4"),
   281  		},
   282  	)
   283  }
   284  
   285  func (s *DeploySuite) TestPrepareSuccess_Upgrade_PreservePendingHook(c *gc.C) {
   286  	for i, newDeploy := range []newDeploy{
   287  		(operation.Factory).NewUpgrade,
   288  		(operation.Factory).NewRevertUpgrade,
   289  		(operation.Factory).NewResolvedUpgrade,
   290  	} {
   291  		c.Logf("variant %d", i)
   292  		s.testPrepareSuccess(c,
   293  			newDeploy,
   294  			operation.State{
   295  				Kind: operation.RunHook,
   296  				Step: operation.Pending,
   297  				Hook: &hook.Info{Kind: hooks.ConfigChanged},
   298  			},
   299  			operation.State{
   300  				Kind:     operation.Upgrade,
   301  				Step:     operation.Pending,
   302  				CharmURL: curl("cs:quantal/nyancat-4"),
   303  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   304  			},
   305  		)
   306  	}
   307  }
   308  
   309  func (s *DeploySuite) TestPrepareSuccess_Upgrade_PreserveOriginalPendingHook(c *gc.C) {
   310  	for i, newDeploy := range []newDeploy{
   311  		(operation.Factory).NewUpgrade,
   312  		(operation.Factory).NewRevertUpgrade,
   313  		(operation.Factory).NewResolvedUpgrade,
   314  	} {
   315  		c.Logf("variant %d", i)
   316  		s.testPrepareSuccess(c,
   317  			newDeploy,
   318  			operation.State{
   319  				Kind:     operation.Upgrade,
   320  				Step:     operation.Pending,
   321  				CharmURL: curl("cs:quantal/random-23"),
   322  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   323  			},
   324  			operation.State{
   325  				Kind:     operation.Upgrade,
   326  				Step:     operation.Pending,
   327  				CharmURL: curl("cs:quantal/nyancat-4"),
   328  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   329  			},
   330  		)
   331  	}
   332  }
   333  
   334  func (s *DeploySuite) TestPrepareSuccess_Upgrade_PreserveNoHook(c *gc.C) {
   335  	for i, newDeploy := range []newDeploy{
   336  		(operation.Factory).NewUpgrade,
   337  		(operation.Factory).NewRevertUpgrade,
   338  		(operation.Factory).NewResolvedUpgrade,
   339  	} {
   340  		c.Logf("variant %d", i)
   341  		s.testPrepareSuccess(c,
   342  			newDeploy,
   343  			overwriteState,
   344  			operation.State{
   345  				Kind:               operation.Upgrade,
   346  				Step:               operation.Pending,
   347  				CharmURL:           curl("cs:quantal/nyancat-4"),
   348  				Started:            true,
   349  				CollectMetricsTime: 1234567,
   350  				UpdateStatusTime:   1234567,
   351  			},
   352  		)
   353  	}
   354  }
   355  
   356  func (s *DeploySuite) testExecuteConflictError(c *gc.C, newDeploy newDeploy) {
   357  	callbacks := NewDeployCallbacks()
   358  	deployer := &MockDeployer{
   359  		MockNotifyRevert:   &MockNoArgs{},
   360  		MockNotifyResolved: &MockNoArgs{},
   361  		MockStage:          &MockStage{},
   362  		MockDeploy:         &MockNoArgs{err: charm.ErrConflict},
   363  	}
   364  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   365  	charmURL := curl("cs:quantal/nyancat-4")
   366  	op, err := newDeploy(factory, charmURL)
   367  	c.Assert(err, jc.ErrorIsNil)
   368  	_, err = op.Prepare(operation.State{})
   369  	c.Assert(err, jc.ErrorIsNil)
   370  
   371  	newState, err := op.Execute(operation.State{})
   372  	c.Check(newState, gc.IsNil)
   373  	c.Check(err, gc.ErrorMatches, "cannot deploy charm cs:quantal/nyancat-4")
   374  	errURL, ok := operation.DeployConflictCharmURL(err)
   375  	c.Check(ok, jc.IsTrue)
   376  	c.Check(errURL, gc.DeepEquals, charmURL)
   377  	c.Check(deployer.MockDeploy.called, jc.IsTrue)
   378  }
   379  
   380  func (s *DeploySuite) TestExecuteConflictError_Install(c *gc.C) {
   381  	s.testExecuteError(c, (operation.Factory).NewInstall)
   382  }
   383  
   384  func (s *DeploySuite) TestExecuteConflictError_Upgrade(c *gc.C) {
   385  	s.testExecuteError(c, (operation.Factory).NewUpgrade)
   386  }
   387  
   388  func (s *DeploySuite) TestExecuteConflictError_RevertUpgrade(c *gc.C) {
   389  	s.testExecuteError(c, (operation.Factory).NewRevertUpgrade)
   390  }
   391  
   392  func (s *DeploySuite) TestExecuteConflictError_ResolvedUpgrade(c *gc.C) {
   393  	s.testExecuteError(c, (operation.Factory).NewResolvedUpgrade)
   394  }
   395  
   396  func (s *DeploySuite) testExecuteError(c *gc.C, newDeploy newDeploy) {
   397  	callbacks := NewDeployCallbacks()
   398  	deployer := &MockDeployer{
   399  		MockNotifyRevert:   &MockNoArgs{},
   400  		MockNotifyResolved: &MockNoArgs{},
   401  		MockStage:          &MockStage{},
   402  		MockDeploy:         &MockNoArgs{err: errors.New("rasp")},
   403  	}
   404  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   405  	op, err := newDeploy(factory, curl("cs:quantal/nyancat-4"))
   406  	c.Assert(err, jc.ErrorIsNil)
   407  	_, err = op.Prepare(operation.State{})
   408  	c.Assert(err, jc.ErrorIsNil)
   409  
   410  	newState, err := op.Execute(operation.State{})
   411  	c.Check(newState, gc.IsNil)
   412  	c.Check(err, gc.ErrorMatches, "rasp")
   413  	c.Check(deployer.MockDeploy.called, jc.IsTrue)
   414  }
   415  
   416  func (s *DeploySuite) TestExecuteError_Install(c *gc.C) {
   417  	s.testExecuteError(c, (operation.Factory).NewInstall)
   418  }
   419  
   420  func (s *DeploySuite) TestExecuteError_Upgrade(c *gc.C) {
   421  	s.testExecuteError(c, (operation.Factory).NewUpgrade)
   422  }
   423  
   424  func (s *DeploySuite) TestExecuteError_RevertUpgrade(c *gc.C) {
   425  	s.testExecuteError(c, (operation.Factory).NewRevertUpgrade)
   426  }
   427  
   428  func (s *DeploySuite) TestExecuteError_ResolvedUpgrade(c *gc.C) {
   429  	s.testExecuteError(c, (operation.Factory).NewResolvedUpgrade)
   430  }
   431  
   432  func (s *DeploySuite) testExecuteSuccess(
   433  	c *gc.C, newDeploy newDeploy, before, after operation.State,
   434  ) {
   435  	deployer := NewMockDeployer()
   436  	callbacks := NewDeployCallbacks()
   437  	factory := operation.NewFactory(deployer, nil, callbacks, nil, nil)
   438  	op, err := newDeploy(factory, curl("cs:quantal/lol-1"))
   439  	c.Assert(err, jc.ErrorIsNil)
   440  
   441  	midState, err := op.Prepare(before)
   442  	c.Assert(err, jc.ErrorIsNil)
   443  	c.Assert(midState, gc.NotNil)
   444  
   445  	newState, err := op.Execute(*midState)
   446  	c.Check(err, jc.ErrorIsNil)
   447  	c.Check(newState, gc.DeepEquals, &after)
   448  	c.Check(deployer.MockDeploy.called, jc.IsTrue)
   449  }
   450  
   451  func (s *DeploySuite) TestExecuteSuccess_Install_BlankSlate(c *gc.C) {
   452  	s.testExecuteSuccess(c,
   453  		(operation.Factory).NewInstall,
   454  		operation.State{},
   455  		operation.State{
   456  			Kind:     operation.Install,
   457  			Step:     operation.Done,
   458  			CharmURL: curl("cs:quantal/lol-1"),
   459  		},
   460  	)
   461  }
   462  
   463  func (s *DeploySuite) TestExecuteSuccess_Install_Queued(c *gc.C) {
   464  	s.testExecuteSuccess(c,
   465  		(operation.Factory).NewInstall,
   466  		operation.State{
   467  			Kind:     operation.Install,
   468  			Step:     operation.Queued,
   469  			CharmURL: curl("cs:quantal/lol-1"),
   470  		},
   471  		operation.State{
   472  			Kind:     operation.Install,
   473  			Step:     operation.Done,
   474  			CharmURL: curl("cs:quantal/lol-1"),
   475  		},
   476  	)
   477  }
   478  
   479  func (s *DeploySuite) TestExecuteSuccess_Upgrade_PreservePendingHook(c *gc.C) {
   480  	for i, newDeploy := range []newDeploy{
   481  		(operation.Factory).NewUpgrade,
   482  		(operation.Factory).NewRevertUpgrade,
   483  		(operation.Factory).NewResolvedUpgrade,
   484  	} {
   485  		c.Logf("variant %d", i)
   486  		s.testExecuteSuccess(c,
   487  			newDeploy,
   488  			operation.State{
   489  				Kind: operation.RunHook,
   490  				Step: operation.Pending,
   491  				Hook: &hook.Info{Kind: hooks.ConfigChanged},
   492  			},
   493  			operation.State{
   494  				Kind:     operation.Upgrade,
   495  				Step:     operation.Done,
   496  				CharmURL: curl("cs:quantal/lol-1"),
   497  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   498  			},
   499  		)
   500  	}
   501  }
   502  
   503  func (s *DeploySuite) TestExecuteSuccess_Upgrade_PreserveOriginalPendingHook(c *gc.C) {
   504  	for i, newDeploy := range []newDeploy{
   505  		(operation.Factory).NewUpgrade,
   506  		(operation.Factory).NewRevertUpgrade,
   507  		(operation.Factory).NewResolvedUpgrade,
   508  	} {
   509  		c.Logf("variant %d", i)
   510  		s.testExecuteSuccess(c,
   511  			newDeploy,
   512  			operation.State{
   513  				Kind:     operation.Upgrade,
   514  				Step:     operation.Pending,
   515  				CharmURL: curl("cs:quantal/wild-9"),
   516  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   517  			},
   518  			operation.State{
   519  				Kind:     operation.Upgrade,
   520  				Step:     operation.Done,
   521  				CharmURL: curl("cs:quantal/lol-1"),
   522  				Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   523  			},
   524  		)
   525  	}
   526  }
   527  
   528  func (s *DeploySuite) TestExecuteSuccess_Upgrade_PreserveNoHook(c *gc.C) {
   529  	for i, newDeploy := range []newDeploy{
   530  		(operation.Factory).NewUpgrade,
   531  		(operation.Factory).NewRevertUpgrade,
   532  		(operation.Factory).NewResolvedUpgrade,
   533  	} {
   534  		c.Logf("variant %d", i)
   535  		s.testExecuteSuccess(c,
   536  			newDeploy,
   537  			overwriteState,
   538  			operation.State{
   539  				Kind:               operation.Upgrade,
   540  				Step:               operation.Done,
   541  				CharmURL:           curl("cs:quantal/lol-1"),
   542  				Started:            true,
   543  				CollectMetricsTime: 1234567,
   544  				UpdateStatusTime:   1234567,
   545  			},
   546  		)
   547  	}
   548  }
   549  
   550  func (s *DeploySuite) testCommitMetricsError(c *gc.C, newDeploy newDeploy) {
   551  	callbacks := NewDeployCommitCallbacks(errors.New("glukh"))
   552  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
   553  	op, err := newDeploy(factory, curl("cs:quantal/x-0"))
   554  	c.Assert(err, jc.ErrorIsNil)
   555  	newState, err := op.Commit(operation.State{})
   556  	c.Check(err, gc.ErrorMatches, "glukh")
   557  	c.Check(newState, gc.IsNil)
   558  }
   559  
   560  func (s *DeploySuite) TestCommitMetricsError_Install(c *gc.C) {
   561  	s.testCommitMetricsError(c, (operation.Factory).NewInstall)
   562  }
   563  
   564  func (s *DeploySuite) TestCommitMetricsError_Upgrade(c *gc.C) {
   565  	s.testCommitMetricsError(c, (operation.Factory).NewUpgrade)
   566  }
   567  
   568  func (s *DeploySuite) TestCommitMetricsError_RevertUpgrade(c *gc.C) {
   569  	s.testCommitMetricsError(c, (operation.Factory).NewRevertUpgrade)
   570  }
   571  
   572  func (s *DeploySuite) TestCommitMetricsError_ResolvedUpgrade(c *gc.C) {
   573  	s.testCommitMetricsError(c, (operation.Factory).NewResolvedUpgrade)
   574  }
   575  
   576  func (s *DeploySuite) TestCommitQueueInstallHook(c *gc.C) {
   577  	callbacks := NewDeployCommitCallbacks(nil)
   578  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
   579  	op, err := factory.NewInstall(curl("cs:quantal/x-0"))
   580  	c.Assert(err, jc.ErrorIsNil)
   581  	newState, err := op.Commit(operation.State{
   582  		Kind:     operation.Install,
   583  		Step:     operation.Done,
   584  		CharmURL: nil, // doesn't actually matter here
   585  	})
   586  	c.Check(err, jc.ErrorIsNil)
   587  	c.Check(newState, gc.DeepEquals, &operation.State{
   588  		Kind: operation.RunHook,
   589  		Step: operation.Queued,
   590  		Hook: &hook.Info{Kind: hooks.Install},
   591  	})
   592  }
   593  
   594  func (s *DeploySuite) testCommitQueueUpgradeHook(c *gc.C, newDeploy newDeploy) {
   595  	callbacks := NewDeployCommitCallbacks(nil)
   596  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
   597  	op, err := newDeploy(factory, curl("cs:quantal/x-0"))
   598  	c.Assert(err, jc.ErrorIsNil)
   599  	newState, err := op.Commit(operation.State{
   600  		Kind:     operation.Upgrade,
   601  		Step:     operation.Done,
   602  		CharmURL: nil, // doesn't actually matter here
   603  	})
   604  	c.Check(err, jc.ErrorIsNil)
   605  	c.Check(newState, gc.DeepEquals, &operation.State{
   606  		Kind: operation.RunHook,
   607  		Step: operation.Queued,
   608  		Hook: &hook.Info{Kind: hooks.UpgradeCharm},
   609  	})
   610  }
   611  
   612  func (s *DeploySuite) TestCommitQueueUpgradeHook_Upgrade(c *gc.C) {
   613  	s.testCommitQueueUpgradeHook(c, (operation.Factory).NewUpgrade)
   614  }
   615  
   616  func (s *DeploySuite) TestCommitQueueUpgradeHook_RevertUpgrade(c *gc.C) {
   617  	s.testCommitQueueUpgradeHook(c, (operation.Factory).NewRevertUpgrade)
   618  }
   619  
   620  func (s *DeploySuite) TestCommitQueueUpgradeHook_ResolvedUpgrade(c *gc.C) {
   621  	s.testCommitQueueUpgradeHook(c, (operation.Factory).NewResolvedUpgrade)
   622  }
   623  
   624  func (s *DeploySuite) testCommitInterruptedHook(c *gc.C, newDeploy newDeploy) {
   625  	callbacks := NewDeployCommitCallbacks(nil)
   626  	factory := operation.NewFactory(nil, nil, callbacks, nil, nil)
   627  	op, err := newDeploy(factory, curl("cs:quantal/x-0"))
   628  	c.Assert(err, jc.ErrorIsNil)
   629  	newState, err := op.Commit(operation.State{
   630  		Kind:     operation.Upgrade,
   631  		Step:     operation.Done,
   632  		CharmURL: nil, // doesn't actually matter here
   633  		Hook:     &hook.Info{Kind: hooks.ConfigChanged},
   634  	})
   635  	c.Check(err, jc.ErrorIsNil)
   636  	c.Check(newState, gc.DeepEquals, &operation.State{
   637  		Kind: operation.RunHook,
   638  		Step: operation.Pending,
   639  		Hook: &hook.Info{Kind: hooks.ConfigChanged},
   640  	})
   641  }
   642  
   643  func (s *DeploySuite) TestCommitInterruptedHook_Upgrade(c *gc.C) {
   644  	s.testCommitInterruptedHook(c, (operation.Factory).NewUpgrade)
   645  }
   646  
   647  func (s *DeploySuite) TestCommitInterruptedHook_RevertUpgrade(c *gc.C) {
   648  	s.testCommitInterruptedHook(c, (operation.Factory).NewRevertUpgrade)
   649  }
   650  
   651  func (s *DeploySuite) TestCommitInterruptedHook_ResolvedUpgrade(c *gc.C) {
   652  	s.testCommitInterruptedHook(c, (operation.Factory).NewResolvedUpgrade)
   653  }
   654  
   655  func (s *DeploySuite) testDoesNotNeedGlobalMachineLock(c *gc.C, newDeploy newDeploy) {
   656  	factory := operation.NewFactory(nil, nil, nil, nil, nil)
   657  	op, err := newDeploy(factory, curl("cs:quantal/x-0"))
   658  	c.Assert(err, jc.ErrorIsNil)
   659  	c.Assert(op.NeedsGlobalMachineLock(), jc.IsFalse)
   660  }
   661  
   662  func (s *DeploySuite) TestDoesNotNeedGlobalMachineLock_Install(c *gc.C) {
   663  	s.testDoesNotNeedGlobalMachineLock(c, (operation.Factory).NewInstall)
   664  }
   665  
   666  func (s *DeploySuite) TestDoesNotNeedGlobalMachineLock_Upgrade(c *gc.C) {
   667  	s.testDoesNotNeedGlobalMachineLock(c, (operation.Factory).NewUpgrade)
   668  }
   669  
   670  func (s *DeploySuite) TestDoesNotNeedGlobalMachineLock_RevertUpgrade(c *gc.C) {
   671  	s.testDoesNotNeedGlobalMachineLock(c, (operation.Factory).NewRevertUpgrade)
   672  }
   673  
   674  func (s *DeploySuite) TestDoesNotNeedGlobalMachineLock_ResolvedUpgrade(c *gc.C) {
   675  	s.testDoesNotNeedGlobalMachineLock(c, (operation.Factory).NewResolvedUpgrade)
   676  }