k8s.io/apiserver@v0.31.1/pkg/util/flowcontrol/fairqueuing/testing/eventclock/fake_event_clock_test.go (about) 1 /* 2 Copyright 2021 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 package eventclock 18 19 import ( 20 "math/rand" 21 "sync/atomic" 22 "testing" 23 "time" 24 25 "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/eventclock" 26 ) 27 28 type TestableEventClock interface { 29 eventclock.Interface 30 SetTime(time.Time) 31 Run(*time.Time) 32 } 33 34 func exerciseTestableEventClock(t *testing.T, ec TestableEventClock, fuzz time.Duration) { 35 exerciseSettablePassiveClock(t, ec) 36 var numDone int32 37 now := ec.Now() 38 strictable := true 39 const batchSize = 100 40 times := make(chan time.Time, batchSize+1) 41 try := func(abs, strict bool, d time.Duration) { 42 f := func(u time.Time) { 43 realD := ec.Since(now) 44 atomic.AddInt32(&numDone, 1) 45 times <- u 46 if realD < d || strict && strictable && realD > d+fuzz { 47 t.Errorf("Asked for %v, got %v", d, realD) 48 } 49 } 50 if abs { 51 ec.EventAfterTime(f, now.Add(d)) 52 } else { 53 ec.EventAfterDuration(f, d) 54 } 55 } 56 try(true, true, time.Minute) 57 for i := 0; i < batchSize; i++ { 58 d := time.Duration(rand.Intn(30)-3) * time.Second 59 try(i%2 == 0, d >= 0, d) 60 } 61 ec.Run(nil) 62 if numDone != batchSize+1 { 63 t.Errorf("Got only %v events", numDone) 64 } 65 lastTime := now.Add(-3 * time.Second) 66 for i := 0; i <= batchSize; i++ { 67 nextTime := <-times 68 if nextTime.Before(lastTime) { 69 t.Errorf("Got %s after %s", nextTime, lastTime) 70 } 71 } 72 endTime := ec.Now() 73 dx := endTime.Sub(now) 74 if dx > time.Minute+fuzz { 75 t.Errorf("Run started at %#+v, ended at %#+v, dx=%d", now, endTime, dx) 76 } 77 now = endTime 78 var shouldRun int32 79 strictable = false 80 for i := 0; i < batchSize; i++ { 81 d := time.Duration(rand.Intn(30)-3) * time.Second 82 try(i%2 == 0, d >= 0, d) 83 if d <= 12*time.Second { 84 shouldRun++ 85 } 86 } 87 ec.SetTime(now.Add(13*time.Second - 1)) 88 if numDone != batchSize+1+shouldRun { 89 t.Errorf("Expected %v, but %v ran", shouldRun, numDone-batchSize-1) 90 } 91 lastTime = now.Add(-3 * time.Second) 92 for i := int32(0); i < shouldRun; i++ { 93 nextTime := <-times 94 if nextTime.Before(lastTime) { 95 t.Errorf("Got %s after %s", nextTime, lastTime) 96 } 97 lastTime = nextTime 98 } 99 } 100 101 // copied from baseclocktest, because it is not public 102 func exerciseSettablePassiveClock(t *testing.T, pc TestableEventClock) { 103 t1 := time.Now() 104 t2 := t1.Add(time.Hour) 105 pc.SetTime(t1) 106 tx := pc.Now() 107 if tx != t1 { 108 t.Errorf("SetTime(%#+v); Now() => %#+v", t1, tx) 109 } 110 dx := pc.Since(t1) 111 if dx != 0 { 112 t.Errorf("Since() => %v", dx) 113 } 114 pc.SetTime(t2) 115 dx = pc.Since(t1) 116 if dx != time.Hour { 117 t.Errorf("Since() => %v", dx) 118 } 119 tx = pc.Now() 120 if tx != t2 { 121 t.Errorf("Now() => %#+v", tx) 122 } 123 } 124 125 func TestFake(t *testing.T) { 126 startTime := time.Now() 127 fec, _ := NewFake(startTime, 0, nil) 128 exerciseTestableEventClock(t, fec, 0) 129 fec, _ = NewFake(startTime, time.Second, nil) 130 exerciseTestableEventClock(t, fec, time.Second) 131 }