k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/flowcontrol/ensurer/prioritylevelconfiguration_test.go (about)

     1  /*
     2  Copyright 2021 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 ensurer
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"testing"
    23  
    24  	flowcontrolv1 "k8s.io/api/flowcontrol/v1"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap"
    28  	"k8s.io/client-go/kubernetes/fake"
    29  	flowcontrollisters "k8s.io/client-go/listers/flowcontrol/v1"
    30  	toolscache "k8s.io/client-go/tools/cache"
    31  	flowcontrolapisv1 "k8s.io/kubernetes/pkg/apis/flowcontrol/v1"
    32  	"k8s.io/utils/ptr"
    33  
    34  	"github.com/google/go-cmp/cmp"
    35  )
    36  
    37  func TestEnsurePriorityLevel(t *testing.T) {
    38  	validExemptPL := func() *flowcontrolv1.PriorityLevelConfiguration {
    39  		copy := bootstrap.MandatoryPriorityLevelConfigurationExempt.DeepCopy()
    40  		copy.Annotations[flowcontrolv1.AutoUpdateAnnotationKey] = "true"
    41  		copy.Spec.Exempt.NominalConcurrencyShares = ptr.To[int32](10)
    42  		copy.Spec.Exempt.LendablePercent = ptr.To[int32](50)
    43  		return copy
    44  	}()
    45  
    46  	tests := []struct {
    47  		name      string
    48  		strategy  func() EnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration]
    49  		current   *flowcontrolv1.PriorityLevelConfiguration
    50  		bootstrap *flowcontrolv1.PriorityLevelConfiguration
    51  		expected  *flowcontrolv1.PriorityLevelConfiguration
    52  	}{
    53  		// for suggested configurations
    54  		{
    55  			name:      "suggested priority level configuration does not exist - the object should always be re-created",
    56  			strategy:  NewSuggestedEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    57  			bootstrap: newPLConfiguration("pl1").WithLimited(10).Object(),
    58  			current:   nil,
    59  			expected:  newPLConfiguration("pl1").WithLimited(10).Object(),
    60  		},
    61  		{
    62  			name:      "suggested priority level configuration exists, auto update is enabled, spec does not match - current object should be updated",
    63  			strategy:  NewSuggestedEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    64  			bootstrap: newPLConfiguration("pl1").WithLimited(20).Object(),
    65  			current:   newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").WithLimited(10).Object(),
    66  			expected:  newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").WithLimited(20).Object(),
    67  		},
    68  		{
    69  			name:      "suggested priority level configuration exists, auto update is disabled, spec does not match - current object should not be updated",
    70  			strategy:  NewSuggestedEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    71  			bootstrap: newPLConfiguration("pl1").WithLimited(20).Object(),
    72  			current:   newPLConfiguration("pl1").WithAutoUpdateAnnotation("false").WithLimited(10).Object(),
    73  			expected:  newPLConfiguration("pl1").WithAutoUpdateAnnotation("false").WithLimited(10).Object(),
    74  		},
    75  
    76  		// for mandatory configurations
    77  		{
    78  			name:      "mandatory priority level configuration does not exist - new object should be created",
    79  			strategy:  NewMandatoryEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    80  			bootstrap: newPLConfiguration("pl1").WithLimited(10).WithAutoUpdateAnnotation("true").Object(),
    81  			current:   nil,
    82  			expected:  newPLConfiguration("pl1").WithLimited(10).WithAutoUpdateAnnotation("true").Object(),
    83  		},
    84  		{
    85  			name:      "mandatory priority level configuration exists, annotation is missing - annotation is added",
    86  			strategy:  NewMandatoryEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    87  			bootstrap: newPLConfiguration("pl1").WithLimited(20).Object(),
    88  			current:   newPLConfiguration("pl1").WithLimited(20).Object(),
    89  			expected:  newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").WithLimited(20).Object(),
    90  		},
    91  		{
    92  			name:      "mandatory priority level configuration exists, auto update is disabled, spec does not match - current object should be updated",
    93  			strategy:  NewMandatoryEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
    94  			bootstrap: newPLConfiguration("pl1").WithLimited(20).Object(),
    95  			current:   newPLConfiguration("pl1").WithAutoUpdateAnnotation("false").WithLimited(10).Object(),
    96  			expected:  newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").WithLimited(20).Object(),
    97  		},
    98  		{
    99  			name:     "admin changes the Exempt field of the exempt priority level configuration",
   100  			strategy: NewMandatoryEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration],
   101  			bootstrap: func() *flowcontrolv1.PriorityLevelConfiguration {
   102  				return bootstrap.MandatoryPriorityLevelConfigurationExempt
   103  			}(),
   104  			current:  validExemptPL,
   105  			expected: validExemptPL,
   106  		},
   107  	}
   108  
   109  	for _, test := range tests {
   110  		t.Run(test.name, func(t *testing.T) {
   111  			client := fake.NewSimpleClientset().FlowcontrolV1().PriorityLevelConfigurations()
   112  			indexer := toolscache.NewIndexer(toolscache.MetaNamespaceKeyFunc, toolscache.Indexers{})
   113  			if test.current != nil {
   114  				client.Create(context.TODO(), test.current, metav1.CreateOptions{})
   115  				indexer.Add(test.current)
   116  			}
   117  
   118  			ops := NewPriorityLevelConfigurationOps(client, flowcontrollisters.NewPriorityLevelConfigurationLister(indexer))
   119  			boots := []*flowcontrolv1.PriorityLevelConfiguration{test.bootstrap}
   120  			strategy := test.strategy()
   121  
   122  			err := EnsureConfigurations(context.Background(), ops, boots, strategy)
   123  			if err != nil {
   124  				t.Fatalf("Expected no error, but got: %v", err)
   125  			}
   126  
   127  			plGot, err := client.Get(context.TODO(), test.bootstrap.Name, metav1.GetOptions{})
   128  			switch {
   129  			case test.expected == nil:
   130  				if !apierrors.IsNotFound(err) {
   131  					t.Fatalf("Expected GET to return an %q error, but got: %v", metav1.StatusReasonNotFound, err)
   132  				}
   133  			case err != nil:
   134  				t.Fatalf("Expected GET to return no error, but got: %v", err)
   135  			}
   136  
   137  			if !reflect.DeepEqual(test.expected, plGot) {
   138  				t.Errorf("PriorityLevelConfiguration does not match - diff: %s", cmp.Diff(test.expected, plGot))
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestSuggestedPLEnsureStrategy_ShouldUpdate(t *testing.T) {
   145  	tests := []struct {
   146  		name              string
   147  		current           *flowcontrolv1.PriorityLevelConfiguration
   148  		bootstrap         *flowcontrolv1.PriorityLevelConfiguration
   149  		newObjectExpected *flowcontrolv1.PriorityLevelConfiguration
   150  	}{
   151  		{
   152  			name:              "auto update is enabled, first generation, spec does not match - spec update expected",
   153  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(1).WithLimited(5).Object(),
   154  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   155  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(1).WithLimited(10).Object(),
   156  		},
   157  		{
   158  			name:              "auto update is enabled, first generation, spec matches - no update expected",
   159  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(1).WithLimited(5).Object(),
   160  			bootstrap:         newPLConfiguration("foo").WithGeneration(1).WithLimited(5).Object(),
   161  			newObjectExpected: nil,
   162  		},
   163  		{
   164  			name:              "auto update is enabled, second generation, spec does not match - spec update expected",
   165  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(2).WithLimited(5).Object(),
   166  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   167  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(2).WithLimited(10).Object(),
   168  		},
   169  		{
   170  			name:              "auto update is enabled, second generation, spec matches - no update expected",
   171  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(2).WithLimited(5).Object(),
   172  			bootstrap:         newPLConfiguration("foo").WithLimited(5).Object(),
   173  			newObjectExpected: nil,
   174  		},
   175  		{
   176  			name:              "auto update is disabled, first generation, spec does not match - no update expected",
   177  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(1).WithLimited(5).Object(),
   178  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   179  			newObjectExpected: nil,
   180  		},
   181  		{
   182  			name:              "auto update is disabled, first generation, spec matches - no update expected",
   183  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(1).WithLimited(5).Object(),
   184  			bootstrap:         newPLConfiguration("foo").WithLimited(5).Object(),
   185  			newObjectExpected: nil,
   186  		},
   187  		{
   188  			name:              "auto update is disabled, second generation, spec does not match - no update expected",
   189  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(2).WithLimited(5).Object(),
   190  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   191  			newObjectExpected: nil,
   192  		},
   193  		{
   194  			name:              "auto update is disabled, second generation, spec matches - no update expected",
   195  			current:           newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(2).WithLimited(5).Object(),
   196  			bootstrap:         newPLConfiguration("foo").WithLimited(5).Object(),
   197  			newObjectExpected: nil,
   198  		},
   199  		{
   200  			name:              "annotation is missing, first generation, spec does not match - both annotation and spec update expected",
   201  			current:           newPLConfiguration("foo").WithGeneration(1).WithLimited(5).Object(),
   202  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   203  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(1).WithLimited(10).Object(),
   204  		},
   205  		{
   206  			name:              "annotation is missing, first generation, spec matches - annotation update is expected",
   207  			current:           newPLConfiguration("foo").WithGeneration(1).WithLimited(5).Object(),
   208  			bootstrap:         newPLConfiguration("foo").WithLimited(5).Object(),
   209  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("true").WithGeneration(1).WithLimited(5).Object(),
   210  		},
   211  		{
   212  			name:              "annotation is missing, second generation, spec does not match - annotation update is expected",
   213  			current:           newPLConfiguration("foo").WithGeneration(2).WithLimited(5).Object(),
   214  			bootstrap:         newPLConfiguration("foo").WithLimited(10).Object(),
   215  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(2).WithLimited(5).Object(),
   216  		},
   217  		{
   218  			name:              "annotation is missing, second generation, spec matches - annotation update is expected",
   219  			current:           newPLConfiguration("foo").WithGeneration(2).WithLimited(5).Object(),
   220  			bootstrap:         newPLConfiguration("foo").WithLimited(5).Object(),
   221  			newObjectExpected: newPLConfiguration("foo").WithAutoUpdateAnnotation("false").WithGeneration(2).WithLimited(5).Object(),
   222  		},
   223  	}
   224  
   225  	ops := NewPriorityLevelConfigurationOps(nil, nil)
   226  	for _, test := range tests {
   227  		t.Run(test.name, func(t *testing.T) {
   228  			strategy := NewSuggestedEnsureStrategy[*flowcontrolv1.PriorityLevelConfiguration]()
   229  			updatableGot, updateGot, err := strategy.ReviseIfNeeded(ops, test.current, test.bootstrap)
   230  			if err != nil {
   231  				t.Errorf("Expected no error, but got: %v", err)
   232  			}
   233  			if test.newObjectExpected == nil {
   234  				if updatableGot != nil {
   235  					t.Errorf("Expected a nil object, but got: %#v", updatableGot)
   236  				}
   237  				if updateGot {
   238  					t.Errorf("Expected update=%t but got: %t", false, updateGot)
   239  				}
   240  				return
   241  			}
   242  
   243  			if !updateGot {
   244  				t.Errorf("Expected update=%t but got: %t", true, updateGot)
   245  			}
   246  			if !reflect.DeepEqual(test.newObjectExpected, updatableGot) {
   247  				t.Errorf("Expected the object to be updated to match - diff: %s", cmp.Diff(test.newObjectExpected, updatableGot))
   248  			}
   249  		})
   250  	}
   251  }
   252  
   253  func TestPriorityLevelSpecChanged(t *testing.T) {
   254  	pl1 := &flowcontrolv1.PriorityLevelConfiguration{
   255  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   256  			Type: flowcontrolv1.PriorityLevelEnablementLimited,
   257  			Limited: &flowcontrolv1.LimitedPriorityLevelConfiguration{
   258  				LimitResponse: flowcontrolv1.LimitResponse{
   259  					Type: flowcontrolv1.LimitResponseTypeReject,
   260  				},
   261  			},
   262  		},
   263  	}
   264  	pl2 := &flowcontrolv1.PriorityLevelConfiguration{
   265  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   266  			Type: flowcontrolv1.PriorityLevelEnablementLimited,
   267  			Limited: &flowcontrolv1.LimitedPriorityLevelConfiguration{
   268  				NominalConcurrencyShares: ptr.To(int32(1)),
   269  			},
   270  		},
   271  	}
   272  	pl1Defaulted := &flowcontrolv1.PriorityLevelConfiguration{
   273  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   274  			Type: flowcontrolv1.PriorityLevelEnablementLimited,
   275  			Limited: &flowcontrolv1.LimitedPriorityLevelConfiguration{
   276  				NominalConcurrencyShares: ptr.To(flowcontrolapisv1.PriorityLevelConfigurationDefaultNominalConcurrencyShares),
   277  				LendablePercent:          ptr.To[int32](0),
   278  				LimitResponse: flowcontrolv1.LimitResponse{
   279  					Type: flowcontrolv1.LimitResponseTypeReject,
   280  				},
   281  			},
   282  		},
   283  	}
   284  	ple1 := &flowcontrolv1.PriorityLevelConfiguration{
   285  		ObjectMeta: metav1.ObjectMeta{Name: "exempt"},
   286  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   287  			Type: flowcontrolv1.PriorityLevelEnablementExempt,
   288  			Exempt: &flowcontrolv1.ExemptPriorityLevelConfiguration{
   289  				NominalConcurrencyShares: ptr.To[int32](42),
   290  				LendablePercent:          ptr.To[int32](33),
   291  			},
   292  		},
   293  	}
   294  	ple2 := &flowcontrolv1.PriorityLevelConfiguration{
   295  		ObjectMeta: metav1.ObjectMeta{Name: "exempt"},
   296  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   297  			Type: flowcontrolv1.PriorityLevelEnablementExempt,
   298  			Exempt: &flowcontrolv1.ExemptPriorityLevelConfiguration{
   299  				NominalConcurrencyShares: ptr.To[int32](24),
   300  				LendablePercent:          ptr.To[int32](86),
   301  			},
   302  		},
   303  	}
   304  	pleWrong := &flowcontrolv1.PriorityLevelConfiguration{
   305  		ObjectMeta: metav1.ObjectMeta{Name: "exempt"},
   306  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   307  			Type: flowcontrolv1.PriorityLevelEnablementLimited,
   308  			Limited: &flowcontrolv1.LimitedPriorityLevelConfiguration{
   309  				NominalConcurrencyShares: ptr.To(int32(1)),
   310  			},
   311  		},
   312  	}
   313  	pleInvalid := &flowcontrolv1.PriorityLevelConfiguration{
   314  		ObjectMeta: metav1.ObjectMeta{Name: "exempt"},
   315  		Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   316  			Type: "widget",
   317  		},
   318  	}
   319  	testCases := []struct {
   320  		name        string
   321  		expected    *flowcontrolv1.PriorityLevelConfiguration
   322  		actual      *flowcontrolv1.PriorityLevelConfiguration
   323  		specChanged bool
   324  	}{
   325  		{
   326  			name:        "identical priority-level should work",
   327  			expected:    bootstrap.MandatoryPriorityLevelConfigurationCatchAll,
   328  			actual:      bootstrap.MandatoryPriorityLevelConfigurationCatchAll,
   329  			specChanged: false,
   330  		},
   331  		{
   332  			name:        "defaulted priority-level should work",
   333  			expected:    pl1,
   334  			actual:      pl1Defaulted,
   335  			specChanged: false,
   336  		},
   337  		{
   338  			name:        "non-defaulted priority-level has wrong spec",
   339  			expected:    pl1,
   340  			actual:      pl2,
   341  			specChanged: true,
   342  		},
   343  		{
   344  			name:        "tweaked exempt config",
   345  			expected:    ple1,
   346  			actual:      ple2,
   347  			specChanged: false,
   348  		},
   349  		{
   350  			name:        "exempt with wrong tag",
   351  			expected:    ple1,
   352  			actual:      pleWrong,
   353  			specChanged: true,
   354  		},
   355  		{
   356  			name:        "exempt with invalid tag",
   357  			expected:    ple1,
   358  			actual:      pleInvalid,
   359  			specChanged: true,
   360  		},
   361  	}
   362  	for _, testCase := range testCases {
   363  		t.Run(testCase.name, func(t *testing.T) {
   364  			w := !plcSpecEqualish(testCase.expected, testCase.actual)
   365  			if testCase.specChanged != w {
   366  				t.Errorf("Expected priorityLevelSpecChanged to return %t, but got: %t - diff: %s", testCase.specChanged, w,
   367  					cmp.Diff(testCase.expected, testCase.actual))
   368  			}
   369  		})
   370  	}
   371  }
   372  
   373  func TestRemovePriorityLevelConfiguration(t *testing.T) {
   374  	tests := []struct {
   375  		name           string
   376  		current        *flowcontrolv1.PriorityLevelConfiguration
   377  		bootstrapName  string
   378  		removeExpected bool
   379  	}{
   380  		{
   381  			name:          "no priority level configuration objects exist",
   382  			bootstrapName: "pl1",
   383  			current:       nil,
   384  		},
   385  		{
   386  			name:           "priority level configuration not wanted, auto update is enabled",
   387  			bootstrapName:  "pl0",
   388  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").Object(),
   389  			removeExpected: true,
   390  		},
   391  		{
   392  			name:           "priority level configuration not wanted, auto update is disabled",
   393  			bootstrapName:  "pl0",
   394  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("false").Object(),
   395  			removeExpected: false,
   396  		},
   397  		{
   398  			name:           "priority level configuration not wanted, the auto-update annotation is malformed",
   399  			bootstrapName:  "pl0",
   400  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("invalid").Object(),
   401  			removeExpected: false,
   402  		},
   403  		{
   404  			name:           "priority level configuration wanted, auto update is enabled",
   405  			bootstrapName:  "pl1",
   406  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("true").Object(),
   407  			removeExpected: false,
   408  		},
   409  		{
   410  			name:           "priority level configuration wanted, auto update is disabled",
   411  			bootstrapName:  "pl1",
   412  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("false").Object(),
   413  			removeExpected: false,
   414  		},
   415  		{
   416  			name:           "priority level configuration wanted, the auto-update annotation is malformed",
   417  			bootstrapName:  "pl1",
   418  			current:        newPLConfiguration("pl1").WithAutoUpdateAnnotation("invalid").Object(),
   419  			removeExpected: false,
   420  		},
   421  	}
   422  
   423  	for _, test := range tests {
   424  		t.Run(test.name, func(t *testing.T) {
   425  			client := fake.NewSimpleClientset().FlowcontrolV1().PriorityLevelConfigurations()
   426  			indexer := toolscache.NewIndexer(toolscache.MetaNamespaceKeyFunc, toolscache.Indexers{})
   427  			if test.current != nil {
   428  				client.Create(context.TODO(), test.current, metav1.CreateOptions{})
   429  				indexer.Add(test.current)
   430  			}
   431  
   432  			boot := newPLConfiguration(test.bootstrapName).Object()
   433  			boots := []*flowcontrolv1.PriorityLevelConfiguration{boot}
   434  			ops := NewPriorityLevelConfigurationOps(client, flowcontrollisters.NewPriorityLevelConfigurationLister(indexer))
   435  			err := RemoveUnwantedObjects(context.Background(), ops, boots)
   436  			if err != nil {
   437  				t.Fatalf("Expected no error, but got: %v", err)
   438  			}
   439  
   440  			if test.current == nil {
   441  				return
   442  			}
   443  			_, err = client.Get(context.TODO(), test.current.Name, metav1.GetOptions{})
   444  			switch {
   445  			case test.removeExpected:
   446  				if !apierrors.IsNotFound(err) {
   447  					t.Errorf("Expected error: %q, but got: %v", metav1.StatusReasonNotFound, err)
   448  				}
   449  			default:
   450  				if err != nil {
   451  					t.Errorf("Expected no error, but got: %v", err)
   452  				}
   453  			}
   454  		})
   455  	}
   456  }
   457  
   458  type plBuilder struct {
   459  	object *flowcontrolv1.PriorityLevelConfiguration
   460  }
   461  
   462  func newPLConfiguration(name string) *plBuilder {
   463  	return &plBuilder{
   464  		object: &flowcontrolv1.PriorityLevelConfiguration{
   465  			ObjectMeta: metav1.ObjectMeta{
   466  				Name: name,
   467  			},
   468  		},
   469  	}
   470  }
   471  
   472  func (b *plBuilder) Object() *flowcontrolv1.PriorityLevelConfiguration {
   473  	return b.object
   474  }
   475  
   476  func (b *plBuilder) WithGeneration(value int64) *plBuilder {
   477  	b.object.SetGeneration(value)
   478  	return b
   479  }
   480  
   481  func (b *plBuilder) WithAutoUpdateAnnotation(value string) *plBuilder {
   482  	setAnnotation(b.object, value)
   483  	return b
   484  }
   485  
   486  func (b *plBuilder) WithLimited(nominalConcurrencyShares int32) *plBuilder {
   487  	b.object.Spec.Type = flowcontrolv1.PriorityLevelEnablementLimited
   488  	b.object.Spec.Limited = &flowcontrolv1.LimitedPriorityLevelConfiguration{
   489  		NominalConcurrencyShares: ptr.To(nominalConcurrencyShares),
   490  		LendablePercent:          ptr.To[int32](0),
   491  		LimitResponse: flowcontrolv1.LimitResponse{
   492  			Type: flowcontrolv1.LimitResponseTypeReject,
   493  		},
   494  	}
   495  	return b
   496  }
   497  
   498  // must be called after WithLimited
   499  func (b *plBuilder) WithQueuing(queues, handSize, queueLengthLimit int32) *plBuilder {
   500  	limited := b.object.Spec.Limited
   501  	if limited == nil {
   502  		return b
   503  	}
   504  
   505  	limited.LimitResponse.Type = flowcontrolv1.LimitResponseTypeQueue
   506  	limited.LimitResponse.Queuing = &flowcontrolv1.QueuingConfiguration{
   507  		Queues:           queues,
   508  		HandSize:         handSize,
   509  		QueueLengthLimit: queueLengthLimit,
   510  	}
   511  
   512  	return b
   513  }