k8s.io/apiserver@v0.31.1/pkg/util/flowcontrol/fairqueuing/testing/promise/counting_test.go (about) 1 /* 2 Copyright 2019 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 promise 18 19 import ( 20 "context" 21 "os" 22 "sync" 23 "testing" 24 "time" 25 26 "k8s.io/apimachinery/pkg/util/wait" 27 "k8s.io/apiserver/pkg/util/flowcontrol/counter" 28 "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/promise" 29 testeventclock "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/testing/eventclock" 30 "k8s.io/klog/v2" 31 ) 32 33 func TestMain(m *testing.M) { 34 klog.InitFlags(nil) 35 os.Exit(m.Run()) 36 } 37 38 func TestCountingWriteOnceSet(t *testing.T) { 39 oldTime := time.Now() 40 cval := &oldTime 41 doneCh := make(chan struct{}) 42 now := time.Now() 43 clock, counter := testeventclock.NewFake(now, 0, nil) 44 var lock sync.Mutex 45 wr := NewCountingWriteOnce(counter, &lock, nil, doneCh, cval) 46 gots := make(chan interface{}, 1) 47 goGetExpectNotYet(t, clock, counter, wr, gots, "Set") 48 aval := &now 49 func() { 50 lock.Lock() 51 defer lock.Unlock() 52 if !wr.Set(aval) { 53 t.Error("Set() returned false") 54 } 55 }() 56 clock.Run(nil) 57 expectGotValue(t, gots, aval) 58 goGetAndExpect(t, clock, counter, wr, gots, aval) 59 later := time.Now() 60 bval := &later 61 func() { 62 lock.Lock() 63 defer lock.Unlock() 64 if wr.Set(bval) { 65 t.Error("second Set() returned true") 66 } 67 }() 68 goGetAndExpect(t, clock, counter, wr, gots, aval) 69 counter.Add(1) // account for unblocking the receive on doneCh 70 close(doneCh) 71 time.Sleep(time.Second) // give it a chance to misbehave 72 goGetAndExpect(t, clock, counter, wr, gots, aval) 73 } 74 func TestCountingWriteOnceCancel(t *testing.T) { 75 oldTime := time.Now() 76 cval := &oldTime 77 clock, counter := testeventclock.NewFake(oldTime, 0, nil) 78 ctx, cancel := context.WithCancel(context.Background()) 79 var lock sync.Mutex 80 wr := NewCountingWriteOnce(counter, &lock, nil, ctx.Done(), cval) 81 gots := make(chan interface{}, 1) 82 goGetExpectNotYet(t, clock, counter, wr, gots, "cancel") 83 counter.Add(1) // account for unblocking the receive on doneCh 84 cancel() 85 clock.Run(nil) 86 expectGotValue(t, gots, cval) 87 goGetAndExpect(t, clock, counter, wr, gots, cval) 88 later := time.Now() 89 bval := &later 90 func() { 91 lock.Lock() 92 defer lock.Unlock() 93 if wr.Set(bval) { 94 t.Error("Set() after cancel returned true") 95 } 96 }() 97 goGetAndExpect(t, clock, counter, wr, gots, cval) 98 } 99 100 func TestCountingWriteOnceInitial(t *testing.T) { 101 oldTime := time.Now() 102 cval := &oldTime 103 clock, counter := testeventclock.NewFake(oldTime, 0, nil) 104 ctx, cancel := context.WithCancel(context.Background()) 105 var lock sync.Mutex 106 now := time.Now() 107 aval := &now 108 wr := NewCountingWriteOnce(counter, &lock, aval, ctx.Done(), cval) 109 gots := make(chan interface{}, 1) 110 goGetAndExpect(t, clock, counter, wr, gots, aval) 111 goGetAndExpect(t, clock, counter, wr, gots, aval) // check that a set value stays set 112 later := time.Now() 113 bval := &later 114 func() { 115 lock.Lock() 116 defer lock.Unlock() 117 if wr.Set(bval) { 118 t.Error("Set of initialized promise returned true") 119 } 120 }() 121 goGetAndExpect(t, clock, counter, wr, gots, aval) 122 counter.Add(1) // account for unblocking receive on doneCh 123 cancel() 124 time.Sleep(time.Second) // give it a chance to misbehave 125 goGetAndExpect(t, clock, counter, wr, gots, aval) 126 } 127 128 func goGetExpectNotYet(t *testing.T, clk *testeventclock.Fake, grc counter.GoRoutineCounter, wr promise.WriteOnce, gots chan interface{}, trigger string) { 129 grc.Add(1) // count the following goroutine 130 go func() { 131 defer grc.Add(-1) // count completion of this goroutine 132 gots <- wr.Get() 133 }() 134 clk.Run(nil) 135 select { 136 case <-gots: 137 t.Errorf("Get returned before %s", trigger) 138 case <-time.After(time.Second): 139 t.Log("Good: Get did not return yet") 140 } 141 142 } 143 144 func goGetAndExpect(t *testing.T, clk *testeventclock.Fake, grc counter.GoRoutineCounter, wr promise.WriteOnce, gots chan interface{}, expected interface{}) { 145 grc.Add(1) 146 go func() { 147 defer grc.Add(-1) 148 gots <- wr.Get() 149 }() 150 clk.Run(nil) 151 expectGotValue(t, gots, expected) 152 } 153 154 func expectGotValue(t *testing.T, gots <-chan interface{}, expected interface{}) { 155 select { 156 case gotVal := <-gots: 157 t.Logf("Got %v", gotVal) 158 if gotVal != expected { 159 t.Errorf("Get returned %v, expected: %v", gotVal, expected) 160 } 161 case <-time.After(wait.ForeverTestTimeout): 162 t.Error("Get did not return") 163 } 164 }