...

Source file src/k8s.io/client-go/tools/cache/reflector_data_consistency_detector_test.go

Documentation: k8s.io/client-go/tools/cache

     1  /*
     2  Copyright 2023 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 cache
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/watch"
    29  )
    30  
    31  func TestWatchListConsistency(t *testing.T) {
    32  	scenarios := []struct {
    33  		name string
    34  
    35  		podList      *v1.PodList
    36  		storeContent []*v1.Pod
    37  
    38  		expectedRequestOptions []metav1.ListOptions
    39  		expectedListRequests   int
    40  		expectPanic            bool
    41  	}{
    42  		{
    43  			name: "watchlist consistency check won't panic when data is consistent",
    44  			podList: &v1.PodList{
    45  				ListMeta: metav1.ListMeta{ResourceVersion: "2"},
    46  				Items:    []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2")},
    47  			},
    48  			storeContent:         []*v1.Pod{makePod("p1", "1"), makePod("p2", "2")},
    49  			expectedListRequests: 1,
    50  			expectedRequestOptions: []metav1.ListOptions{
    51  				{
    52  					ResourceVersion:      "2",
    53  					ResourceVersionMatch: metav1.ResourceVersionMatchExact,
    54  				},
    55  			},
    56  		},
    57  
    58  		{
    59  			name: "watchlist consistency check won't panic when there is no data",
    60  			podList: &v1.PodList{
    61  				ListMeta: metav1.ListMeta{ResourceVersion: "2"},
    62  			},
    63  			expectedListRequests: 1,
    64  			expectedRequestOptions: []metav1.ListOptions{
    65  				{
    66  					ResourceVersion:      "2",
    67  					ResourceVersionMatch: metav1.ResourceVersionMatchExact,
    68  				},
    69  			},
    70  		},
    71  
    72  		{
    73  			name: "watchlist consistency panics when data is inconsistent",
    74  			podList: &v1.PodList{
    75  				ListMeta: metav1.ListMeta{ResourceVersion: "2"},
    76  				Items:    []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2"), *makePod("p3", "3")},
    77  			},
    78  			storeContent:         []*v1.Pod{makePod("p1", "1"), makePod("p2", "2")},
    79  			expectedListRequests: 1,
    80  			expectedRequestOptions: []metav1.ListOptions{
    81  				{
    82  					ResourceVersion:      "2",
    83  					ResourceVersionMatch: metav1.ResourceVersionMatchExact,
    84  				},
    85  			},
    86  			expectPanic: true,
    87  		},
    88  	}
    89  
    90  	for _, scenario := range scenarios {
    91  		t.Run(scenario.name, func(t *testing.T) {
    92  			listWatcher, store, _, stopCh := testData()
    93  			for _, obj := range scenario.storeContent {
    94  				require.NoError(t, store.Add(obj))
    95  			}
    96  			listWatcher.customListResponse = scenario.podList
    97  
    98  			if scenario.expectPanic {
    99  				require.Panics(t, func() { checkWatchListConsistency(stopCh, "", scenario.podList.ResourceVersion, listWatcher, store) })
   100  			} else {
   101  				checkWatchListConsistency(stopCh, "", scenario.podList.ResourceVersion, listWatcher, store)
   102  			}
   103  
   104  			verifyListCounter(t, listWatcher, scenario.expectedListRequests)
   105  			verifyRequestOptions(t, listWatcher, scenario.expectedRequestOptions)
   106  		})
   107  	}
   108  }
   109  
   110  func TestDriveWatchLisConsistencyIfRequired(t *testing.T) {
   111  	stopCh := make(chan struct{})
   112  	defer close(stopCh)
   113  	checkWatchListConsistencyIfRequested(stopCh, "", "", nil, nil)
   114  }
   115  
   116  func TestWatchListConsistencyRetry(t *testing.T) {
   117  	store := NewStore(MetaNamespaceKeyFunc)
   118  	stopCh := make(chan struct{})
   119  	defer close(stopCh)
   120  
   121  	stopListErrorAfter := 5
   122  	errLister := &errorLister{stopErrorAfter: stopListErrorAfter}
   123  
   124  	checkWatchListConsistency(stopCh, "", "", errLister, store)
   125  	require.Equal(t, errLister.listCounter, errLister.stopErrorAfter)
   126  }
   127  
   128  type errorLister struct {
   129  	listCounter    int
   130  	stopErrorAfter int
   131  }
   132  
   133  func (lw *errorLister) List(_ metav1.ListOptions) (runtime.Object, error) {
   134  	lw.listCounter++
   135  	if lw.listCounter == lw.stopErrorAfter {
   136  		return &v1.PodList{}, nil
   137  	}
   138  	return nil, fmt.Errorf("nasty error")
   139  }
   140  
   141  func (lw *errorLister) Watch(_ metav1.ListOptions) (watch.Interface, error) {
   142  	panic("not implemented")
   143  }
   144  

View as plain text