github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/resolver/opfactory_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package resolver_test
     5  
     6  import (
     7  	"errors"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/charm.v6"
    12  	"gopkg.in/juju/charm.v6/hooks"
    13  
    14  	"github.com/juju/juju/core/model"
    15  	"github.com/juju/juju/testing"
    16  	"github.com/juju/juju/worker/uniter/hook"
    17  	"github.com/juju/juju/worker/uniter/operation"
    18  	"github.com/juju/juju/worker/uniter/remotestate"
    19  	"github.com/juju/juju/worker/uniter/resolver"
    20  )
    21  
    22  type ResolverOpFactorySuite struct {
    23  	testing.BaseSuite
    24  	opFactory *mockOpFactory
    25  }
    26  
    27  var _ = gc.Suite(&ResolverOpFactorySuite{})
    28  
    29  func (s *ResolverOpFactorySuite) SetUpTest(c *gc.C) {
    30  	s.BaseSuite.SetUpTest(c)
    31  	s.opFactory = &mockOpFactory{}
    32  }
    33  
    34  func (s *ResolverOpFactorySuite) TestInitialState(c *gc.C) {
    35  	f := resolver.NewResolverOpFactory(s.opFactory)
    36  	c.Assert(f.LocalState, jc.DeepEquals, &resolver.LocalState{})
    37  	c.Assert(f.RemoteState, jc.DeepEquals, remotestate.Snapshot{})
    38  }
    39  
    40  func (s *ResolverOpFactorySuite) TestUpdateStatusChanged(c *gc.C) {
    41  	s.testUpdateStatusChanged(c, resolver.ResolverOpFactory.NewRunHook)
    42  	s.testUpdateStatusChanged(c, resolver.ResolverOpFactory.NewSkipHook)
    43  }
    44  
    45  func (s *ResolverOpFactorySuite) testUpdateStatusChanged(
    46  	c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error),
    47  ) {
    48  	f := resolver.NewResolverOpFactory(s.opFactory)
    49  	f.RemoteState.UpdateStatusVersion = 1
    50  
    51  	op, err := f.NewRunHook(hook.Info{Kind: hooks.UpdateStatus})
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	f.RemoteState.UpdateStatusVersion = 2
    54  
    55  	_, err = op.Commit(operation.State{})
    56  	c.Assert(err, jc.ErrorIsNil)
    57  
    58  	// Local state's UpdateStatusVersion should be set to what
    59  	// RemoteState's UpdateStatusVersion was when the operation
    60  	// was constructed.
    61  	c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 1)
    62  }
    63  
    64  func (s *ResolverOpFactorySuite) TestConfigChanged(c *gc.C) {
    65  	s.testConfigChanged(c, resolver.ResolverOpFactory.NewRunHook)
    66  	s.testConfigChanged(c, resolver.ResolverOpFactory.NewSkipHook)
    67  }
    68  
    69  func (s *ResolverOpFactorySuite) TestUpgradeSeriesStatusChanged(c *gc.C) {
    70  	f := resolver.NewResolverOpFactory(s.opFactory)
    71  
    72  	// The initial state.
    73  	f.LocalState.UpgradeSeriesStatus = model.UpgradeSeriesNotStarted
    74  	f.RemoteState.UpgradeSeriesStatus = model.UpgradeSeriesPrepareStarted
    75  
    76  	op, err := f.NewRunHook(hook.Info{Kind: hooks.PreSeriesUpgrade})
    77  	c.Assert(err, jc.ErrorIsNil)
    78  
    79  	_, err = op.Prepare(operation.State{})
    80  	c.Assert(err, jc.ErrorIsNil)
    81  
    82  	c.Assert(f.LocalState.UpgradeSeriesStatus, gc.Equals, model.UpgradeSeriesPrepareStarted)
    83  	f.RemoteState.UpgradeSeriesStatus = model.UpgradeSeriesPrepareCompleted
    84  
    85  	_, err = op.Commit(operation.State{})
    86  	c.Assert(err, jc.ErrorIsNil)
    87  
    88  	c.Assert(f.LocalState.UpgradeSeriesStatus, gc.Equals, model.UpgradeSeriesPrepareCompleted)
    89  }
    90  
    91  func (s *ResolverOpFactorySuite) TestNewHookError(c *gc.C) {
    92  	s.opFactory.SetErrors(
    93  		errors.New("NewRunHook fails"),
    94  		errors.New("NewSkipHook fails"),
    95  	)
    96  	f := resolver.NewResolverOpFactory(s.opFactory)
    97  	_, err := f.NewRunHook(hook.Info{Kind: hooks.ConfigChanged})
    98  	c.Assert(err, gc.ErrorMatches, "NewRunHook fails")
    99  	_, err = f.NewSkipHook(hook.Info{Kind: hooks.ConfigChanged})
   100  	c.Assert(err, gc.ErrorMatches, "NewSkipHook fails")
   101  }
   102  
   103  func (s *ResolverOpFactorySuite) testConfigChanged(
   104  	c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error),
   105  ) {
   106  	f := resolver.NewResolverOpFactory(s.opFactory)
   107  	f.RemoteState.ConfigHash = "confighash"
   108  	f.RemoteState.TrustHash = "trusthash"
   109  	f.RemoteState.AddressesHash = "addresseshash"
   110  	f.RemoteState.UpdateStatusVersion = 3
   111  
   112  	op, err := f.NewRunHook(hook.Info{Kind: hooks.ConfigChanged})
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	f.RemoteState.ConfigHash = "newhash"
   115  	f.RemoteState.TrustHash = "badhash"
   116  	f.RemoteState.AddressesHash = "differenthash"
   117  	f.RemoteState.UpdateStatusVersion = 4
   118  
   119  	resultState, err := op.Commit(operation.State{})
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	c.Assert(resultState, gc.NotNil)
   122  
   123  	// Local state's UpdateStatusVersion should be set to what
   124  	// RemoteState's UpdateStatusVersion was when the operation
   125  	// was constructed.
   126  	c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 3)
   127  	// The hashes need to be set on the result state, because that is
   128  	// written to disk by the executor before the next step is picked.
   129  	c.Assert(resultState.ConfigHash, gc.Equals, "confighash")
   130  	c.Assert(resultState.TrustHash, gc.Equals, "trusthash")
   131  	c.Assert(resultState.AddressesHash, gc.Equals, "addresseshash")
   132  }
   133  
   134  func (s *ResolverOpFactorySuite) TestLeaderSettingsChanged(c *gc.C) {
   135  	s.testLeaderSettingsChanged(c, resolver.ResolverOpFactory.NewRunHook)
   136  	s.testLeaderSettingsChanged(c, resolver.ResolverOpFactory.NewSkipHook)
   137  }
   138  
   139  func (s *ResolverOpFactorySuite) testLeaderSettingsChanged(
   140  	c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error),
   141  ) {
   142  	f := resolver.NewResolverOpFactory(s.opFactory)
   143  	f.RemoteState.LeaderSettingsVersion = 1
   144  	f.RemoteState.UpdateStatusVersion = 3
   145  
   146  	op, err := meth(f, hook.Info{Kind: hooks.LeaderSettingsChanged})
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	f.RemoteState.LeaderSettingsVersion = 2
   149  	f.RemoteState.UpdateStatusVersion = 4
   150  
   151  	_, err = op.Commit(operation.State{})
   152  	c.Assert(err, jc.ErrorIsNil)
   153  
   154  	// Local state's LeaderSettingsVersion should be set to what
   155  	// RemoteState's LeaderSettingsVersion was when the operation
   156  	// was constructed.
   157  	c.Assert(f.LocalState.LeaderSettingsVersion, gc.Equals, 1)
   158  	c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 3)
   159  }
   160  
   161  func (s *ResolverOpFactorySuite) TestUpgrade(c *gc.C) {
   162  	s.testUpgrade(c, resolver.ResolverOpFactory.NewUpgrade)
   163  	s.testUpgrade(c, resolver.ResolverOpFactory.NewRevertUpgrade)
   164  	s.testUpgrade(c, resolver.ResolverOpFactory.NewResolvedUpgrade)
   165  	s.testUpgrade(c, resolver.ResolverOpFactory.NewNoOpUpgrade)
   166  }
   167  
   168  func (s *ResolverOpFactorySuite) testUpgrade(
   169  	c *gc.C, meth func(resolver.ResolverOpFactory, *charm.URL) (operation.Operation, error),
   170  ) {
   171  	f := resolver.NewResolverOpFactory(s.opFactory)
   172  	f.LocalState.Conflicted = true
   173  	curl := charm.MustParseURL("cs:trusty/mysql")
   174  	op, err := meth(f, curl)
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	_, err = op.Commit(operation.State{})
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	c.Assert(f.LocalState.CharmURL, jc.DeepEquals, curl)
   179  	c.Assert(f.LocalState.Conflicted, jc.IsFalse)
   180  }
   181  
   182  func (s *ResolverOpFactorySuite) TestNewUpgradeError(c *gc.C) {
   183  	curl := charm.MustParseURL("cs:trusty/mysql")
   184  	s.opFactory.SetErrors(
   185  		errors.New("NewUpgrade fails"),
   186  		errors.New("NewRevertUpgrade fails"),
   187  		errors.New("NewResolvedUpgrade fails"),
   188  	)
   189  	f := resolver.NewResolverOpFactory(s.opFactory)
   190  	_, err := f.NewUpgrade(curl)
   191  	c.Assert(err, gc.ErrorMatches, "NewUpgrade fails")
   192  	_, err = f.NewRevertUpgrade(curl)
   193  	c.Assert(err, gc.ErrorMatches, "NewRevertUpgrade fails")
   194  	_, err = f.NewResolvedUpgrade(curl)
   195  	c.Assert(err, gc.ErrorMatches, "NewResolvedUpgrade fails")
   196  }
   197  
   198  func (s *ResolverOpFactorySuite) TestCommitError(c *gc.C) {
   199  	f := resolver.NewResolverOpFactory(s.opFactory)
   200  	curl := charm.MustParseURL("cs:trusty/mysql")
   201  	s.opFactory.op.commit = func(operation.State) (*operation.State, error) {
   202  		return nil, errors.New("commit fails")
   203  	}
   204  	op, err := f.NewUpgrade(curl)
   205  	c.Assert(err, jc.ErrorIsNil)
   206  	_, err = op.Commit(operation.State{})
   207  	c.Assert(err, gc.ErrorMatches, "commit fails")
   208  	// Local state should not have been updated. We use the same code
   209  	// internally for all operations, so it suffices to test just the
   210  	// upgrade case.
   211  	c.Assert(f.LocalState.CharmURL, gc.IsNil)
   212  }
   213  
   214  func (s *ResolverOpFactorySuite) TestActionsCommit(c *gc.C) {
   215  	f := resolver.NewResolverOpFactory(s.opFactory)
   216  	f.RemoteState.Actions = []string{"action 1", "action 2", "action 3"}
   217  	f.LocalState.CompletedActions = map[string]struct{}{}
   218  	op, err := f.NewAction("action 1")
   219  	c.Assert(err, jc.ErrorIsNil)
   220  	_, err = op.Commit(operation.State{})
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	c.Assert(f.LocalState.CompletedActions, gc.DeepEquals, map[string]struct{}{
   223  		"action 1": {},
   224  	})
   225  }
   226  
   227  func (s *ResolverOpFactorySuite) TestActionsTrimming(c *gc.C) {
   228  	f := resolver.NewResolverOpFactory(s.opFactory)
   229  	f.RemoteState.Actions = []string{"c", "d"}
   230  	f.LocalState.CompletedActions = map[string]struct{}{
   231  		"a": {},
   232  		"b": {},
   233  		"c": {},
   234  	}
   235  	op, err := f.NewAction("d")
   236  	c.Assert(err, jc.ErrorIsNil)
   237  	_, err = op.Commit(operation.State{})
   238  	c.Assert(err, jc.ErrorIsNil)
   239  	c.Assert(f.LocalState.CompletedActions, gc.DeepEquals, map[string]struct{}{
   240  		"c": {},
   241  		"d": {},
   242  	})
   243  }