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  }