k8s.io/kubernetes@v1.29.3/pkg/scheduler/internal/heap/heap_test.go (about)

     1  /*
     2  Copyright 2018 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, error) {
    27  	return obj.(testHeapObject).name, nil
    28  }
    29  
    30  type testHeapObject struct {
    31  	name string
    32  	val  interface{}
    33  }
    34  
    35  type testMetricRecorder int
    36  
    37  func (tmr *testMetricRecorder) Inc() {
    38  	if tmr != nil {
    39  		*tmr++
    40  	}
    41  }
    42  
    43  func (tmr *testMetricRecorder) Dec() {
    44  	if tmr != nil {
    45  		*tmr--
    46  	}
    47  }
    48  
    49  func (tmr *testMetricRecorder) Clear() {
    50  	if tmr != nil {
    51  		*tmr = 0
    52  	}
    53  }
    54  
    55  func mkHeapObj(name string, val interface{}) testHeapObject {
    56  	return testHeapObject{name: name, val: val}
    57  }
    58  
    59  func compareInts(val1 interface{}, val2 interface{}) bool {
    60  	first := val1.(testHeapObject).val.(int)
    61  	second := val2.(testHeapObject).val.(int)
    62  	return first < second
    63  }
    64  
    65  // TestHeapBasic tests Heap invariant
    66  func TestHeapBasic(t *testing.T) {
    67  	h := New(testHeapObjectKeyFunc, compareInts)
    68  	const amount = 500
    69  	var i int
    70  
    71  	// empty queue
    72  	if item := h.Peek(); item != nil {
    73  		t.Errorf("expected nil object but got %v", item)
    74  	}
    75  
    76  	for i = amount; i > 0; i-- {
    77  		h.Add(mkHeapObj(string([]rune{'a', rune(i)}), i))
    78  		// Retrieve head without removing it
    79  		head := h.Peek()
    80  		if e, a := i, head.(testHeapObject).val; a != e {
    81  			t.Errorf("expected %d, got %d", e, a)
    82  		}
    83  	}
    84  
    85  	// Make sure that the numbers are popped in ascending order.
    86  	prevNum := 0
    87  	for i := 0; i < amount; i++ {
    88  		obj, err := h.Pop()
    89  		num := obj.(testHeapObject).val.(int)
    90  		// All the items must be sorted.
    91  		if err != nil || prevNum > num {
    92  			t.Errorf("got %v out of order, last was %v", obj, prevNum)
    93  		}
    94  		prevNum = num
    95  	}
    96  }
    97  
    98  // Tests Heap.Add and ensures that heap invariant is preserved after adding items.
    99  func TestHeap_Add(t *testing.T) {
   100  	h := New(testHeapObjectKeyFunc, compareInts)
   101  	h.Add(mkHeapObj("foo", 10))
   102  	h.Add(mkHeapObj("bar", 1))
   103  	h.Add(mkHeapObj("baz", 11))
   104  	h.Add(mkHeapObj("zab", 30))
   105  	h.Add(mkHeapObj("foo", 13)) // This updates "foo".
   106  
   107  	item, err := h.Pop()
   108  	if e, a := 1, item.(testHeapObject).val; err != nil || a != e {
   109  		t.Fatalf("expected %d, got %d", e, a)
   110  	}
   111  	item, err = h.Pop()
   112  	if e, a := 11, item.(testHeapObject).val; err != nil || a != e {
   113  		t.Fatalf("expected %d, got %d", e, a)
   114  	}
   115  	h.Delete(mkHeapObj("baz", 11)) // Nothing is deleted.
   116  	h.Add(mkHeapObj("foo", 14))    // foo is updated.
   117  	item, err = h.Pop()
   118  	if e, a := 14, item.(testHeapObject).val; err != nil || a != e {
   119  		t.Fatalf("expected %d, got %d", e, a)
   120  	}
   121  	item, err = h.Pop()
   122  	if e, a := 30, item.(testHeapObject).val; err != nil || a != e {
   123  		t.Fatalf("expected %d, got %d", e, a)
   124  	}
   125  }
   126  
   127  // TestHeap_Delete tests Heap.Delete and ensures that heap invariant is
   128  // preserved after deleting items.
   129  func TestHeap_Delete(t *testing.T) {
   130  	h := New(testHeapObjectKeyFunc, compareInts)
   131  	h.Add(mkHeapObj("foo", 10))
   132  	h.Add(mkHeapObj("bar", 1))
   133  	h.Add(mkHeapObj("bal", 31))
   134  	h.Add(mkHeapObj("baz", 11))
   135  
   136  	// Delete head. Delete should work with "key" and doesn't care about the value.
   137  	if err := h.Delete(mkHeapObj("bar", 200)); err != nil {
   138  		t.Fatalf("Failed to delete head.")
   139  	}
   140  	item, err := h.Pop()
   141  	if e, a := 10, item.(testHeapObject).val; err != nil || a != e {
   142  		t.Fatalf("expected %d, got %d", e, a)
   143  	}
   144  	h.Add(mkHeapObj("zab", 30))
   145  	h.Add(mkHeapObj("faz", 30))
   146  	len := h.data.Len()
   147  	// Delete non-existing item.
   148  	if err = h.Delete(mkHeapObj("non-existent", 10)); err == nil || len != h.data.Len() {
   149  		t.Fatalf("Didn't expect any item removal")
   150  	}
   151  	// Delete tail.
   152  	if err = h.Delete(mkHeapObj("bal", 31)); err != nil {
   153  		t.Fatalf("Failed to delete tail.")
   154  	}
   155  	// Delete one of the items with value 30.
   156  	if err = h.Delete(mkHeapObj("zab", 30)); err != nil {
   157  		t.Fatalf("Failed to delete item.")
   158  	}
   159  	item, err = h.Pop()
   160  	if e, a := 11, item.(testHeapObject).val; err != nil || a != e {
   161  		t.Fatalf("expected %d, got %d", e, a)
   162  	}
   163  	item, err = h.Pop()
   164  	if e, a := 30, item.(testHeapObject).val; err != nil || a != e {
   165  		t.Fatalf("expected %d, got %d", e, a)
   166  	}
   167  	if h.data.Len() != 0 {
   168  		t.Fatalf("expected an empty heap.")
   169  	}
   170  }
   171  
   172  // TestHeap_Update tests Heap.Update and ensures that heap invariant is
   173  // preserved after adding items.
   174  func TestHeap_Update(t *testing.T) {
   175  	h := New(testHeapObjectKeyFunc, compareInts)
   176  	h.Add(mkHeapObj("foo", 10))
   177  	h.Add(mkHeapObj("bar", 1))
   178  	h.Add(mkHeapObj("bal", 31))
   179  	h.Add(mkHeapObj("baz", 11))
   180  
   181  	// Update an item to a value that should push it to the head.
   182  	h.Update(mkHeapObj("baz", 0))
   183  	if h.data.queue[0] != "baz" || h.data.items["baz"].index != 0 {
   184  		t.Fatalf("expected baz to be at the head")
   185  	}
   186  	item, err := h.Pop()
   187  	if e, a := 0, item.(testHeapObject).val; err != nil || a != e {
   188  		t.Fatalf("expected %d, got %d", e, a)
   189  	}
   190  	// Update bar to push it farther back in the queue.
   191  	h.Update(mkHeapObj("bar", 100))
   192  	if h.data.queue[0] != "foo" || h.data.items["foo"].index != 0 {
   193  		t.Fatalf("expected foo to be at the head")
   194  	}
   195  }
   196  
   197  // TestHeap_Get tests Heap.Get.
   198  func TestHeap_Get(t *testing.T) {
   199  	h := New(testHeapObjectKeyFunc, compareInts)
   200  	h.Add(mkHeapObj("foo", 10))
   201  	h.Add(mkHeapObj("bar", 1))
   202  	h.Add(mkHeapObj("bal", 31))
   203  	h.Add(mkHeapObj("baz", 11))
   204  
   205  	// Get works with the key.
   206  	obj, exists, err := h.Get(mkHeapObj("baz", 0))
   207  	if err != nil || exists == false || obj.(testHeapObject).val != 11 {
   208  		t.Fatalf("unexpected error in getting element")
   209  	}
   210  	// Get non-existing object.
   211  	_, exists, err = h.Get(mkHeapObj("non-existing", 0))
   212  	if err != nil || exists {
   213  		t.Fatalf("didn't expect to get any object")
   214  	}
   215  }
   216  
   217  // TestHeap_GetByKey tests Heap.GetByKey and is very similar to TestHeap_Get.
   218  func TestHeap_GetByKey(t *testing.T) {
   219  	h := New(testHeapObjectKeyFunc, compareInts)
   220  	h.Add(mkHeapObj("foo", 10))
   221  	h.Add(mkHeapObj("bar", 1))
   222  	h.Add(mkHeapObj("bal", 31))
   223  	h.Add(mkHeapObj("baz", 11))
   224  
   225  	obj, exists, err := h.GetByKey("baz")
   226  	if err != nil || !exists || obj.(testHeapObject).val != 11 {
   227  		t.Fatalf("unexpected error in getting element")
   228  	}
   229  	// Get non-existing object.
   230  	_, exists, err = h.GetByKey("non-existing")
   231  	if err != nil || exists {
   232  		t.Fatalf("didn't expect to get any object")
   233  	}
   234  }
   235  
   236  // TestHeap_List tests Heap.List function.
   237  func TestHeap_List(t *testing.T) {
   238  	h := New(testHeapObjectKeyFunc, compareInts)
   239  	list := h.List()
   240  	if len(list) != 0 {
   241  		t.Errorf("expected an empty list")
   242  	}
   243  
   244  	items := map[string]int{
   245  		"foo": 10,
   246  		"bar": 1,
   247  		"bal": 30,
   248  		"baz": 11,
   249  		"faz": 30,
   250  	}
   251  	for k, v := range items {
   252  		h.Add(mkHeapObj(k, v))
   253  	}
   254  	list = h.List()
   255  	if len(list) != len(items) {
   256  		t.Errorf("expected %d items, got %d", len(items), len(list))
   257  	}
   258  	for _, obj := range list {
   259  		heapObj := obj.(testHeapObject)
   260  		v, ok := items[heapObj.name]
   261  		if !ok || v != heapObj.val {
   262  			t.Errorf("unexpected item in the list: %v", heapObj)
   263  		}
   264  	}
   265  }
   266  
   267  func TestHeapWithRecorder(t *testing.T) {
   268  	metricRecorder := new(testMetricRecorder)
   269  	h := NewWithRecorder(testHeapObjectKeyFunc, compareInts, metricRecorder)
   270  	h.Add(mkHeapObj("foo", 10))
   271  	h.Add(mkHeapObj("bar", 1))
   272  	h.Add(mkHeapObj("baz", 100))
   273  	h.Add(mkHeapObj("qux", 11))
   274  
   275  	if *metricRecorder != 4 {
   276  		t.Errorf("expected count to be 4 but got %d", *metricRecorder)
   277  	}
   278  	if err := h.Delete(mkHeapObj("bar", 1)); err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	if *metricRecorder != 3 {
   282  		t.Errorf("expected count to be 3 but got %d", *metricRecorder)
   283  	}
   284  	if _, err := h.Pop(); err != nil {
   285  		t.Fatal(err)
   286  	}
   287  	if *metricRecorder != 2 {
   288  		t.Errorf("expected count to be 2 but got %d", *metricRecorder)
   289  	}
   290  
   291  	h.metricRecorder.Clear()
   292  	if *metricRecorder != 0 {
   293  		t.Errorf("expected count to be 0 but got %d", *metricRecorder)
   294  	}
   295  }