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 }