mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			625 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			625 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build linux
 | |
| 
 | |
| /*
 | |
| Copyright 2015 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package cm
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"k8s.io/api/core/v1"
 | |
| 	"k8s.io/apimachinery/pkg/api/resource"
 | |
| 	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | |
| 	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | |
| 	pkgfeatures "k8s.io/kubernetes/pkg/features"
 | |
| )
 | |
| 
 | |
| // getResourceList returns a ResourceList with the
 | |
| // specified cpu and memory resource values
 | |
| func getResourceList(cpu, memory string) v1.ResourceList {
 | |
| 	res := v1.ResourceList{}
 | |
| 	if cpu != "" {
 | |
| 		res[v1.ResourceCPU] = resource.MustParse(cpu)
 | |
| 	}
 | |
| 	if memory != "" {
 | |
| 		res[v1.ResourceMemory] = resource.MustParse(memory)
 | |
| 	}
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // getResourceRequirements returns a ResourceRequirements object
 | |
| func getResourceRequirements(requests, limits v1.ResourceList) v1.ResourceRequirements {
 | |
| 	res := v1.ResourceRequirements{}
 | |
| 	res.Requests = requests
 | |
| 	res.Limits = limits
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| func TestResourceConfigForPod(t *testing.T) {
 | |
| 	defaultQuotaPeriod := uint64(100 * time.Millisecond / time.Microsecond)
 | |
| 	tunedQuotaPeriod := uint64(5 * time.Millisecond / time.Microsecond)
 | |
| 
 | |
| 	minShares := uint64(MinShares)
 | |
| 	burstableShares := MilliCPUToShares(100)
 | |
| 	memoryQuantity := resource.MustParse("200Mi")
 | |
| 	burstableMemory := memoryQuantity.Value()
 | |
| 	burstablePartialShares := MilliCPUToShares(200)
 | |
| 	burstableQuota := MilliCPUToQuota(200, int64(defaultQuotaPeriod))
 | |
| 	guaranteedShares := MilliCPUToShares(100)
 | |
| 	guaranteedQuota := MilliCPUToQuota(100, int64(defaultQuotaPeriod))
 | |
| 	guaranteedTunedQuota := MilliCPUToQuota(100, int64(tunedQuotaPeriod))
 | |
| 	memoryQuantity = resource.MustParse("100Mi")
 | |
| 	cpuNoLimit := int64(-1)
 | |
| 	guaranteedMemory := memoryQuantity.Value()
 | |
| 	testCases := map[string]struct {
 | |
| 		pod              *v1.Pod
 | |
| 		expected         *ResourceConfig
 | |
| 		enforceCPULimits bool
 | |
| 		quotaPeriod      uint64
 | |
| 	}{
 | |
| 		"besteffort": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("", ""), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &minShares},
 | |
| 		},
 | |
| 		"burstable-no-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares},
 | |
| 		},
 | |
| 		"burstable-with-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &burstableQuota, CpuPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-with-limits-no-cpu-enforcement": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &cpuNoLimit, CpuPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-partial-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstablePartialShares},
 | |
| 		},
 | |
| 		"burstable-with-limits-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &burstableQuota, CpuPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-with-limits-no-cpu-enforcement-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &cpuNoLimit, CpuPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-partial-limits-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstablePartialShares},
 | |
| 		},
 | |
| 		"guaranteed": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &guaranteedQuota, CpuPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-no-cpu-enforcement": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &cpuNoLimit, CpuPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &guaranteedTunedQuota, CpuPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-no-cpu-enforcement-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &cpuNoLimit, CpuPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for testName, testCase := range testCases {
 | |
| 
 | |
| 		actual := ResourceConfigForPod(testCase.pod, testCase.enforceCPULimits, testCase.quotaPeriod)
 | |
| 
 | |
| 		if !reflect.DeepEqual(actual.CpuPeriod, testCase.expected.CpuPeriod) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu period not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.CpuQuota, testCase.expected.CpuQuota) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu quota not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.CpuShares, testCase.expected.CpuShares) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu shares not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.Memory, testCase.expected.Memory) {
 | |
| 			t.Errorf("unexpected result, test: %v, memory not as expected", testName)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestResourceConfigForPodWithCustomCPUCFSQuotaPeriod(t *testing.T) {
 | |
| 	defaultQuotaPeriod := uint64(100 * time.Millisecond / time.Microsecond)
 | |
| 	tunedQuotaPeriod := uint64(5 * time.Millisecond / time.Microsecond)
 | |
| 	tunedQuota := int64(1 * time.Millisecond / time.Microsecond)
 | |
| 
 | |
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUCFSQuotaPeriod, true)()
 | |
| 
 | |
| 	minShares := uint64(MinShares)
 | |
| 	burstableShares := MilliCPUToShares(100)
 | |
| 	memoryQuantity := resource.MustParse("200Mi")
 | |
| 	burstableMemory := memoryQuantity.Value()
 | |
| 	burstablePartialShares := MilliCPUToShares(200)
 | |
| 	burstableQuota := MilliCPUToQuota(200, int64(defaultQuotaPeriod))
 | |
| 	guaranteedShares := MilliCPUToShares(100)
 | |
| 	guaranteedQuota := MilliCPUToQuota(100, int64(defaultQuotaPeriod))
 | |
| 	guaranteedTunedQuota := MilliCPUToQuota(100, int64(tunedQuotaPeriod))
 | |
| 	memoryQuantity = resource.MustParse("100Mi")
 | |
| 	cpuNoLimit := int64(-1)
 | |
| 	guaranteedMemory := memoryQuantity.Value()
 | |
| 	testCases := map[string]struct {
 | |
| 		pod              *v1.Pod
 | |
| 		expected         *ResourceConfig
 | |
| 		enforceCPULimits bool
 | |
| 		quotaPeriod      uint64
 | |
| 	}{
 | |
| 		"besteffort": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("", ""), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &minShares},
 | |
| 		},
 | |
| 		"burstable-no-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares},
 | |
| 		},
 | |
| 		"burstable-with-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &burstableQuota, CpuPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-with-limits-no-cpu-enforcement": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &cpuNoLimit, CpuPeriod: &defaultQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-partial-limits": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstablePartialShares},
 | |
| 		},
 | |
| 		"burstable-with-limits-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &tunedQuota, CpuPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-with-limits-no-cpu-enforcement-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstableShares, CpuQuota: &cpuNoLimit, CpuPeriod: &tunedQuotaPeriod, Memory: &burstableMemory},
 | |
| 		},
 | |
| 		"burstable-partial-limits-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("200m", "200Mi")),
 | |
| 						},
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("", "")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &burstablePartialShares},
 | |
| 		},
 | |
| 		"guaranteed": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &guaranteedQuota, CpuPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-no-cpu-enforcement": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      defaultQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &cpuNoLimit, CpuPeriod: &defaultQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: true,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &guaranteedTunedQuota, CpuPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 		"guaranteed-no-cpu-enforcement-with-tuned-quota": {
 | |
| 			pod: &v1.Pod{
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			enforceCPULimits: false,
 | |
| 			quotaPeriod:      tunedQuotaPeriod,
 | |
| 			expected:         &ResourceConfig{CpuShares: &guaranteedShares, CpuQuota: &cpuNoLimit, CpuPeriod: &tunedQuotaPeriod, Memory: &guaranteedMemory},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for testName, testCase := range testCases {
 | |
| 
 | |
| 		actual := ResourceConfigForPod(testCase.pod, testCase.enforceCPULimits, testCase.quotaPeriod)
 | |
| 
 | |
| 		if !reflect.DeepEqual(actual.CpuPeriod, testCase.expected.CpuPeriod) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu period not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.CpuQuota, testCase.expected.CpuQuota) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu quota not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.CpuShares, testCase.expected.CpuShares) {
 | |
| 			t.Errorf("unexpected result, test: %v, cpu shares not as expected", testName)
 | |
| 		}
 | |
| 		if !reflect.DeepEqual(actual.Memory, testCase.expected.Memory) {
 | |
| 			t.Errorf("unexpected result, test: %v, memory not as expected", testName)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMilliCPUToQuota(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		input  int64
 | |
| 		quota  int64
 | |
| 		period uint64
 | |
| 	}{
 | |
| 		{
 | |
| 			input:  int64(0),
 | |
| 			quota:  int64(0),
 | |
| 			period: uint64(0),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(5),
 | |
| 			quota:  int64(1000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(9),
 | |
| 			quota:  int64(1000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(10),
 | |
| 			quota:  int64(1000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(200),
 | |
| 			quota:  int64(20000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(500),
 | |
| 			quota:  int64(50000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(1000),
 | |
| 			quota:  int64(100000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 		{
 | |
| 			input:  int64(1500),
 | |
| 			quota:  int64(150000),
 | |
| 			period: uint64(100000),
 | |
| 		},
 | |
| 	}
 | |
| 	for _, testCase := range testCases {
 | |
| 		quota := MilliCPUToQuota(testCase.input, int64(testCase.period))
 | |
| 		if quota != testCase.quota {
 | |
| 			t.Errorf("Input %v and %v, expected quota %v, but got quota %v", testCase.input, testCase.period, testCase.quota, quota)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestHugePageLimits(t *testing.T) {
 | |
| 	Mi := int64(1024 * 1024)
 | |
| 	type inputStruct struct {
 | |
| 		key   string
 | |
| 		input string
 | |
| 	}
 | |
| 
 | |
| 	testCases := []struct {
 | |
| 		name     string
 | |
| 		inputs   []inputStruct
 | |
| 		expected map[int64]int64
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "no valid hugepages",
 | |
| 			inputs: []inputStruct{
 | |
| 				{
 | |
| 					key:   "2Mi",
 | |
| 					input: "128",
 | |
| 				},
 | |
| 			},
 | |
| 			expected: map[int64]int64{},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "2Mi only",
 | |
| 			inputs: []inputStruct{
 | |
| 				{
 | |
| 					key:   v1.ResourceHugePagesPrefix + "2Mi",
 | |
| 					input: "128",
 | |
| 				},
 | |
| 			},
 | |
| 			expected: map[int64]int64{2 * Mi: 128},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "2Mi and 4Mi",
 | |
| 			inputs: []inputStruct{
 | |
| 				{
 | |
| 					key:   v1.ResourceHugePagesPrefix + "2Mi",
 | |
| 					input: "128",
 | |
| 				},
 | |
| 				{
 | |
| 					key:   v1.ResourceHugePagesPrefix + strconv.FormatInt(2*Mi, 10),
 | |
| 					input: "256",
 | |
| 				},
 | |
| 				{
 | |
| 					key:   v1.ResourceHugePagesPrefix + "4Mi",
 | |
| 					input: "512",
 | |
| 				},
 | |
| 				{
 | |
| 					key:   "4Mi",
 | |
| 					input: "1024",
 | |
| 				},
 | |
| 			},
 | |
| 			expected: map[int64]int64{2 * Mi: 384, 4 * Mi: 512},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, testcase := range testCases {
 | |
| 		t.Run(testcase.name, func(t *testing.T) {
 | |
| 			resourceList := v1.ResourceList{}
 | |
| 
 | |
| 			for _, input := range testcase.inputs {
 | |
| 				value, err := resource.ParseQuantity(input.input)
 | |
| 				if err != nil {
 | |
| 					t.Fatalf("error in parsing hugepages, value: %s", input.input)
 | |
| 				} else {
 | |
| 					resourceList[v1.ResourceName(input.key)] = value
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			resultValue := HugePageLimits(resourceList)
 | |
| 
 | |
| 			if !reflect.DeepEqual(testcase.expected, resultValue) {
 | |
| 				t.Errorf("unexpected result, expected: %v, actual: %v", testcase.expected, resultValue)
 | |
| 			}
 | |
| 		})
 | |
| 
 | |
| 	}
 | |
| }
 |