github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 applicationName: "led-application", 34 } 35 s.CheckCalls(c, []testing.StubCall{{ 36 FuncName: "ApplicationName", 37 }}, func() { 38 s.context = context.NewLeadershipContext(s.accessor, s.tracker, "u/0") 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-application"}, 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-application"}, 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-application", "u/0", 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 // We are not the leader. 205 s.tracker.results = []StubTicket{false} 206 err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"}) 207 // No error, no call to Merge. 208 c.Check(err, jc.ErrorIsNil) 209 }) 210 211 s.CheckCalls(c, nil, func() { 212 // ctx.isMinion is now true. No call to claim leader. 213 err := s.context.WriteLeaderSettings(map[string]string{"blah": "blah"}) 214 c.Check(err, jc.ErrorIsNil) 215 }) 216 } 217 218 func (s *LeaderSuite) TestWriteLeaderSettingsError(c *gc.C) { 219 s.CheckCalls(c, []testing.StubCall{{ 220 FuncName: "ClaimLeader", 221 }, { 222 FuncName: "Merge", 223 Args: []interface{}{"led-application", "u/0", map[string]string{ 224 "some": "very", 225 "nice": "data", 226 }}, 227 }}, func() { 228 s.tracker.results = []StubTicket{true} 229 s.Stub.SetErrors(errors.New("glurk")) 230 err := s.context.WriteLeaderSettings(map[string]string{ 231 "some": "very", 232 "nice": "data", 233 }) 234 c.Check(err, gc.ErrorMatches, "cannot write settings: glurk") 235 }) 236 } 237 238 func (s *LeaderSuite) TestWriteLeaderSettingsClearsCache(c *gc.C) { 239 s.CheckCalls(c, []testing.StubCall{{ 240 FuncName: "Read", 241 Args: []interface{}{"led-application"}, 242 }}, func() { 243 // Start off by populating the cache... 244 s.accessor.results = []map[string]string{{ 245 "some": "settings", 246 "of": "interest", 247 }} 248 _, err := s.context.LeaderSettings() 249 c.Check(err, gc.IsNil) 250 }) 251 252 s.CheckCalls(c, []testing.StubCall{{ 253 FuncName: "ClaimLeader", 254 }, { 255 FuncName: "Merge", 256 Args: []interface{}{"led-application", "u/0", map[string]string{ 257 "some": "very", 258 "nice": "data", 259 }}, 260 }}, func() { 261 // Write new data to the controller... 262 s.tracker.results = []StubTicket{true} 263 err := s.context.WriteLeaderSettings(map[string]string{ 264 "some": "very", 265 "nice": "data", 266 }) 267 c.Check(err, jc.ErrorIsNil) 268 }) 269 270 s.CheckCalls(c, []testing.StubCall{{ 271 FuncName: "Read", 272 Args: []interface{}{"led-application"}, 273 }}, func() { 274 s.accessor.results = []map[string]string{{ 275 "totally": "different", 276 "server": "decides", 277 }} 278 settings, err := s.context.LeaderSettings() 279 c.Check(err, gc.IsNil) 280 c.Check(settings, jc.DeepEquals, map[string]string{ 281 "totally": "different", 282 "server": "decides", 283 }) 284 c.Check(err, jc.ErrorIsNil) 285 }) 286 } 287 288 type StubLeadershipSettingsAccessor struct { 289 *testing.Stub 290 results []map[string]string 291 } 292 293 func (stub *StubLeadershipSettingsAccessor) Read(applicationName string) (result map[string]string, _ error) { 294 stub.MethodCall(stub, "Read", applicationName) 295 result, stub.results = stub.results[0], stub.results[1:] 296 return result, stub.NextErr() 297 } 298 299 func (stub *StubLeadershipSettingsAccessor) Merge(applicationName, unitName string, settings map[string]string) error { 300 stub.MethodCall(stub, "Merge", applicationName, unitName, settings) 301 return stub.NextErr() 302 } 303 304 type StubTracker struct { 305 leadership.Tracker 306 *testing.Stub 307 applicationName string 308 results []StubTicket 309 } 310 311 func (stub *StubTracker) ApplicationName() string { 312 stub.MethodCall(stub, "ApplicationName") 313 return stub.applicationName 314 } 315 316 func (stub *StubTracker) ClaimLeader() (result leadership.Ticket) { 317 stub.MethodCall(stub, "ClaimLeader") 318 result, stub.results = stub.results[0], stub.results[1:] 319 return result 320 } 321 322 type StubTicket bool 323 324 func (ticket StubTicket) Wait() bool { 325 return bool(ticket) 326 } 327 328 func (ticket StubTicket) Ready() <-chan struct{} { 329 return alwaysReady 330 } 331 332 var alwaysReady = make(chan struct{}) 333 334 func init() { 335 close(alwaysReady) 336 }