github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/resolver_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_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"
    12  	"gopkg.in/juju/charm.v6-unstable/hooks"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/worker/uniter"
    17  	uniteractions "github.com/juju/juju/worker/uniter/actions"
    18  	"github.com/juju/juju/worker/uniter/hook"
    19  	"github.com/juju/juju/worker/uniter/leadership"
    20  	"github.com/juju/juju/worker/uniter/operation"
    21  	"github.com/juju/juju/worker/uniter/relation"
    22  	"github.com/juju/juju/worker/uniter/remotestate"
    23  	"github.com/juju/juju/worker/uniter/resolver"
    24  	"github.com/juju/juju/worker/uniter/storage"
    25  )
    26  
    27  type resolverSuite struct {
    28  	stub                 testing.Stub
    29  	charmModifiedVersion int
    30  	charmURL             *charm.URL
    31  	remoteState          remotestate.Snapshot
    32  	opFactory            operation.Factory
    33  	resolver             resolver.Resolver
    34  	resolverConfig       uniter.ResolverConfig
    35  
    36  	clearResolved   func() error
    37  	reportHookError func(hook.Info) error
    38  }
    39  
    40  var _ = gc.Suite(&resolverSuite{})
    41  
    42  func (s *resolverSuite) SetUpTest(c *gc.C) {
    43  	s.stub = testing.Stub{}
    44  	s.charmURL = charm.MustParseURL("cs:precise/mysql-2")
    45  	s.remoteState = remotestate.Snapshot{
    46  		CharmModifiedVersion: s.charmModifiedVersion,
    47  		CharmURL:             s.charmURL,
    48  	}
    49  	s.opFactory = operation.NewFactory(operation.FactoryParams{})
    50  
    51  	attachments, err := storage.NewAttachments(&dummyStorageAccessor{}, names.NewUnitTag("u/0"), c.MkDir(), nil)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  
    54  	s.clearResolved = func() error {
    55  		return errors.New("unexpected resolved")
    56  	}
    57  
    58  	s.reportHookError = func(hook.Info) error {
    59  		return errors.New("unexpected report hook error")
    60  	}
    61  
    62  	s.resolverConfig = uniter.ResolverConfig{
    63  		ClearResolved:       func() error { return s.clearResolved() },
    64  		ReportHookError:     func(info hook.Info) error { return s.reportHookError(info) },
    65  		StartRetryHookTimer: func() { s.stub.AddCall("StartRetryHookTimer") },
    66  		StopRetryHookTimer:  func() { s.stub.AddCall("StopRetryHookTimer") },
    67  		ShouldRetryHooks:    true,
    68  		Leadership:          leadership.NewResolver(),
    69  		Actions:             uniteractions.NewResolver(),
    70  		Relations:           relation.NewRelationsResolver(&dummyRelations{}),
    71  		Storage:             storage.NewResolver(attachments),
    72  		Commands:            nopResolver{},
    73  	}
    74  
    75  	s.resolver = uniter.NewUniterResolver(s.resolverConfig)
    76  }
    77  
    78  // TestStartedNotInstalled tests whether the Started flag overrides the
    79  // Installed flag being unset, in the event of an unexpected inconsistency in
    80  // local state.
    81  func (s *resolverSuite) TestStartedNotInstalled(c *gc.C) {
    82  	localState := resolver.LocalState{
    83  		CharmModifiedVersion: s.charmModifiedVersion,
    84  		CharmURL:             s.charmURL,
    85  		State: operation.State{
    86  			Kind:      operation.Continue,
    87  			Installed: false,
    88  			Started:   true,
    89  		},
    90  	}
    91  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
    92  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
    93  }
    94  
    95  // TestNotStartedNotInstalled tests whether the next operation for an
    96  // uninstalled local state is an install hook operation.
    97  func (s *resolverSuite) TestNotStartedNotInstalled(c *gc.C) {
    98  	localState := resolver.LocalState{
    99  		CharmModifiedVersion: s.charmModifiedVersion,
   100  		CharmURL:             s.charmURL,
   101  		State: operation.State{
   102  			Kind:      operation.Continue,
   103  			Installed: false,
   104  			Started:   false,
   105  		},
   106  	}
   107  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  	c.Assert(op.String(), gc.Equals, "run install hook")
   110  }
   111  
   112  func (s *resolverSuite) TestHookErrorDoesNotStartRetryTimerIfShouldRetryFalse(c *gc.C) {
   113  	s.resolverConfig.ShouldRetryHooks = false
   114  	s.resolver = uniter.NewUniterResolver(s.resolverConfig)
   115  	s.reportHookError = func(hook.Info) error { return nil }
   116  	localState := resolver.LocalState{
   117  		CharmURL: s.charmURL,
   118  		State: operation.State{
   119  			Kind:      operation.RunHook,
   120  			Step:      operation.Pending,
   121  			Installed: true,
   122  			Started:   true,
   123  			Hook: &hook.Info{
   124  				Kind: hooks.ConfigChanged,
   125  			},
   126  		},
   127  	}
   128  	// Run the resolver; we should not attempt a hook retry
   129  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   130  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   131  	s.stub.CheckNoCalls(c)
   132  }
   133  
   134  func (s *resolverSuite) TestHookErrorStartRetryTimer(c *gc.C) {
   135  	s.reportHookError = func(hook.Info) error { return nil }
   136  	localState := resolver.LocalState{
   137  		CharmModifiedVersion: s.charmModifiedVersion,
   138  		CharmURL:             s.charmURL,
   139  		State: operation.State{
   140  			Kind:      operation.RunHook,
   141  			Step:      operation.Pending,
   142  			Installed: true,
   143  			Started:   true,
   144  			Hook: &hook.Info{
   145  				Kind: hooks.ConfigChanged,
   146  			},
   147  		},
   148  	}
   149  	// Run the resolver twice; we should start the hook retry
   150  	// timer on the first time through, no change on the second.
   151  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   152  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   153  	s.stub.CheckCallNames(c, "StartRetryHookTimer")
   154  
   155  	_, err = s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   156  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   157  	s.stub.CheckCallNames(c, "StartRetryHookTimer") // no change
   158  }
   159  
   160  func (s *resolverSuite) TestHookErrorStartRetryTimerAgain(c *gc.C) {
   161  	s.reportHookError = func(hook.Info) error { return nil }
   162  	localState := resolver.LocalState{
   163  		CharmModifiedVersion: s.charmModifiedVersion,
   164  		CharmURL:             s.charmURL,
   165  		State: operation.State{
   166  			Kind:      operation.RunHook,
   167  			Step:      operation.Pending,
   168  			Installed: true,
   169  			Started:   true,
   170  			Hook: &hook.Info{
   171  				Kind: hooks.ConfigChanged,
   172  			},
   173  		},
   174  	}
   175  
   176  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   177  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   178  	s.stub.CheckCallNames(c, "StartRetryHookTimer")
   179  
   180  	s.remoteState.RetryHookVersion = 1
   181  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	c.Assert(op.String(), gc.Equals, "run config-changed hook")
   184  	s.stub.CheckCallNames(c, "StartRetryHookTimer") // no change
   185  	localState.RetryHookVersion = 1
   186  
   187  	_, err = s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   188  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   189  	s.stub.CheckCallNames(c, "StartRetryHookTimer", "StartRetryHookTimer")
   190  }
   191  
   192  func (s *resolverSuite) TestResolvedRetryHooksStopRetryTimer(c *gc.C) {
   193  	// Resolving a failed hook should stop the retry timer.
   194  	s.testResolveHookErrorStopRetryTimer(c, params.ResolvedRetryHooks)
   195  }
   196  
   197  func (s *resolverSuite) TestResolvedNoHooksStopRetryTimer(c *gc.C) {
   198  	// Resolving a failed hook should stop the retry timer.
   199  	s.testResolveHookErrorStopRetryTimer(c, params.ResolvedNoHooks)
   200  }
   201  
   202  func (s *resolverSuite) testResolveHookErrorStopRetryTimer(c *gc.C, mode params.ResolvedMode) {
   203  	s.stub.ResetCalls()
   204  	s.clearResolved = func() error { return nil }
   205  	s.reportHookError = func(hook.Info) error { return nil }
   206  	localState := resolver.LocalState{
   207  		CharmModifiedVersion: s.charmModifiedVersion,
   208  		CharmURL:             s.charmURL,
   209  		State: operation.State{
   210  			Kind:      operation.RunHook,
   211  			Step:      operation.Pending,
   212  			Installed: true,
   213  			Started:   true,
   214  			Hook: &hook.Info{
   215  				Kind: hooks.ConfigChanged,
   216  			},
   217  		},
   218  	}
   219  
   220  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   221  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   222  	s.stub.CheckCallNames(c, "StartRetryHookTimer")
   223  
   224  	s.remoteState.ResolvedMode = mode
   225  	_, err = s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	s.stub.CheckCallNames(c, "StartRetryHookTimer", "StopRetryHookTimer")
   228  }
   229  
   230  func (s *resolverSuite) TestRunHookStopRetryTimer(c *gc.C) {
   231  	s.reportHookError = func(hook.Info) error { return nil }
   232  	localState := resolver.LocalState{
   233  		CharmModifiedVersion: s.charmModifiedVersion,
   234  		CharmURL:             s.charmURL,
   235  		State: operation.State{
   236  			Kind:      operation.RunHook,
   237  			Step:      operation.Pending,
   238  			Installed: true,
   239  			Started:   true,
   240  			Hook: &hook.Info{
   241  				Kind: hooks.ConfigChanged,
   242  			},
   243  		},
   244  	}
   245  
   246  	_, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   247  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   248  	s.stub.CheckCallNames(c, "StartRetryHookTimer")
   249  
   250  	localState.Kind = operation.Continue
   251  	_, err = s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   252  	c.Assert(err, gc.Equals, resolver.ErrNoOperation)
   253  	s.stub.CheckCallNames(c, "StartRetryHookTimer", "StopRetryHookTimer")
   254  }