Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 package uniter | 1 package uniter |
2 | 2 |
3 import ( | 3 import ( |
4 "fmt" | 4 "fmt" |
5 . "launchpad.net/gocheck" | 5 . "launchpad.net/gocheck" |
6 "launchpad.net/juju-core/charm" | 6 "launchpad.net/juju-core/charm" |
7 "launchpad.net/juju-core/juju/testing" | 7 "launchpad.net/juju-core/juju/testing" |
8 "launchpad.net/juju-core/state" | 8 "launchpad.net/juju-core/state" |
9 "launchpad.net/juju-core/worker" | 9 "launchpad.net/juju-core/worker" |
10 "launchpad.net/tomb" | |
10 "time" | 11 "time" |
11 ) | 12 ) |
12 | 13 |
13 type FilterSuite struct { | 14 type FilterSuite struct { |
14 testing.JujuConnSuite | 15 testing.JujuConnSuite |
15 wordpress *state.Service | 16 wordpress *state.Service |
16 unit *state.Unit | 17 unit *state.Unit |
17 mysqlcharm *state.Charm | 18 mysqlcharm *state.Charm |
19 wpcharm *state.Charm | |
18 } | 20 } |
19 | 21 |
20 var _ = Suite(&FilterSuite{}) | 22 var _ = Suite(&FilterSuite{}) |
21 | 23 |
22 func (s *FilterSuite) SetUpTest(c *C) { | 24 func (s *FilterSuite) SetUpTest(c *C) { |
23 s.JujuConnSuite.SetUpTest(c) | 25 s.JujuConnSuite.SetUpTest(c) |
24 var err error | 26 var err error |
25 » s.wordpress, err = s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress")) | 27 » s.wpcharm = s.AddTestingCharm(c, "wordpress") |
28 » s.wordpress, err = s.State.AddService("wordpress", s.wpcharm) | |
26 c.Assert(err, IsNil) | 29 c.Assert(err, IsNil) |
27 s.unit, err = s.wordpress.AddUnit() | 30 s.unit, err = s.wordpress.AddUnit() |
28 c.Assert(err, IsNil) | 31 c.Assert(err, IsNil) |
29 } | 32 } |
30 | 33 |
31 func (s *FilterSuite) TestUnitDeath(c *C) { | 34 func (s *FilterSuite) TestUnitDeath(c *C) { |
32 f, err := newFilter(s.State, s.unit.Name()) | 35 f, err := newFilter(s.State, s.unit.Name()) |
33 c.Assert(err, IsNil) | 36 c.Assert(err, IsNil) |
34 defer f.Stop() | 37 defer f.Stop() |
35 assertNotClosed := func() { | 38 assertNotClosed := func() { |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 err = s.unit.ClearResolved() | 159 err = s.unit.ClearResolved() |
157 c.Assert(err, IsNil) | 160 c.Assert(err, IsNil) |
158 f.WantResolvedEvent() | 161 f.WantResolvedEvent() |
159 err = s.unit.SetResolved(state.ResolvedNoHooks) | 162 err = s.unit.SetResolved(state.ResolvedNoHooks) |
160 c.Assert(err, IsNil) | 163 c.Assert(err, IsNil) |
161 f.WantResolvedEvent() | 164 f.WantResolvedEvent() |
162 assertChange(state.ResolvedNoHooks) | 165 assertChange(state.ResolvedNoHooks) |
163 assertNoChange() | 166 assertNoChange() |
164 } | 167 } |
165 | 168 |
166 func (s *FilterSuite) TestCharmEvents(c *C) { | 169 func (s *FilterSuite) TestCharmUpgradeEvents(c *C) { |
167 oldCharm := s.AddTestingCharm(c, "upgrade1") | 170 oldCharm := s.AddTestingCharm(c, "upgrade1") |
168 svc, err := s.State.AddService("upgradetest", oldCharm) | 171 svc, err := s.State.AddService("upgradetest", oldCharm) |
169 c.Assert(err, IsNil) | 172 c.Assert(err, IsNil) |
170 unit, err := svc.AddUnit() | 173 unit, err := svc.AddUnit() |
171 c.Assert(err, IsNil) | 174 c.Assert(err, IsNil) |
172 | 175 |
173 f, err := newFilter(s.State, unit.Name()) | 176 f, err := newFilter(s.State, unit.Name()) |
174 c.Assert(err, IsNil) | 177 c.Assert(err, IsNil) |
175 defer f.Stop() | 178 defer f.Stop() |
176 | 179 |
177 // No initial event is sent. | 180 // No initial event is sent. |
178 assertNoChange := func() { | 181 assertNoChange := func() { |
179 s.State.StartSync() | 182 s.State.StartSync() |
180 select { | 183 select { |
181 case sch := <-f.UpgradeEvents(): | 184 case sch := <-f.UpgradeEvents(): |
182 c.Fatalf("unexpected %#v", sch) | 185 c.Fatalf("unexpected %#v", sch) |
183 case <-time.After(50 * time.Millisecond): | 186 case <-time.After(50 * time.Millisecond): |
184 } | 187 } |
185 } | 188 } |
186 assertNoChange() | 189 assertNoChange() |
187 | 190 |
188 » // Request an event relative to the existing state; nothing. | 191 » // Setting a charm generates no new events if it already matches. |
192 » err = f.SetCharm(oldCharm.URL()) | |
193 » c.Assert(err, IsNil) | |
194 » assertNoChange() | |
195 | |
196 » // Explicitly request an event relative to the existing state; nothing. | |
189 f.WantUpgradeEvent(false) | 197 f.WantUpgradeEvent(false) |
190 // TODO: is this needed here? | |
TheMue
2013/03/01 10:31:07
See above.
dimitern
2013/03/01 16:42:37
Gone now.
| |
191 f.SetCharm(oldCharm.URL()) | |
192 assertNoChange() | 198 assertNoChange() |
193 | 199 |
194 // Change the service in an irrelevant way; no events. | 200 // Change the service in an irrelevant way; no events. |
195 err = svc.SetExposed() | 201 err = svc.SetExposed() |
196 c.Assert(err, IsNil) | 202 c.Assert(err, IsNil) |
197 assertNoChange() | 203 assertNoChange() |
198 | 204 |
199 // Change the service's charm; new event received. | 205 // Change the service's charm; new event received. |
200 newCharm := s.AddTestingCharm(c, "upgrade2") | 206 newCharm := s.AddTestingCharm(c, "upgrade2") |
201 err = svc.SetCharm(newCharm, false) | 207 err = svc.SetCharm(newCharm, false) |
202 c.Assert(err, IsNil) | 208 c.Assert(err, IsNil) |
203 assertChange := func(url *charm.URL) { | 209 assertChange := func(url *charm.URL) { |
204 s.State.Sync() | 210 s.State.Sync() |
205 select { | 211 select { |
206 case upgradeCharm := <-f.UpgradeEvents(): | 212 case upgradeCharm := <-f.UpgradeEvents(): |
207 c.Assert(upgradeCharm, DeepEquals, url) | 213 c.Assert(upgradeCharm, DeepEquals, url) |
208 case <-time.After(50 * time.Millisecond): | 214 case <-time.After(50 * time.Millisecond): |
209 c.Fatalf("timed out") | 215 c.Fatalf("timed out") |
210 } | 216 } |
211 } | 217 } |
212 assertChange(newCharm.URL()) | 218 assertChange(newCharm.URL()) |
213 assertNoChange() | 219 assertNoChange() |
214 | 220 |
215 » // Request a change relative to the original state, unforced; | 221 » // Request a new upgrade *unforced* upgrade event, we should see one. |
216 » // same event is sent. | |
217 f.WantUpgradeEvent(false) | 222 f.WantUpgradeEvent(false) |
218 // TODO: is this needed here? | |
219 f.SetCharm(oldCharm.URL()) | |
220 assertChange(newCharm.URL()) | 223 assertChange(newCharm.URL()) |
221 assertNoChange() | 224 assertNoChange() |
222 | 225 |
223 » // Request a forced change relative to the initial state; no change... | 226 » // Request only *forced* upgrade events; nothing. |
224 f.WantUpgradeEvent(true) | 227 f.WantUpgradeEvent(true) |
225 » // TODO: is this needed here? | 228 » assertNoChange() |
226 » f.SetCharm(oldCharm.URL()) | 229 |
227 » assertNoChange() | 230 » // But when we have a forced upgrade to the same URL, no new event. |
228 | |
229 » // ...and still no change when we have a forced upgrade to that state... | |
230 err = svc.SetCharm(oldCharm, true) | 231 err = svc.SetCharm(oldCharm, true) |
231 c.Assert(err, IsNil) | 232 c.Assert(err, IsNil) |
232 assertNoChange() | 233 assertNoChange() |
233 | 234 |
234 » // ...but a *forced* change to a different charm does generate an event. | 235 » // ...but a *forced* change to a different URL should generate an event. |
235 err = svc.SetCharm(newCharm, true) | 236 err = svc.SetCharm(newCharm, true) |
236 assertChange(newCharm.URL()) | 237 assertChange(newCharm.URL()) |
237 assertNoChange() | 238 assertNoChange() |
238 } | 239 } |
239 | 240 |
240 func (s *FilterSuite) TestConfigEvents(c *C) { | 241 func (s *FilterSuite) TestConfigEvents(c *C) { |
241 f, err := newFilter(s.State, s.unit.Name()) | 242 f, err := newFilter(s.State, s.unit.Name()) |
242 c.Assert(err, IsNil) | 243 c.Assert(err, IsNil) |
243 defer f.Stop() | 244 defer f.Stop() |
244 | 245 |
245 » // Initial event. | 246 » // Test no changes before the charm URL is set. |
247 » assertNoChange := func() { | |
248 » » s.State.StartSync() | |
249 » » select { | |
250 » » case <-f.ConfigEvents(): | |
251 » » » c.Fatalf("unexpected config event") | |
252 » » case <-time.After(50 * time.Millisecond): | |
253 » » } | |
254 » } | |
255 » assertNoChange() | |
256 | |
246 assertChange := func() { | 257 assertChange := func() { |
247 s.State.Sync() | 258 s.State.Sync() |
248 select { | 259 select { |
249 case _, ok := <-f.ConfigEvents(): | 260 case _, ok := <-f.ConfigEvents(): |
250 c.Assert(ok, Equals, true) | 261 c.Assert(ok, Equals, true) |
251 case <-time.After(50 * time.Millisecond): | 262 case <-time.After(50 * time.Millisecond): |
252 c.Fatalf("timed out") | 263 c.Fatalf("timed out") |
253 } | 264 } |
254 » } | 265 » » assertNoChange() |
266 » } | |
267 | |
268 » // Set the charm URL to trigger config events. | |
269 » err = f.SetCharm(s.wpcharm.URL()) | |
270 » c.Assert(err, IsNil) | |
255 assertChange() | 271 assertChange() |
256 » assertNoChange := func() { | 272 |
257 » » s.State.StartSync() | 273 » // Make sure the charm URL is set now. |
258 » » select { | 274 » s.unit.Refresh() |
259 » » case <-f.ConfigEvents(): | 275 » curl, ok := s.unit.CharmURL() |
260 » » » c.Fatalf("unexpected config event") | 276 » c.Assert(ok, Equals, true) |
261 » » case <-time.After(50 * time.Millisecond): | 277 » c.Assert(curl, DeepEquals, s.wpcharm.URL()) |
262 » » } | |
263 » } | |
264 » assertNoChange() | |
265 | 278 |
266 // Change the config; new event received. | 279 // Change the config; new event received. |
267 node, err := s.wordpress.Config() | 280 node, err := s.wordpress.Config() |
268 c.Assert(err, IsNil) | 281 c.Assert(err, IsNil) |
269 node.Set("skill-level", 9001) | 282 node.Set("skill-level", 9001) |
270 _, err = node.Write() | 283 _, err = node.Write() |
271 c.Assert(err, IsNil) | 284 c.Assert(err, IsNil) |
272 assertChange() | 285 assertChange() |
273 assertNoChange() | |
274 | 286 |
275 // Change the config a couple of times, then reset the events. | 287 // Change the config a couple of times, then reset the events. |
276 node.Set("title", "20,000 leagues in the cloud") | 288 node.Set("title", "20,000 leagues in the cloud") |
277 _, err = node.Write() | 289 _, err = node.Write() |
278 c.Assert(err, IsNil) | 290 c.Assert(err, IsNil) |
279 node.Set("outlook", "precipitous") | 291 node.Set("outlook", "precipitous") |
280 _, err = node.Write() | 292 _, err = node.Write() |
281 c.Assert(err, IsNil) | 293 c.Assert(err, IsNil) |
294 // We make sure the event has come into the filter before we tell it to discard any received. | |
282 s.State.Sync() | 295 s.State.Sync() |
283 f.DiscardConfigEvent() | 296 f.DiscardConfigEvent() |
284 assertNoChange() | 297 assertNoChange() |
285 | 298 |
286 // Check that a filter's initial event works with DiscardConfigEvent | 299 // Check that a filter's initial event works with DiscardConfigEvent |
287 // as expected. | 300 // as expected. |
288 f, err = newFilter(s.State, s.unit.Name()) | 301 f, err = newFilter(s.State, s.unit.Name()) |
289 c.Assert(err, IsNil) | 302 c.Assert(err, IsNil) |
290 defer f.Stop() | 303 defer f.Stop() |
304 s.State.Sync() | |
291 f.DiscardConfigEvent() | 305 f.DiscardConfigEvent() |
292 s.State.Sync() | |
293 assertNoChange() | 306 assertNoChange() |
294 | 307 |
295 // Further changes are still collapsed as appropriate. | 308 // Further changes are still collapsed as appropriate. |
296 node.Set("skill-level", 123) | 309 node.Set("skill-level", 123) |
297 _, err = node.Write() | 310 _, err = node.Write() |
298 c.Assert(err, IsNil) | 311 c.Assert(err, IsNil) |
299 node.Set("outlook", "expressive") | 312 node.Set("outlook", "expressive") |
300 _, err = node.Write() | 313 _, err = node.Write() |
301 c.Assert(err, IsNil) | 314 c.Assert(err, IsNil) |
302 assertChange() | 315 assertChange() |
303 » assertNoChange() | 316 } |
317 | |
318 func (s *FilterSuite) TestCharmErrorEvents(c *C) { | |
319 » f, err := newFilter(s.State, s.unit.Name()) | |
320 » c.Assert(err, IsNil) | |
321 » defer f.Stop() | |
322 | |
323 » assertNoChange := func() { | |
324 » » s.State.StartSync() | |
325 » » select { | |
326 » » case <-f.ConfigEvents(): | |
327 » » » c.Fatalf("unexpected config event") | |
328 » » case <-time.After(50 * time.Millisecond): | |
329 » » } | |
330 » } | |
331 » assertDead := func(f *filter) { | |
332 » » select { | |
333 » » case <-f.Dead(): | |
334 » » case <-time.After(50 * time.Millisecond): | |
335 » » » c.Fatalf("filter did not die") | |
336 » » } | |
337 » } | |
338 | |
339 » // Check setting an invalid charm URL does not send events. | |
340 » err = f.SetCharm(charm.MustParseURL("cs:missing/one-1")) | |
341 » c.Assert(err, Equals, tomb.ErrDying) | |
342 » assertNoChange() | |
343 » assertDead(f) | |
344 | |
345 » // Filter died after the error, so restart it. | |
346 » f, err = newFilter(s.State, s.unit.Name()) | |
347 » c.Assert(err, IsNil) | |
348 » defer f.Stop() | |
349 | |
350 » // Check with a nil charm URL, again no changes. | |
351 » err = f.SetCharm(nil) | |
352 » c.Assert(err, Equals, tomb.ErrDying) | |
353 » assertNoChange() | |
354 » assertDead(f) | |
304 } | 355 } |
305 | 356 |
306 func (s *FilterSuite) TestRelationsEvents(c *C) { | 357 func (s *FilterSuite) TestRelationsEvents(c *C) { |
307 f, err := newFilter(s.State, s.unit.Name()) | 358 f, err := newFilter(s.State, s.unit.Name()) |
308 c.Assert(err, IsNil) | 359 c.Assert(err, IsNil) |
309 defer f.Stop() | 360 defer f.Stop() |
310 | 361 |
311 assertNoChange := func() { | 362 assertNoChange := func() { |
312 s.State.Sync() | 363 s.State.Sync() |
313 select { | 364 select { |
314 case ids := <-f.RelationsEvents(): | 365 case ids := <-f.RelationsEvents(): |
315 c.Fatalf("unexpected relations event %#v", ids) | 366 c.Fatalf("unexpected relations event %#v", ids) |
316 case <-time.After(50 * time.Millisecond): | 367 case <-time.After(50 * time.Millisecond): |
317 } | 368 } |
318 } | 369 } |
319 assertNoChange() | 370 assertNoChange() |
320 | 371 |
321 // Add a couple of relations; check the event. | 372 // Add a couple of relations; check the event. |
322 rel0 := s.addRelation(c) | 373 rel0 := s.addRelation(c) |
323 rel1 := s.addRelation(c) | 374 rel1 := s.addRelation(c) |
324 assertChange := func(expect []int) { | 375 assertChange := func(expect []int) { |
325 s.State.Sync() | 376 s.State.Sync() |
326 select { | 377 select { |
327 case got := <-f.RelationsEvents(): | 378 case got := <-f.RelationsEvents(): |
328 c.Assert(got, DeepEquals, expect) | 379 c.Assert(got, DeepEquals, expect) |
329 case <-time.After(50 * time.Millisecond): | 380 case <-time.After(50 * time.Millisecond): |
330 c.Fatalf("timed out") | 381 c.Fatalf("timed out") |
331 } | 382 } |
383 assertNoChange() | |
332 } | 384 } |
333 assertChange([]int{0, 1}) | 385 assertChange([]int{0, 1}) |
334 assertNoChange() | |
335 | |
336 // TODO: remove if safe | |
fwereade
2013/03/01 11:59:56
We definitely need to test this behaviour, as we d
dimitern
2013/03/01 16:42:37
I'll do a separate test.
| |
337 // Request all relations events; no changes should happen | |
338 //f.WantAllRelationsEvents() | |
339 //assertChange([]int{0, 1}) | |
340 //assertNoChange() | |
341 | 386 |
342 // Add another relation, and change another's Life (by entering scope be fore | 387 // Add another relation, and change another's Life (by entering scope be fore |
343 // Destroy, thereby setting the relation to Dying); check event. | 388 // Destroy, thereby setting the relation to Dying); check event. |
344 s.addRelation(c) | 389 s.addRelation(c) |
345 ru0, err := rel0.Unit(s.unit) | 390 ru0, err := rel0.Unit(s.unit) |
346 c.Assert(err, IsNil) | 391 c.Assert(err, IsNil) |
347 err = ru0.EnterScope(nil) | 392 err = ru0.EnterScope(nil) |
348 c.Assert(err, IsNil) | 393 c.Assert(err, IsNil) |
349 err = rel0.Destroy() | 394 err = rel0.Destroy() |
350 c.Assert(err, IsNil) | 395 c.Assert(err, IsNil) |
351 assertChange([]int{0, 2}) | 396 assertChange([]int{0, 2}) |
352 assertNoChange() | |
353 | 397 |
354 // Remove a relation completely; check event. | 398 // Remove a relation completely; check event. |
355 err = rel1.Destroy() | 399 err = rel1.Destroy() |
356 c.Assert(err, IsNil) | 400 c.Assert(err, IsNil) |
357 assertChange([]int{1}) | 401 assertChange([]int{1}) |
358 assertNoChange() | |
359 | 402 |
360 // Start a new filter, check initial event. | 403 // Start a new filter, check initial event. |
361 f, err = newFilter(s.State, s.unit.Name()) | 404 f, err = newFilter(s.State, s.unit.Name()) |
362 c.Assert(err, IsNil) | 405 c.Assert(err, IsNil) |
363 defer f.Stop() | 406 defer f.Stop() |
364 assertChange([]int{0, 2}) | 407 assertChange([]int{0, 2}) |
365 » assertNoChange() | 408 |
409 » // Check setting the charm URL generates all new relation events. | |
410 » err = f.SetCharm(s.wpcharm.URL()) | |
411 » c.Assert(err, IsNil) | |
412 » assertChange([]int{0, 2}) | |
366 } | 413 } |
367 | 414 |
368 func (s *FilterSuite) addRelation(c *C) *state.Relation { | 415 func (s *FilterSuite) addRelation(c *C) *state.Relation { |
369 if s.mysqlcharm == nil { | 416 if s.mysqlcharm == nil { |
370 s.mysqlcharm = s.AddTestingCharm(c, "mysql") | 417 s.mysqlcharm = s.AddTestingCharm(c, "mysql") |
371 } | 418 } |
372 rels, err := s.wordpress.Relations() | 419 rels, err := s.wordpress.Relations() |
373 c.Assert(err, IsNil) | 420 c.Assert(err, IsNil) |
374 svcName := fmt.Sprintf("mysql%d", len(rels)) | 421 svcName := fmt.Sprintf("mysql%d", len(rels)) |
375 _, err = s.State.AddService(svcName, s.mysqlcharm) | 422 _, err = s.State.AddService(svcName, s.mysqlcharm) |
376 c.Assert(err, IsNil) | 423 c.Assert(err, IsNil) |
377 eps, err := s.State.InferEndpoints([]string{svcName, "wordpress"}) | 424 eps, err := s.State.InferEndpoints([]string{svcName, "wordpress"}) |
378 c.Assert(err, IsNil) | 425 c.Assert(err, IsNil) |
379 rel, err := s.State.AddRelation(eps...) | 426 rel, err := s.State.AddRelation(eps...) |
380 c.Assert(err, IsNil) | 427 c.Assert(err, IsNil) |
381 return rel | 428 return rel |
382 } | 429 } |
LEFT | RIGHT |