k8s.io/apiserver@v0.31.1/pkg/util/flowcontrol/max_seats_test.go (about)

     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 flowcontrol
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	flowcontrolv1 "k8s.io/api/flowcontrol/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	fqs "k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset"
    26  	"k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/testing/eventclock"
    27  	"k8s.io/apiserver/pkg/util/flowcontrol/metrics"
    28  	"k8s.io/client-go/informers"
    29  	clientsetfake "k8s.io/client-go/kubernetes/fake"
    30  	"k8s.io/utils/ptr"
    31  )
    32  
    33  // Test_GetMaxSeats tests max seats retrieved from MaxSeatsTracker
    34  func Test_GetMaxSeats(t *testing.T) {
    35  	testcases := []struct {
    36  		name             string
    37  		nominalCL        int
    38  		handSize         int32
    39  		expectedMaxSeats uint64
    40  	}{
    41  		{
    42  			name:             "nominalCL=5, handSize=6",
    43  			nominalCL:        5,
    44  			handSize:         6,
    45  			expectedMaxSeats: 1,
    46  		},
    47  		{
    48  			name:             "nominalCL=10, handSize=6",
    49  			nominalCL:        10,
    50  			handSize:         6,
    51  			expectedMaxSeats: 1,
    52  		},
    53  		{
    54  			name:             "nominalCL=15, handSize=6",
    55  			nominalCL:        15,
    56  			handSize:         6,
    57  			expectedMaxSeats: 2,
    58  		},
    59  		{
    60  			name:             "nominalCL=20, handSize=6",
    61  			nominalCL:        20,
    62  			handSize:         6,
    63  			expectedMaxSeats: 3,
    64  		},
    65  		{
    66  			name:             "nominalCL=35, handSize=6",
    67  			nominalCL:        35,
    68  			handSize:         6,
    69  			expectedMaxSeats: 5,
    70  		},
    71  		{
    72  			name:             "nominalCL=100, handSize=6",
    73  			nominalCL:        100,
    74  			handSize:         6,
    75  			expectedMaxSeats: 15,
    76  		},
    77  		{
    78  			name:             "nominalCL=200, handSize=6",
    79  			nominalCL:        200,
    80  			handSize:         6,
    81  			expectedMaxSeats: 30,
    82  		},
    83  		{
    84  			name:             "nominalCL=10, handSize=1",
    85  			nominalCL:        10,
    86  			handSize:         1,
    87  			expectedMaxSeats: 2,
    88  		},
    89  		{
    90  			name:             "nominalCL=100, handSize=20",
    91  			nominalCL:        100,
    92  			handSize:         20,
    93  			expectedMaxSeats: 5,
    94  		},
    95  	}
    96  
    97  	for _, testcase := range testcases {
    98  		t.Run(testcase.name, func(t *testing.T) {
    99  			clientset := clientsetfake.NewSimpleClientset()
   100  			informerFactory := informers.NewSharedInformerFactory(clientset, time.Second)
   101  			flowcontrolClient := clientset.FlowcontrolV1()
   102  			startTime := time.Now()
   103  			clk, _ := eventclock.NewFake(startTime, 0, nil)
   104  			c := newTestableController(TestableConfig{
   105  				Name:              "Controller",
   106  				Clock:             clk,
   107  				InformerFactory:   informerFactory,
   108  				FlowcontrolClient: flowcontrolClient,
   109  				// for the purposes of this test, serverCL ~= nominalCL since there is
   110  				// only 1 PL with large concurrency shares, making mandatory PLs negligible.
   111  				ServerConcurrencyLimit: testcase.nominalCL,
   112  				ReqsGaugeVec:           metrics.PriorityLevelConcurrencyGaugeVec,
   113  				ExecSeatsGaugeVec:      metrics.PriorityLevelExecutionSeatsGaugeVec,
   114  				QueueSetFactory:        fqs.NewQueueSetFactory(clk),
   115  			})
   116  
   117  			testPriorityLevel := &flowcontrolv1.PriorityLevelConfiguration{
   118  				ObjectMeta: metav1.ObjectMeta{
   119  					Name: "test-pl",
   120  				},
   121  				Spec: flowcontrolv1.PriorityLevelConfigurationSpec{
   122  					Type: flowcontrolv1.PriorityLevelEnablementLimited,
   123  					Limited: &flowcontrolv1.LimitedPriorityLevelConfiguration{
   124  						NominalConcurrencyShares: ptr.To(int32(10000)),
   125  						LimitResponse: flowcontrolv1.LimitResponse{
   126  							Queuing: &flowcontrolv1.QueuingConfiguration{
   127  								HandSize: testcase.handSize,
   128  							},
   129  						},
   130  					},
   131  				},
   132  			}
   133  			if _, err := c.digestConfigObjects([]*flowcontrolv1.PriorityLevelConfiguration{testPriorityLevel}, nil); err != nil {
   134  				t.Errorf("unexpected error from digestConfigObjects: %v", err)
   135  			}
   136  			maxSeats := c.GetMaxSeats("test-pl")
   137  			if maxSeats != testcase.expectedMaxSeats {
   138  				t.Errorf("unexpected max seats, got=%d, want=%d", maxSeats, testcase.expectedMaxSeats)
   139  			}
   140  		})
   141  	}
   142  }