github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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-unstable" 12 "gopkg.in/juju/charm.v6-unstable/hooks" 13 14 "github.com/juju/juju/testing" 15 "github.com/juju/juju/worker/uniter/hook" 16 "github.com/juju/juju/worker/uniter/operation" 17 "github.com/juju/juju/worker/uniter/remotestate" 18 "github.com/juju/juju/worker/uniter/resolver" 19 ) 20 21 type ResolverOpFactorySuite struct { 22 testing.BaseSuite 23 opFactory *mockOpFactory 24 } 25 26 var _ = gc.Suite(&ResolverOpFactorySuite{}) 27 28 func (s *ResolverOpFactorySuite) SetUpTest(c *gc.C) { 29 s.BaseSuite.SetUpTest(c) 30 s.opFactory = &mockOpFactory{} 31 } 32 33 func (s *ResolverOpFactorySuite) TestInitialState(c *gc.C) { 34 f := resolver.NewResolverOpFactory(s.opFactory) 35 c.Assert(f.LocalState, jc.DeepEquals, &resolver.LocalState{}) 36 c.Assert(f.RemoteState, jc.DeepEquals, remotestate.Snapshot{}) 37 } 38 39 func (s *ResolverOpFactorySuite) TestUpdateStatusChanged(c *gc.C) { 40 s.testUpdateStatusChanged(c, resolver.ResolverOpFactory.NewRunHook) 41 s.testUpdateStatusChanged(c, resolver.ResolverOpFactory.NewSkipHook) 42 } 43 44 func (s *ResolverOpFactorySuite) testUpdateStatusChanged( 45 c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error), 46 ) { 47 f := resolver.NewResolverOpFactory(s.opFactory) 48 f.RemoteState.UpdateStatusVersion = 1 49 50 op, err := f.NewRunHook(hook.Info{Kind: hooks.UpdateStatus}) 51 c.Assert(err, jc.ErrorIsNil) 52 f.RemoteState.UpdateStatusVersion = 2 53 54 _, err = op.Commit(operation.State{}) 55 c.Assert(err, jc.ErrorIsNil) 56 57 // Local state's UpdateStatusVersion should be set to what 58 // RemoteState's UpdateStatusVersion was when the operation 59 // was constructed. 60 c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 1) 61 } 62 63 func (s *ResolverOpFactorySuite) TestConfigChanged(c *gc.C) { 64 s.testConfigChanged(c, resolver.ResolverOpFactory.NewRunHook) 65 s.testConfigChanged(c, resolver.ResolverOpFactory.NewSkipHook) 66 } 67 68 func (s *ResolverOpFactorySuite) TestNewHookError(c *gc.C) { 69 s.opFactory.SetErrors( 70 errors.New("NewRunHook fails"), 71 errors.New("NewSkipHook fails"), 72 ) 73 f := resolver.NewResolverOpFactory(s.opFactory) 74 _, err := f.NewRunHook(hook.Info{Kind: hooks.ConfigChanged}) 75 c.Assert(err, gc.ErrorMatches, "NewRunHook fails") 76 _, err = f.NewSkipHook(hook.Info{Kind: hooks.ConfigChanged}) 77 c.Assert(err, gc.ErrorMatches, "NewSkipHook fails") 78 } 79 80 func (s *ResolverOpFactorySuite) testConfigChanged( 81 c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error), 82 ) { 83 f := resolver.NewResolverOpFactory(s.opFactory) 84 f.RemoteState.ConfigVersion = 1 85 f.RemoteState.UpdateStatusVersion = 3 86 87 op, err := f.NewRunHook(hook.Info{Kind: hooks.ConfigChanged}) 88 c.Assert(err, jc.ErrorIsNil) 89 f.RemoteState.ConfigVersion = 2 90 f.RemoteState.UpdateStatusVersion = 4 91 92 _, err = op.Commit(operation.State{}) 93 c.Assert(err, jc.ErrorIsNil) 94 95 // Local state's ConfigVersion should be set to what 96 // RemoteState's ConfigVersion was when the operation 97 // was constructed. 98 c.Assert(f.LocalState.ConfigVersion, gc.Equals, 1) 99 c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 3) 100 } 101 102 func (s *ResolverOpFactorySuite) TestLeaderSettingsChanged(c *gc.C) { 103 s.testLeaderSettingsChanged(c, resolver.ResolverOpFactory.NewRunHook) 104 s.testLeaderSettingsChanged(c, resolver.ResolverOpFactory.NewSkipHook) 105 } 106 107 func (s *ResolverOpFactorySuite) testLeaderSettingsChanged( 108 c *gc.C, meth func(resolver.ResolverOpFactory, hook.Info) (operation.Operation, error), 109 ) { 110 f := resolver.NewResolverOpFactory(s.opFactory) 111 f.RemoteState.LeaderSettingsVersion = 1 112 f.RemoteState.UpdateStatusVersion = 3 113 114 op, err := meth(f, hook.Info{Kind: hooks.LeaderSettingsChanged}) 115 c.Assert(err, jc.ErrorIsNil) 116 f.RemoteState.LeaderSettingsVersion = 2 117 f.RemoteState.UpdateStatusVersion = 4 118 119 _, err = op.Commit(operation.State{}) 120 c.Assert(err, jc.ErrorIsNil) 121 122 // Local state's LeaderSettingsVersion should be set to what 123 // RemoteState's LeaderSettingsVersion was when the operation 124 // was constructed. 125 c.Assert(f.LocalState.LeaderSettingsVersion, gc.Equals, 1) 126 c.Assert(f.LocalState.UpdateStatusVersion, gc.Equals, 3) 127 } 128 129 func (s *ResolverOpFactorySuite) TestUpgrade(c *gc.C) { 130 s.testUpgrade(c, resolver.ResolverOpFactory.NewUpgrade) 131 s.testUpgrade(c, resolver.ResolverOpFactory.NewRevertUpgrade) 132 s.testUpgrade(c, resolver.ResolverOpFactory.NewResolvedUpgrade) 133 } 134 135 func (s *ResolverOpFactorySuite) testUpgrade( 136 c *gc.C, meth func(resolver.ResolverOpFactory, *charm.URL) (operation.Operation, error), 137 ) { 138 f := resolver.NewResolverOpFactory(s.opFactory) 139 f.LocalState.Conflicted = true 140 curl := charm.MustParseURL("cs:trusty/mysql") 141 op, err := meth(f, curl) 142 c.Assert(err, jc.ErrorIsNil) 143 _, err = op.Commit(operation.State{}) 144 c.Assert(err, jc.ErrorIsNil) 145 c.Assert(f.LocalState.CharmURL, jc.DeepEquals, curl) 146 c.Assert(f.LocalState.Conflicted, jc.IsFalse) 147 } 148 149 func (s *ResolverOpFactorySuite) TestNewUpgradeError(c *gc.C) { 150 curl := charm.MustParseURL("cs:trusty/mysql") 151 s.opFactory.SetErrors( 152 errors.New("NewUpgrade fails"), 153 errors.New("NewRevertUpgrade fails"), 154 errors.New("NewResolvedUpgrade fails"), 155 ) 156 f := resolver.NewResolverOpFactory(s.opFactory) 157 _, err := f.NewUpgrade(curl) 158 c.Assert(err, gc.ErrorMatches, "NewUpgrade fails") 159 _, err = f.NewRevertUpgrade(curl) 160 c.Assert(err, gc.ErrorMatches, "NewRevertUpgrade fails") 161 _, err = f.NewResolvedUpgrade(curl) 162 c.Assert(err, gc.ErrorMatches, "NewResolvedUpgrade fails") 163 } 164 165 func (s *ResolverOpFactorySuite) TestCommitError(c *gc.C) { 166 f := resolver.NewResolverOpFactory(s.opFactory) 167 curl := charm.MustParseURL("cs:trusty/mysql") 168 s.opFactory.op.commit = func(operation.State) (*operation.State, error) { 169 return nil, errors.New("Commit fails") 170 } 171 op, err := f.NewUpgrade(curl) 172 c.Assert(err, jc.ErrorIsNil) 173 _, err = op.Commit(operation.State{}) 174 c.Assert(err, gc.ErrorMatches, "Commit fails") 175 // Local state should not have been updated. We use the same code 176 // internally for all operations, so it suffices to test just the 177 // upgrade case. 178 c.Assert(f.LocalState.CharmURL, gc.IsNil) 179 } 180 181 func (s *ResolverOpFactorySuite) TestActionsCommit(c *gc.C) { 182 f := resolver.NewResolverOpFactory(s.opFactory) 183 f.RemoteState.Actions = []string{"action 1", "action 2", "action 3"} 184 f.LocalState.CompletedActions = map[string]struct{}{} 185 op, err := f.NewAction("action 1") 186 c.Assert(err, jc.ErrorIsNil) 187 _, err = op.Commit(operation.State{}) 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(f.LocalState.CompletedActions, gc.DeepEquals, map[string]struct{}{ 190 "action 1": struct{}{}, 191 }) 192 } 193 194 func (s *ResolverOpFactorySuite) TestActionsTrimming(c *gc.C) { 195 f := resolver.NewResolverOpFactory(s.opFactory) 196 f.RemoteState.Actions = []string{"c", "d"} 197 f.LocalState.CompletedActions = map[string]struct{}{ 198 "a": struct{}{}, 199 "b": struct{}{}, 200 "c": struct{}{}, 201 } 202 op, err := f.NewAction("d") 203 c.Assert(err, jc.ErrorIsNil) 204 _, err = op.Commit(operation.State{}) 205 c.Assert(err, jc.ErrorIsNil) 206 c.Assert(f.LocalState.CompletedActions, gc.DeepEquals, map[string]struct{}{ 207 "c": struct{}{}, 208 "d": struct{}{}, 209 }) 210 }