knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/reconciler/testing/generate_name_reactor.go (about)

     1  /*
     2  Copyright 2019 The Knative 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 testing
    18  
    19  import (
    20  	"fmt"
    21  	"sync/atomic"
    22  
    23  	"k8s.io/apimachinery/pkg/api/meta"
    24  	"k8s.io/apimachinery/pkg/runtime"
    25  	clientgotesting "k8s.io/client-go/testing"
    26  )
    27  
    28  // GenerateNameReactor will simulate the k8s API server
    29  // and generate a name for resources who's metadata.generateName
    30  // property is set. This happens only for CreateAction types
    31  //
    32  // This generator is deterministic (unliked k8s) and uses a global
    33  // counter to help make test names predictable
    34  type GenerateNameReactor struct {
    35  	count int64
    36  }
    37  
    38  // Handles contains all the logic to generate the name and mutates
    39  // the create action object
    40  //
    41  // This is a hack as 'React' is passed a DeepCopy of the action hence
    42  // this is the only opportunity to 'mutate' the action in the
    43  // ReactionChain and have to continue executing additional reactors
    44  //
    45  // We should push changes upstream to client-go to help us with
    46  // mocking
    47  func (r *GenerateNameReactor) Handles(action clientgotesting.Action) bool {
    48  	create, ok := action.(clientgotesting.CreateAction)
    49  	if !ok {
    50  		return false
    51  	}
    52  
    53  	objMeta, err := meta.Accessor(create.GetObject())
    54  	if err != nil {
    55  		return false
    56  	}
    57  
    58  	if objMeta.GetName() != "" {
    59  		return false
    60  	}
    61  
    62  	if objMeta.GetGenerateName() == "" {
    63  		return false
    64  	}
    65  
    66  	val := atomic.AddInt64(&r.count, 1)
    67  
    68  	objMeta.SetName(fmt.Sprintf("%s%05d", objMeta.GetGenerateName(), val))
    69  
    70  	return false
    71  }
    72  
    73  // React is noop-function
    74  func (r *GenerateNameReactor) React(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
    75  	return false, nil, nil
    76  }
    77  
    78  var _ clientgotesting.Reactor = (*GenerateNameReactor)(nil)
    79  
    80  // PrependGenerateNameReactor will instrument a client-go testing Fake
    81  // with a reactor that simulates 'generateName' functionality
    82  func PrependGenerateNameReactor(f *clientgotesting.Fake) {
    83  	f.ReactionChain = append([]clientgotesting.Reactor{&GenerateNameReactor{}}, f.ReactionChain...)
    84  }