| 292 | } |
| 293 | |
| 294 | func TestUpdate(t *testing.T) { |
| 295 | // This test is going to exercise the various paths that result in a |
| 296 | // call to update. |
| 297 | |
| 298 | // source simulates an apiserver object endpoint. |
| 299 | source := fcache.NewFakeControllerSource() |
| 300 | |
| 301 | const ( |
| 302 | FROM = "from" |
| 303 | TO = "to" |
| 304 | ) |
| 305 | |
| 306 | // These are the transitions we expect to see; because this is |
| 307 | // asynchronous, there are a lot of valid possibilities. |
| 308 | type pair struct{ from, to string } |
| 309 | allowedTransitions := map[pair]bool{ |
| 310 | {FROM, TO}: true, |
| 311 | |
| 312 | // Because a resync can happen when we've already observed one |
| 313 | // of the above but before the item is deleted. |
| 314 | {TO, TO}: true, |
| 315 | // Because a resync could happen before we observe an update. |
| 316 | {FROM, FROM}: true, |
| 317 | } |
| 318 | |
| 319 | pod := func(name, check string, final bool) *v1.Pod { |
| 320 | p := &v1.Pod{ |
| 321 | ObjectMeta: metav1.ObjectMeta{ |
| 322 | Name: name, |
| 323 | Labels: map[string]string{"check": check}, |
| 324 | }, |
| 325 | } |
| 326 | if final { |
| 327 | p.Labels["final"] = "true" |
| 328 | } |
| 329 | return p |
| 330 | } |
| 331 | deletePod := func(p *v1.Pod) bool { |
| 332 | return p.Labels["final"] == "true" |
| 333 | } |
| 334 | |
| 335 | tests := []func(string){ |
| 336 | func(name string) { |
| 337 | name = "a-" + name |
| 338 | source.Add(pod(name, FROM, false)) |
| 339 | source.Modify(pod(name, TO, true)) |
| 340 | }, |
| 341 | } |
| 342 | |
| 343 | const threads = 3 |
| 344 | |
| 345 | var testDoneWG sync.WaitGroup |
| 346 | testDoneWG.Add(threads * len(tests)) |
| 347 | |
| 348 | // Make a controller that deletes things once it observes an update. |
| 349 | // It calls Done() on the wait group on deletions so we can tell when |
| 350 | // everything we've added has been deleted. |
| 351 | watchCh := make(chan struct{}) |