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  }