github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/context/leader_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package context_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 12 "github.com/juju/juju/core/leadership" 13 "github.com/juju/juju/worker/uniter/runner/context" 14 ) 15 16 type LeaderSuite struct { 17 testing.IsolationSuite 18 testing.Stub 19 accessor *StubLeadershipSettingsAccessor 20 tracker *StubTracker 21 context context.LeadershipContext 22 } 23 24 var _ = gc.Suite(&LeaderSuite{}) 25 26 func (s *LeaderSuite) SetUpTest(c *gc.C) { 27 s.IsolationSuite.SetUpTest(c) 28 s.accessor = &StubLeadershipSettingsAccessor{ 29 Stub: &s.Stub, 30 } 31 s.tracker = &StubTracker{ 32 Stub: &s.Stub, 33 serviceName: "led-service", 34 } 35 s.CheckCalls(c, []testing.StubCall{{ 36 FuncName: "ApplicationName", 37 }}, func() { 38 s.context = context.NewLeadershipContext(s.accessor, s.tracker) 39 }) 40 } 41 42 func (s *LeaderSuite) CheckCalls(c *gc.C, stubCalls []testing.StubCall, f func()) { 43 s.Stub = testing.Stub{} 44 f() 45 s.Stub.CheckCalls(c, stubCalls) 46 } 47 48 func (s *LeaderSuite) TestIsLeaderSuccess(c *gc.C) { 49 s.CheckCalls(c, []testing.StubCall{{ 50 FuncName: "ClaimLeader", 51 }}, func() { 52 // The first call succeeds... 53 s.tracker.results = []StubTicket{true} 54 leader, err := s.context.IsLeader() 55 c.Check(leader, jc.IsTrue) 56 c.Check(err, jc.ErrorIsNil) 57 }) 58 59 s.CheckCalls(c, []testing.StubCall{{ 60 FuncName: "ClaimLeader", 61 }}, func() { 62 // ...and so does the second. 63 s.tracker.results = []StubTicket{true} 64 leader, err := s.context.IsLeader() 65 c.Check(leader, jc.IsTrue) 66 c.Check(err, jc.ErrorIsNil) 67 }) 68 } 69 70 func (s *LeaderSuite) TestIsLeaderFailure(c *gc.C) { 71 s.CheckCalls(c, []testing.StubCall{{ 72 FuncName: "ClaimLeader", 73 }}, func() { 74 // The first call fails... 75 s.tracker.results = []StubTicket{false} 76 leader, err := s.context.IsLeader() 77 c.Check(leader, jc.IsFalse) 78 c.Check(err, jc.ErrorIsNil) 79 }) 80 81 s.CheckCalls(c, nil, func() { 82 // ...and the second doesn't even try. 83 leader, err := s.context.IsLeader() 84 c.Check(leader, jc.IsFalse) 85 c.Check(err, jc.ErrorIsNil) 86 }) 87 } 88 89 func (s *LeaderSuite) TestIsLeaderFailureAfterSuccess(c *gc.C) { 90 s.CheckCalls(c, []testing.StubCall{{ 91 FuncName: "ClaimLeader", 92 }}, func() { 93 // The first call succeeds... 94 s.tracker.results = []StubTicket{true} 95 leader, err := s.context.IsLeader() 96 c.Check(leader, jc.IsTrue) 97 c.Check(err, jc.ErrorIsNil) 98 }) 99 100 s.CheckCalls(c, []testing.StubCall{{ 101 FuncName: "ClaimLeader", 102 }}, func() { 103 // The second fails... 104 s.tracker.results = []StubTicket{false} 105 leader, err := s.context.IsLeader() 106 c.Check(leader, jc.IsFalse) 107 c.Check(err, jc.ErrorIsNil) 108 }) 109 110 s.CheckCalls(c, nil, func() { 111 // The third doesn't even try. 112 leader, err := s.context.IsLeader() 113 c.Check(leader, jc.IsFalse) 114 c.Check(err, jc.ErrorIsNil) 115 }) 116 } 117 118 func (s *LeaderSuite) TestLeaderSettingsSuccess(c *gc.C) { 119 s.CheckCalls(c, []testing.StubCall{{ 120 FuncName: "Read", 121 Args: []interface{}{"led-service"}, 122 }}, func() { 123 // The first call grabs the settings... 124 s.accessor.results = []map[string]string{{ 125 "some": "settings", 126 "of": "interest", 127 }} 128 settings, err := s.context.LeaderSettings() 129 c.Check(settings, jc.DeepEquals, map[string]string{ 130 "some": "settings", 131 "of": "interest", 132 }) 133 c.Check(err, jc.ErrorIsNil) 134 }) 135 136 s.CheckCalls(c, nil, func() { 137 // The second uses the cache. 138 settings, err := s.context.LeaderSettings() 139 c.Check(settings, jc.DeepEquals, map[string]string{ 140 "some": "settings", 141 "of": "interest", 142 }) 143 c.Check(err, jc.ErrorIsNil) 144 }) 145 } 146 147 func (s *LeaderSuite) TestLeaderSettingsCopyMap(c *gc.C) { 148 // Grab the settings to populate the cache... 149 s.accessor.results = []map[string]string{{ 150 "some": "settings", 151 "of": "interest", 152 }} 153 settings, err := s.context.LeaderSettings() 154 c.Check(err, gc.IsNil) 155 156 // Put some nonsense into the returned settings... 157 settings["bad"] = "news" 158 159 // Get the settings again and check they're as expected. 160 settings, err = s.context.LeaderSettings() 161 c.Check(settings, jc.DeepEquals, map[string]string{ 162 "some": "settings", 163 "of": "interest", 164 }) 165 c.Check(err, jc.ErrorIsNil) 166 } 167 168 func (s *LeaderSuite) TestLeaderSettingsError(c *gc.C) { 169 s.CheckCalls(c, []testing.StubCall{{ 170 FuncName: "Read", 171 Args: []interface{}{"led-service"}, 172 }}, func() { 173 s.accessor.results = []map[string]string{nil} 174 s.Stub.SetErrors(errors.New("blort")) 175 settings, err := s.context.LeaderSettings() 176 c.Check(settings, gc.IsNil) 177 c.Check(err, gc.ErrorMatches, "cannot read settings: blort") 178 }) 179 } 180 181 func (s *LeaderSuite) TestWriteLeaderSettingsSuccess(c *gc.C) { 182 s.CheckCalls(c, []testing.StubCall{{ 183 FuncName: "ClaimLeader", 184 }, { 185 FuncName: "Merge", 186 Args: []interface{}{"led-service", map[string]string{ 187 "some": "very", 188 "nice": "data", 189 }}, 190 }}, func() { 191 s.tracker.results = []StubTicket{true} 192 err := s.context.WriteLeaderSettings(map[string]string{ 193 "some": "very", 194 "nice": "data", 195 }) 196 c.Check(err, jc.ErrorIsNil) 197 }) 198 } 199 200 func (s *LeaderSuite) TestWriteLeaderSettingsMinion(c *gc.C) { 201 s.CheckCalls(c, []testing.StubCall{{ 202 FuncName: "ClaimLeader", 203 }}, func() { 204 // The first call fails... 205 s.tracker.results = []StubTicket{false} 206 err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"}) 207 c.Check(err, gc.ErrorMatches, "cannot write settings: not the leader") 208 }) 209 210 s.CheckCalls(c, nil, func() { 211 // The second doesn't even try. 212 err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"}) 213 c.Check(err, gc.ErrorMatches, "cannot write settings: not the leader") 214 }) 215 } 216 217 func (s *LeaderSuite) TestWriteLeaderSettingsError(c *gc.C) { 218 s.CheckCalls(c, []testing.StubCall{{ 219 FuncName: "ClaimLeader", 220 }, { 221 FuncName: "Merge", 222 Args: []interface{}{"led-service", map[string]string{ 223 "some": "very", 224 "nice": "data", 225 }}, 226 }}, func() { 227 s.tracker.results = []StubTicket{true} 228 s.Stub.SetErrors(errors.New("glurk")) 229 err := s.context.WriteLeaderSettings(map[string]string{ 230 "some": "very", 231 "nice": "data", 232 }) 233 c.Check(err, gc.ErrorMatches, "cannot write settings: glurk") 234 }) 235 } 236 237 func (s *LeaderSuite) TestWriteLeaderSettingsClearsCache(c *gc.C) { 238 s.CheckCalls(c, []testing.StubCall{{ 239 FuncName: "Read", 240 Args: []interface{}{"led-service"}, 241 }}, func() { 242 // Start off by populating the cache... 243 s.accessor.results = []map[string]string{{ 244 "some": "settings", 245 "of": "interest", 246 }} 247 _, err := s.context.LeaderSettings() 248 c.Check(err, gc.IsNil) 249 }) 250 251 s.CheckCalls(c, []testing.StubCall{{ 252 FuncName: "ClaimLeader", 253 }, { 254 FuncName: "Merge", 255 Args: []interface{}{"led-service", map[string]string{ 256 "some": "very", 257 "nice": "data", 258 }}, 259 }}, func() { 260 // Write new data to the controller... 261 s.tracker.results = []StubTicket{true} 262 err := s.context.WriteLeaderSettings(map[string]string{ 263 "some": "very", 264 "nice": "data", 265 }) 266 c.Check(err, jc.ErrorIsNil) 267 }) 268 269 s.CheckCalls(c, []testing.StubCall{{ 270 FuncName: "Read", 271 Args: []interface{}{"led-service"}, 272 }}, func() { 273 s.accessor.results = []map[string]string{{ 274 "totally": "different", 275 "server": "decides", 276 }} 277 settings, err := s.context.LeaderSettings() 278 c.Check(err, gc.IsNil) 279 c.Check(settings, jc.DeepEquals, map[string]string{ 280 "totally": "different", 281 "server": "decides", 282 }) 283 c.Check(err, jc.ErrorIsNil) 284 }) 285 } 286 287 type StubLeadershipSettingsAccessor struct { 288 *testing.Stub 289 results []map[string]string 290 } 291 292 func (stub *StubLeadershipSettingsAccessor) Read(serviceName string) (result map[string]string, _ error) { 293 stub.MethodCall(stub, "Read", serviceName) 294 result, stub.results = stub.results[0], stub.results[1:] 295 return result, stub.NextErr() 296 } 297 298 func (stub *StubLeadershipSettingsAccessor) Merge(serviceName string, settings map[string]string) error { 299 stub.MethodCall(stub, "Merge", serviceName, settings) 300 return stub.NextErr() 301 } 302 303 type StubTracker struct { 304 leadership.Tracker 305 *testing.Stub 306 serviceName string 307 results []StubTicket 308 } 309 310 func (stub *StubTracker) ApplicationName() string { 311 stub.MethodCall(stub, "ApplicationName") 312 return stub.serviceName 313 } 314 315 func (stub *StubTracker) ClaimLeader() (result leadership.Ticket) { 316 stub.MethodCall(stub, "ClaimLeader") 317 result, stub.results = stub.results[0], stub.results[1:] 318 return result 319 } 320 321 type StubTicket bool 322 323 func (ticket StubTicket) Wait() bool { 324 return bool(ticket) 325 } 326 327 func (ticket StubTicket) Ready() <-chan struct{} { 328 return alwaysReady 329 } 330 331 var alwaysReady = make(chan struct{}) 332 333 func init() { 334 close(alwaysReady) 335 }