k8s.io/client-go@v0.31.1/tools/cache/testing/fake_controller_source.go (about)

     1  /*
     2  Copyright 2015 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 framework
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/rand"
    23  	"strconv"
    24  	"sync"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    28  	"k8s.io/apimachinery/pkg/api/meta"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/apimachinery/pkg/watch"
    33  )
    34  
    35  func NewFakeControllerSource() *FakeControllerSource {
    36  	return &FakeControllerSource{
    37  		Items:       map[nnu]runtime.Object{},
    38  		Broadcaster: watch.NewBroadcaster(100, watch.WaitIfChannelFull),
    39  	}
    40  }
    41  
    42  func NewFakePVControllerSource() *FakePVControllerSource {
    43  	return &FakePVControllerSource{
    44  		FakeControllerSource{
    45  			Items:       map[nnu]runtime.Object{},
    46  			Broadcaster: watch.NewBroadcaster(100, watch.WaitIfChannelFull),
    47  		}}
    48  }
    49  
    50  func NewFakePVCControllerSource() *FakePVCControllerSource {
    51  	return &FakePVCControllerSource{
    52  		FakeControllerSource{
    53  			Items:       map[nnu]runtime.Object{},
    54  			Broadcaster: watch.NewBroadcaster(100, watch.WaitIfChannelFull),
    55  		}}
    56  }
    57  
    58  // FakeControllerSource implements listing/watching for testing.
    59  type FakeControllerSource struct {
    60  	lock        sync.RWMutex
    61  	Items       map[nnu]runtime.Object
    62  	changes     []watch.Event // one change per resourceVersion
    63  	Broadcaster *watch.Broadcaster
    64  	lastRV      int
    65  
    66  	// Set this to simulate an error on List()
    67  	ListError error
    68  }
    69  
    70  type FakePVControllerSource struct {
    71  	FakeControllerSource
    72  }
    73  
    74  type FakePVCControllerSource struct {
    75  	FakeControllerSource
    76  }
    77  
    78  // namespace, name, uid to be used as a key.
    79  type nnu struct {
    80  	namespace, name string
    81  	uid             types.UID
    82  }
    83  
    84  // ResetWatch simulates connection problems; creates a new Broadcaster and flushes
    85  // the change queue so that clients have to re-list and watch.
    86  func (f *FakeControllerSource) ResetWatch() {
    87  	f.lock.Lock()
    88  	defer f.lock.Unlock()
    89  	f.Broadcaster.Shutdown()
    90  	f.Broadcaster = watch.NewBroadcaster(100, watch.WaitIfChannelFull)
    91  	f.changes = []watch.Event{}
    92  }
    93  
    94  // Add adds an object to the set and sends an add event to watchers.
    95  // obj's ResourceVersion is set.
    96  func (f *FakeControllerSource) Add(obj runtime.Object) {
    97  	f.Change(watch.Event{Type: watch.Added, Object: obj}, 1)
    98  }
    99  
   100  // Modify updates an object in the set and sends a modified event to watchers.
   101  // obj's ResourceVersion is set.
   102  func (f *FakeControllerSource) Modify(obj runtime.Object) {
   103  	f.Change(watch.Event{Type: watch.Modified, Object: obj}, 1)
   104  }
   105  
   106  // Delete deletes an object from the set and sends a delete event to watchers.
   107  // obj's ResourceVersion is set.
   108  func (f *FakeControllerSource) Delete(lastValue runtime.Object) {
   109  	f.Change(watch.Event{Type: watch.Deleted, Object: lastValue}, 1)
   110  }
   111  
   112  // AddDropWatch adds an object to the set but forgets to send an add event to
   113  // watchers.
   114  // obj's ResourceVersion is set.
   115  func (f *FakeControllerSource) AddDropWatch(obj runtime.Object) {
   116  	f.Change(watch.Event{Type: watch.Added, Object: obj}, 0)
   117  }
   118  
   119  // ModifyDropWatch updates an object in the set but forgets to send a modify
   120  // event to watchers.
   121  // obj's ResourceVersion is set.
   122  func (f *FakeControllerSource) ModifyDropWatch(obj runtime.Object) {
   123  	f.Change(watch.Event{Type: watch.Modified, Object: obj}, 0)
   124  }
   125  
   126  // DeleteDropWatch deletes an object from the set but forgets to send a delete
   127  // event to watchers.
   128  // obj's ResourceVersion is set.
   129  func (f *FakeControllerSource) DeleteDropWatch(lastValue runtime.Object) {
   130  	f.Change(watch.Event{Type: watch.Deleted, Object: lastValue}, 0)
   131  }
   132  
   133  func (f *FakeControllerSource) key(accessor metav1.Object) nnu {
   134  	return nnu{accessor.GetNamespace(), accessor.GetName(), accessor.GetUID()}
   135  }
   136  
   137  // Change records the given event (setting the object's resource version) and
   138  // sends a watch event with the specified probability.
   139  func (f *FakeControllerSource) Change(e watch.Event, watchProbability float64) {
   140  	f.lock.Lock()
   141  	defer f.lock.Unlock()
   142  
   143  	accessor, err := meta.Accessor(e.Object)
   144  	if err != nil {
   145  		panic(err) // this is test code only
   146  	}
   147  
   148  	f.lastRV += 1
   149  	accessor.SetResourceVersion(strconv.Itoa(f.lastRV))
   150  	f.changes = append(f.changes, e)
   151  	key := f.key(accessor)
   152  	switch e.Type {
   153  	case watch.Added, watch.Modified:
   154  		f.Items[key] = e.Object
   155  	case watch.Deleted:
   156  		delete(f.Items, key)
   157  	}
   158  
   159  	if rand.Float64() < watchProbability {
   160  		f.Broadcaster.Action(e.Type, e.Object)
   161  	}
   162  }
   163  
   164  func (f *FakeControllerSource) getListItemsLocked() ([]runtime.Object, error) {
   165  	list := make([]runtime.Object, 0, len(f.Items))
   166  	for _, obj := range f.Items {
   167  		// Must make a copy to allow clients to modify the object.
   168  		// Otherwise, if they make a change and write it back, they
   169  		// will inadvertently change our canonical copy (in
   170  		// addition to racing with other clients).
   171  		list = append(list, obj.DeepCopyObject())
   172  	}
   173  	return list, nil
   174  }
   175  
   176  // List returns a list object, with its resource version set.
   177  func (f *FakeControllerSource) List(options metav1.ListOptions) (runtime.Object, error) {
   178  	f.lock.RLock()
   179  	defer f.lock.RUnlock()
   180  
   181  	if f.ListError != nil {
   182  		return nil, f.ListError
   183  	}
   184  
   185  	list, err := f.getListItemsLocked()
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	listObj := &v1.List{}
   190  	if err := meta.SetList(listObj, list); err != nil {
   191  		return nil, err
   192  	}
   193  	listAccessor, err := meta.ListAccessor(listObj)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	listAccessor.SetResourceVersion(strconv.Itoa(f.lastRV))
   198  	return listObj, nil
   199  }
   200  
   201  // List returns a list object, with its resource version set.
   202  func (f *FakePVControllerSource) List(options metav1.ListOptions) (runtime.Object, error) {
   203  	f.lock.RLock()
   204  	defer f.lock.RUnlock()
   205  	list, err := f.FakeControllerSource.getListItemsLocked()
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	listObj := &v1.PersistentVolumeList{}
   210  	if err := meta.SetList(listObj, list); err != nil {
   211  		return nil, err
   212  	}
   213  	listAccessor, err := meta.ListAccessor(listObj)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	listAccessor.SetResourceVersion(strconv.Itoa(f.lastRV))
   218  	return listObj, nil
   219  }
   220  
   221  // List returns a list object, with its resource version set.
   222  func (f *FakePVCControllerSource) List(options metav1.ListOptions) (runtime.Object, error) {
   223  	f.lock.RLock()
   224  	defer f.lock.RUnlock()
   225  	list, err := f.FakeControllerSource.getListItemsLocked()
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	listObj := &v1.PersistentVolumeClaimList{}
   230  	if err := meta.SetList(listObj, list); err != nil {
   231  		return nil, err
   232  	}
   233  	listAccessor, err := meta.ListAccessor(listObj)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	listAccessor.SetResourceVersion(strconv.Itoa(f.lastRV))
   238  	return listObj, nil
   239  }
   240  
   241  // Watch returns a watch, which will be pre-populated with all changes
   242  // after resourceVersion.
   243  func (f *FakeControllerSource) Watch(options metav1.ListOptions) (watch.Interface, error) {
   244  	f.lock.RLock()
   245  	defer f.lock.RUnlock()
   246  	rc, err := strconv.Atoi(options.ResourceVersion)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	if rc < f.lastRV {
   251  		// if the change queue was flushed...
   252  		if len(f.changes) == 0 {
   253  			return nil, apierrors.NewResourceExpired(fmt.Sprintf("too old resource version: %d (%d)", rc, f.lastRV))
   254  		}
   255  
   256  		// get the RV of the oldest object in the change queue
   257  		oldestRV, err := meta.NewAccessor().ResourceVersion(f.changes[0].Object)
   258  		if err != nil {
   259  			panic(err)
   260  		}
   261  		oldestRC, err := strconv.Atoi(oldestRV)
   262  		if err != nil {
   263  			panic(err)
   264  		}
   265  		if rc < oldestRC {
   266  			return nil, apierrors.NewResourceExpired(fmt.Sprintf("too old resource version: %d (%d)", rc, oldestRC))
   267  		}
   268  
   269  		changes := []watch.Event{}
   270  		for _, c := range f.changes[rc-oldestRC+1:] {
   271  			// Must make a copy to allow clients to modify the
   272  			// object.  Otherwise, if they make a change and write
   273  			// it back, they will inadvertently change the our
   274  			// canonical copy (in addition to racing with other
   275  			// clients).
   276  			changes = append(changes, watch.Event{Type: c.Type, Object: c.Object.DeepCopyObject()})
   277  		}
   278  		return f.Broadcaster.WatchWithPrefix(changes)
   279  	} else if rc > f.lastRV {
   280  		return nil, errors.New("resource version in the future not supported by this fake")
   281  	}
   282  	return f.Broadcaster.Watch()
   283  }
   284  
   285  // Shutdown closes the underlying broadcaster, waiting for events to be
   286  // delivered. It's an error to call any method after calling shutdown. This is
   287  // enforced by Shutdown() leaving f locked.
   288  func (f *FakeControllerSource) Shutdown() {
   289  	f.lock.Lock() // Purposely no unlock.
   290  	f.Broadcaster.Shutdown()
   291  }