package cache import ( "testing" "k8s.io/kubernetes/pkg/watch" ) type cacheable struct { key string value interface{} } func keyFunc(obj interface{}) (string, error) { return obj.(cacheable).key, nil } func TestEventQueue_basic(t *testing.T) { q := NewEventQueue(keyFunc) const amount = 500 go func() { for i := 0; i < amount; i++ { q.Add(cacheable{string([]rune{'a', rune(i)}), i + 1}) } }() go func() { for u := uint(0); u < amount; u++ { q.Add(cacheable{string([]rune{'b', rune(u)}), u + 1}) } }() lastInt := int(0) lastUint := uint(0) for i := 0; i < amount*2; i++ { _, obj, _ := q.Pop() value := obj.(cacheable).value switch v := value.(type) { case int: if v <= lastInt { t.Errorf("got %v (int) out of order, last was %v", v, lastInt) } lastInt = v case uint: if v <= lastUint { t.Errorf("got %v (uint) out of order, last was %v", v, lastUint) } else { lastUint = v } default: t.Fatalf("unexpected type %#v", obj) } } } func TestEventQueue_initialEventIsDelete(t *testing.T) { q := NewEventQueue(keyFunc) q.Replace([]interface{}{ cacheable{"foo", 2}, }, "1") q.Delete(cacheable{key: "foo"}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 2 { t.Fatalf("expected %v, got %v", 2, thing) } if event != watch.Deleted { t.Fatalf("expected %s, got %s", watch.Added, event) } } func TestEventQueue_compressAddDelete(t *testing.T) { q := NewEventQueue(keyFunc) q.Add(cacheable{"foo", 10}) q.Delete(cacheable{key: "foo"}) q.Add(cacheable{"zab", 30}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 30 { t.Fatalf("expected %v, got %v", 30, value) } if event != watch.Added { t.Fatalf("expected %s, got %s", watch.Added, event) } } func TestEventQueue_compressAddUpdate(t *testing.T) { q := NewEventQueue(keyFunc) q.Add(cacheable{"foo", 10}) q.Update(cacheable{"foo", 11}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 11 { t.Fatalf("expected %v, got %v", 11, value) } if event != watch.Added { t.Fatalf("expected %s, got %s", watch.Added, event) } } func TestEventQueue_compressTwoUpdates(t *testing.T) { q := NewEventQueue(keyFunc) q.Replace([]interface{}{ cacheable{"foo", 2}, }, "1") q.Update(cacheable{"foo", 3}) q.Update(cacheable{"foo", 4}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 4 { t.Fatalf("expected %v, got %v", 4, value) } if event != watch.Modified { t.Fatalf("expected %s, got %s", watch.Modified, event) } } func TestEventQueue_compressUpdateDelete(t *testing.T) { q := NewEventQueue(keyFunc) q.Replace([]interface{}{ cacheable{"foo", 2}, }, "1") q.Update(cacheable{"foo", 3}) q.Delete(cacheable{key: "foo"}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 3 { t.Fatalf("expected %v, got %v", 3, value) } if event != watch.Deleted { t.Fatalf("expected %s, got %s", watch.Deleted, event) } } func TestEventQueue_modifyEventsFromReplace(t *testing.T) { q := NewEventQueue(keyFunc) q.Replace([]interface{}{ cacheable{"foo", 2}, }, "1") q.Update(cacheable{"foo", 2}) event, thing, _ := q.Pop() value := thing.(cacheable).value if value != 2 { t.Fatalf("expected %v, got %v", 2, value) } if event != watch.Modified { t.Fatalf("expected %s, got %s", watch.Modified, event) } } func TestEventQueue_ListConsumed(t *testing.T) { q := NewEventQueue(keyFunc) if !q.ListConsumed() { t.Fatalf("expected ListConsumed to be true after queue creation") } q.Replace([]interface{}{}, "1") if !q.ListConsumed() { t.Fatalf("expected ListConsumed to be true after Replace() without items") } items := []interface{}{ cacheable{"foo", 2}, } q.Replace(items, "1") if q.ListConsumed() { t.Fatalf("expected ListConsumed to be false after Replace() with items") } // Delete() only results in the removal of a queued item if it is // of event type watch.Add. Since items added by Replace() are of // type watch.Modified, calling Delete() on those items will // change the event type but not remove them from the queue. q.Delete(items[0]) if q.ListConsumed() { t.Fatalf("expected ListConsumed to be false after Delete()") } q.Pop() if !q.ListConsumed() { t.Fatalf("expected ListConsumed to be true after queued items read") } }