k8s.io/apiserver@v0.31.1/pkg/storage/cacher/ready_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 package cacher 18 19 import ( 20 "context" 21 "sync" 22 "testing" 23 "time" 24 ) 25 26 func Test_newReady(t *testing.T) { 27 errCh := make(chan error, 10) 28 ready := newReady() 29 ready.set(false) 30 // create 10 goroutines waiting for ready 31 for i := 0; i < 10; i++ { 32 go func() { 33 errCh <- ready.wait(context.Background()) 34 }() 35 } 36 select { 37 case <-time.After(1 * time.Second): 38 case <-errCh: 39 t.Errorf("ready should be blocking") 40 } 41 ready.set(true) 42 for i := 0; i < 10; i++ { 43 if err := <-errCh; err != nil { 44 t.Errorf("unexpected error on channel %d", i) 45 } 46 } 47 } 48 49 func Test_newReadySetIdempotent(t *testing.T) { 50 errCh := make(chan error, 10) 51 ready := newReady() 52 ready.set(false) 53 ready.set(false) 54 ready.set(false) 55 if generation, ok := ready.checkAndReadGeneration(); generation != 0 || ok { 56 t.Errorf("unexpected state: generation=%v ready=%v", generation, ok) 57 } 58 ready.set(true) 59 if generation, ok := ready.checkAndReadGeneration(); generation != 1 || !ok { 60 t.Errorf("unexpected state: generation=%v ready=%v", generation, ok) 61 } 62 ready.set(true) 63 ready.set(true) 64 if generation, ok := ready.checkAndReadGeneration(); generation != 1 || !ok { 65 t.Errorf("unexpected state: generation=%v ready=%v", generation, ok) 66 } 67 ready.set(false) 68 // create 10 goroutines waiting for ready and stop 69 for i := 0; i < 10; i++ { 70 go func() { 71 errCh <- ready.wait(context.Background()) 72 }() 73 } 74 select { 75 case <-time.After(1 * time.Second): 76 case <-errCh: 77 t.Errorf("ready should be blocking") 78 } 79 ready.set(true) 80 if generation, ok := ready.checkAndReadGeneration(); generation != 2 || !ok { 81 t.Errorf("unexpected state: generation=%v ready=%v", generation, ok) 82 } 83 for i := 0; i < 10; i++ { 84 if err := <-errCh; err != nil { 85 t.Errorf("unexpected error on channel %d", i) 86 } 87 } 88 } 89 90 // Test_newReadyRacy executes all the possible transitions randomly. 91 // It must run with the race detector enabled. 92 func Test_newReadyRacy(t *testing.T) { 93 concurrency := 1000 94 errCh := make(chan error, concurrency) 95 ready := newReady() 96 ready.set(false) 97 98 wg := sync.WaitGroup{} 99 wg.Add(2 * concurrency) 100 for i := 0; i < concurrency; i++ { 101 go func() { 102 errCh <- ready.wait(context.Background()) 103 }() 104 go func() { 105 defer wg.Done() 106 ready.set(false) 107 }() 108 go func() { 109 defer wg.Done() 110 ready.set(true) 111 }() 112 } 113 // Last one has to be set to true. 114 wg.Wait() 115 ready.set(true) 116 117 for i := 0; i < concurrency; i++ { 118 if err := <-errCh; err != nil { 119 t.Errorf("unexpected error %v on channel %d", err, i) 120 } 121 } 122 } 123 124 func Test_newReadyStop(t *testing.T) { 125 errCh := make(chan error, 10) 126 ready := newReady() 127 ready.set(false) 128 // create 10 goroutines waiting for ready and stop 129 for i := 0; i < 10; i++ { 130 go func() { 131 errCh <- ready.wait(context.Background()) 132 }() 133 } 134 select { 135 case <-time.After(1 * time.Second): 136 case <-errCh: 137 t.Errorf("ready should be blocking") 138 } 139 ready.stop() 140 for i := 0; i < 10; i++ { 141 if err := <-errCh; err == nil { 142 t.Errorf("unexpected success on channel %d", i) 143 } 144 } 145 } 146 147 func Test_newReadyCheck(t *testing.T) { 148 ready := newReady() 149 // it starts as false 150 if ready.check() { 151 t.Errorf("unexpected ready state %v", ready.check()) 152 } 153 ready.set(true) 154 if !ready.check() { 155 t.Errorf("unexpected ready state %v", ready.check()) 156 } 157 // stop sets ready to false 158 ready.stop() 159 if ready.check() { 160 t.Errorf("unexpected ready state %v", ready.check()) 161 } 162 // can not set to true if is stopped 163 ready.set(true) 164 if ready.check() { 165 t.Errorf("unexpected ready state %v", ready.check()) 166 } 167 err := ready.wait(context.Background()) 168 if err == nil { 169 t.Errorf("expected error waiting on a stopped state") 170 } 171 } 172 173 func Test_newReadyCancelPending(t *testing.T) { 174 errCh := make(chan error, 10) 175 ready := newReady() 176 ready.set(false) 177 ctx, cancel := context.WithCancel(context.Background()) 178 // create 10 goroutines stuck on pending 179 for i := 0; i < 10; i++ { 180 go func() { 181 errCh <- ready.wait(ctx) 182 }() 183 } 184 select { 185 case <-time.After(1 * time.Second): 186 case <-errCh: 187 t.Errorf("ready should be blocking") 188 } 189 cancel() 190 for i := 0; i < 10; i++ { 191 if err := <-errCh; err == nil { 192 t.Errorf("unexpected success on channel %d", i) 193 } 194 } 195 }