sigs.k8s.io/kueue@v0.6.2/pkg/util/heap/heap_test.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // This file was copied from client-go/tools/cache/heap.go and modified 18 // for our non thread-safe heap 19 20 package heap 21 22 import ( 23 "testing" 24 ) 25 26 func testHeapObjectKeyFunc(obj interface{}) string { 27 return obj.(testHeapObject).name 28 } 29 30 type testHeapObject struct { 31 name string 32 val interface{} 33 } 34 35 func mkHeapObj(name string, val interface{}) testHeapObject { 36 return testHeapObject{name: name, val: val} 37 } 38 39 func compareInts(val1 interface{}, val2 interface{}) bool { 40 first := val1.(testHeapObject).val.(int) 41 second := val2.(testHeapObject).val.(int) 42 return first < second 43 } 44 45 // TestHeapBasic tests Heap invariant 46 func TestHeapBasic(t *testing.T) { 47 h := New(testHeapObjectKeyFunc, compareInts) 48 const amount = 500 49 var i int 50 51 for i = amount; i > 0; i-- { 52 h.PushOrUpdate(mkHeapObj(string([]rune{'a', rune(i)}), i)) 53 } 54 55 // Make sure that the numbers are popped in ascending order. 56 prevNum := 0 57 for i := 0; i < amount; i++ { 58 obj := h.Pop() 59 num := obj.(testHeapObject).val.(int) 60 // All the items must be sorted. 61 if prevNum > num { 62 t.Errorf("got %v out of order, last was %v", obj, prevNum) 63 } 64 prevNum = num 65 } 66 } 67 68 // Tests Heap.PushOrUpdate and ensures that heap invariant is preserved after adding items. 69 func TestHeap_Add(t *testing.T) { 70 h := New(testHeapObjectKeyFunc, compareInts) 71 h.PushOrUpdate(mkHeapObj("foo", 10)) 72 h.PushOrUpdate(mkHeapObj("bar", 1)) 73 h.PushOrUpdate(mkHeapObj("baz", 11)) 74 h.PushOrUpdate(mkHeapObj("zab", 30)) 75 h.PushOrUpdate(mkHeapObj("foo", 13)) // This updates "foo". 76 77 item := h.Pop() 78 if e, a := 1, item.(testHeapObject).val; a != e { 79 t.Fatalf("expected %d, got %d", e, a) 80 } 81 item = h.Pop() 82 if e, a := 11, item.(testHeapObject).val; a != e { 83 t.Fatalf("expected %d, got %d", e, a) 84 } 85 h.Delete("baz") // Nothing is deleted. 86 h.PushOrUpdate(mkHeapObj("foo", 14)) // foo is updated. 87 item = h.Pop() 88 if e, a := 14, item.(testHeapObject).val; a != e { 89 t.Fatalf("expected %d, got %d", e, a) 90 } 91 item = h.Pop() 92 if e, a := 30, item.(testHeapObject).val; a != e { 93 t.Fatalf("expected %d, got %d", e, a) 94 } 95 } 96 97 // TestHeap_PushIfNotPresent tests Heap.PushIfNotPresent and ensures that heap 98 // invariant is preserved after adding items. 99 func TestHeap_PushIfNotPresent(t *testing.T) { 100 h := New(testHeapObjectKeyFunc, compareInts) 101 _ = h.PushIfNotPresent(mkHeapObj("foo", 10)) 102 _ = h.PushIfNotPresent(mkHeapObj("bar", 1)) 103 _ = h.PushIfNotPresent(mkHeapObj("baz", 11)) 104 _ = h.PushIfNotPresent(mkHeapObj("zab", 30)) 105 _ = h.PushIfNotPresent(mkHeapObj("foo", 13)) // This is not added. 106 107 if len := len(h.data.items); len != 4 { 108 t.Errorf("unexpected number of items: %d", len) 109 } 110 if val := h.data.items["foo"].obj.(testHeapObject).val; val != 10 { 111 t.Errorf("unexpected value: %d", val) 112 } 113 item := h.Pop() 114 if e, a := 1, item.(testHeapObject).val; a != e { 115 t.Fatalf("expected %d, got %d", e, a) 116 } 117 item = h.Pop() 118 if e, a := 10, item.(testHeapObject).val; a != e { 119 t.Fatalf("expected %d, got %d", e, a) 120 } 121 // bar is already popped. Let's add another one. 122 _ = h.PushIfNotPresent(mkHeapObj("bar", 14)) 123 item = h.Pop() 124 if e, a := 11, item.(testHeapObject).val; a != e { 125 t.Fatalf("expected %d, got %d", e, a) 126 } 127 item = h.Pop() 128 if e, a := 14, item.(testHeapObject).val; a != e { 129 t.Fatalf("expected %d, got %d", e, a) 130 } 131 } 132 133 // TestHeap_PushOrUpdate tests Heap.PushOrUpdate and ensures that heap 134 // invariant is preserved after adding/updating items. 135 func TestHeap_PushOrUpdate(t *testing.T) { 136 h := New(testHeapObjectKeyFunc, compareInts) 137 h.PushOrUpdate(mkHeapObj("foo", 100)) 138 h.PushOrUpdate(mkHeapObj("baz", 20)) 139 h.PushOrUpdate(mkHeapObj("foo", 1)) // This behaves as update. 140 h.PushOrUpdate(mkHeapObj("zab", 8)) // This behaves as add. 141 142 if len := len(h.data.items); len != 3 { 143 t.Errorf("unexpected number of items: %d", len) 144 } 145 item := h.Pop() 146 if e, a := 1, item.(testHeapObject).val; a != e { 147 t.Fatalf("expected %d, got %d", e, a) 148 } 149 item = h.Pop() 150 if e, a := 8, item.(testHeapObject).val; a != e { 151 t.Fatalf("expected %d, got %d", e, a) 152 } 153 } 154 155 // TestHeap_Delete tests Heap.Delete and ensures that heap invariant is 156 // preserved after deleting items. 157 func TestHeap_Delete(t *testing.T) { 158 h := New(testHeapObjectKeyFunc, compareInts) 159 h.PushOrUpdate(mkHeapObj("foo", 10)) 160 h.PushOrUpdate(mkHeapObj("bar", 1)) 161 h.PushOrUpdate(mkHeapObj("bal", 31)) 162 h.PushOrUpdate(mkHeapObj("baz", 11)) 163 164 // Delete head. Delete should work with "key" and doesn't care about the value. 165 h.Delete("bar") 166 item := h.Pop() 167 if e, a := 10, item.(testHeapObject).val; a != e { 168 t.Fatalf("expected %d, got %d", e, a) 169 } 170 h.PushOrUpdate(mkHeapObj("zab", 30)) 171 h.PushOrUpdate(mkHeapObj("faz", 30)) 172 len := h.data.Len() 173 // Delete non-existing item. 174 if h.Delete("non-existent"); len != h.data.Len() { 175 t.Fatalf("Didn't expect any item removal") 176 } 177 // Delete tail. 178 h.Delete("bal") 179 // Delete one of the items with value 30. 180 h.Delete("zab") 181 item = h.Pop() 182 if e, a := 11, item.(testHeapObject).val; a != e { 183 t.Fatalf("expected %d, got %d", e, a) 184 } 185 item = h.Pop() 186 if e, a := 30, item.(testHeapObject).val; a != e { 187 t.Fatalf("expected %d, got %d", e, a) 188 } 189 if h.data.Len() != 0 { 190 t.Fatalf("expected an empty heap.") 191 } 192 } 193 194 // TestHeap_Update tests Heap.PushOrUpdate and ensures that heap invariant is 195 // preserved after adding items. 196 func TestHeap_Update(t *testing.T) { 197 h := New(testHeapObjectKeyFunc, compareInts) 198 h.PushOrUpdate(mkHeapObj("foo", 10)) 199 h.PushOrUpdate(mkHeapObj("bar", 1)) 200 h.PushOrUpdate(mkHeapObj("bal", 31)) 201 h.PushOrUpdate(mkHeapObj("baz", 11)) 202 203 // Update an item to a value that should push it to the head. 204 h.PushOrUpdate(mkHeapObj("baz", 0)) 205 if h.data.keys[0] != "baz" || h.data.items["baz"].index != 0 { 206 t.Fatalf("expected baz to be at the head") 207 } 208 item := h.Pop() 209 if e, a := 0, item.(testHeapObject).val; a != e { 210 t.Fatalf("expected %d, got %d", e, a) 211 } 212 // Update bar to push it farther back in the queue. 213 h.PushOrUpdate(mkHeapObj("bar", 100)) 214 if h.data.keys[0] != "foo" || h.data.items["foo"].index != 0 { 215 t.Fatalf("expected foo to be at the head") 216 } 217 } 218 219 // TestHeap_Get tests Heap.Get. 220 func TestHeap_Get(t *testing.T) { 221 h := New(testHeapObjectKeyFunc, compareInts) 222 h.PushOrUpdate(mkHeapObj("foo", 10)) 223 h.PushOrUpdate(mkHeapObj("bar", 1)) 224 h.PushOrUpdate(mkHeapObj("bal", 31)) 225 h.PushOrUpdate(mkHeapObj("baz", 11)) 226 227 // Get works with the key. 228 obj := h.Get(mkHeapObj("baz", 0)) 229 if obj == nil || obj.(testHeapObject).val != 11 { 230 t.Fatalf("unexpected error in getting element") 231 } 232 // Get non-existing object. 233 if obj = h.Get(mkHeapObj("non-existing", 0)); obj != nil { 234 t.Fatalf("didn't expect to get any object") 235 } 236 } 237 238 // TestHeap_GetByKey tests Heap.GetByKey and is very similar to TestHeap_Get. 239 func TestHeap_GetByKey(t *testing.T) { 240 h := New(testHeapObjectKeyFunc, compareInts) 241 h.PushOrUpdate(mkHeapObj("foo", 10)) 242 h.PushOrUpdate(mkHeapObj("bar", 1)) 243 h.PushOrUpdate(mkHeapObj("bal", 31)) 244 h.PushOrUpdate(mkHeapObj("baz", 11)) 245 246 obj := h.GetByKey("baz") 247 if obj == nil || obj.(testHeapObject).val != 11 { 248 t.Fatalf("unexpected error in getting element") 249 } 250 // Get non-existing object. 251 if obj = h.GetByKey("non-existing"); obj != nil { 252 t.Fatalf("didn't expect to get any object") 253 } 254 } 255 256 // TestHeap_List tests Heap.List function. 257 func TestHeap_List(t *testing.T) { 258 h := New(testHeapObjectKeyFunc, compareInts) 259 list := h.List() 260 if len(list) != 0 { 261 t.Errorf("expected an empty list") 262 } 263 264 items := map[string]int{ 265 "foo": 10, 266 "bar": 1, 267 "bal": 30, 268 "baz": 11, 269 "faz": 30, 270 } 271 for k, v := range items { 272 h.PushOrUpdate(mkHeapObj(k, v)) 273 } 274 list = h.List() 275 if len(list) != len(items) { 276 t.Errorf("expected %d items, got %d", len(items), len(list)) 277 } 278 for _, obj := range list { 279 heapObj := obj.(testHeapObject) 280 v, ok := items[heapObj.name] 281 if !ok || v != heapObj.val { 282 t.Errorf("unexpected item in the list: %v", heapObj) 283 } 284 } 285 }