...

Source file src/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_static_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/cm/cpumanager

     1  /*
     2  Copyright 2017 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 cpumanager
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    26  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    27  	pkgfeatures "k8s.io/kubernetes/pkg/features"
    28  	"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
    29  	"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
    30  	"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager"
    31  	"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
    32  	"k8s.io/utils/cpuset"
    33  )
    34  
    35  type staticPolicyTest struct {
    36  	description     string
    37  	topo            *topology.CPUTopology
    38  	numReservedCPUs int
    39  	reservedCPUs    *cpuset.CPUSet
    40  	podUID          string
    41  	options         map[string]string
    42  	containerName   string
    43  	stAssignments   state.ContainerCPUAssignments
    44  	stDefaultCPUSet cpuset.CPUSet
    45  	pod             *v1.Pod
    46  	topologyHint    *topologymanager.TopologyHint
    47  	expErr          error
    48  	expCPUAlloc     bool
    49  	expCSet         cpuset.CPUSet
    50  }
    51  
    52  // this is not a real Clone() - hence Pseudo- - because we don't clone some
    53  // objects which are accessed read-only
    54  func (spt staticPolicyTest) PseudoClone() staticPolicyTest {
    55  	return staticPolicyTest{
    56  		description:     spt.description,
    57  		topo:            spt.topo, // accessed in read-only
    58  		numReservedCPUs: spt.numReservedCPUs,
    59  		podUID:          spt.podUID,
    60  		options:         spt.options, // accessed in read-only
    61  		containerName:   spt.containerName,
    62  		stAssignments:   spt.stAssignments.Clone(),
    63  		stDefaultCPUSet: spt.stDefaultCPUSet.Clone(),
    64  		pod:             spt.pod, // accessed in read-only
    65  		expErr:          spt.expErr,
    66  		expCPUAlloc:     spt.expCPUAlloc,
    67  		expCSet:         spt.expCSet.Clone(),
    68  	}
    69  }
    70  
    71  func TestStaticPolicyName(t *testing.T) {
    72  	policy, _ := NewStaticPolicy(topoSingleSocketHT, 1, cpuset.New(), topologymanager.NewFakeManager(), nil)
    73  
    74  	policyName := policy.Name()
    75  	if policyName != "static" {
    76  		t.Errorf("StaticPolicy Name() error. expected: static, returned: %v",
    77  			policyName)
    78  	}
    79  }
    80  
    81  func TestStaticPolicyStart(t *testing.T) {
    82  	testCases := []staticPolicyTest{
    83  		{
    84  			description: "non-corrupted state",
    85  			topo:        topoDualSocketHT,
    86  			stAssignments: state.ContainerCPUAssignments{
    87  				"fakePod": map[string]cpuset.CPUSet{
    88  					"0": cpuset.New(0),
    89  				},
    90  			},
    91  			stDefaultCPUSet: cpuset.New(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
    92  			expCSet:         cpuset.New(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
    93  		},
    94  		{
    95  			description:     "empty cpuset",
    96  			topo:            topoDualSocketHT,
    97  			numReservedCPUs: 1,
    98  			stAssignments:   state.ContainerCPUAssignments{},
    99  			stDefaultCPUSet: cpuset.New(),
   100  			expCSet:         cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   101  		},
   102  		{
   103  			description:     "reserved cores 0 & 6 are not present in available cpuset",
   104  			topo:            topoDualSocketHT,
   105  			numReservedCPUs: 2,
   106  			stAssignments:   state.ContainerCPUAssignments{},
   107  			stDefaultCPUSet: cpuset.New(0, 1),
   108  			expErr:          fmt.Errorf("not all reserved cpus: \"0,6\" are present in defaultCpuSet: \"0-1\""),
   109  		},
   110  		{
   111  			description: "assigned core 2 is still present in available cpuset",
   112  			topo:        topoDualSocketHT,
   113  			stAssignments: state.ContainerCPUAssignments{
   114  				"fakePod": map[string]cpuset.CPUSet{
   115  					"0": cpuset.New(0, 1, 2),
   116  				},
   117  			},
   118  			stDefaultCPUSet: cpuset.New(2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   119  			expErr:          fmt.Errorf("pod: fakePod, container: 0 cpuset: \"0-2\" overlaps with default cpuset \"2-11\""),
   120  		},
   121  		{
   122  			description: "core 12 is not present in topology but is in state cpuset",
   123  			topo:        topoDualSocketHT,
   124  			stAssignments: state.ContainerCPUAssignments{
   125  				"fakePod": map[string]cpuset.CPUSet{
   126  					"0": cpuset.New(0, 1, 2),
   127  					"1": cpuset.New(3, 4),
   128  				},
   129  			},
   130  			stDefaultCPUSet: cpuset.New(5, 6, 7, 8, 9, 10, 11, 12),
   131  			expErr:          fmt.Errorf("current set of available CPUs \"0-11\" doesn't match with CPUs in state \"0-12\""),
   132  		},
   133  		{
   134  			description: "core 11 is present in topology but is not in state cpuset",
   135  			topo:        topoDualSocketHT,
   136  			stAssignments: state.ContainerCPUAssignments{
   137  				"fakePod": map[string]cpuset.CPUSet{
   138  					"0": cpuset.New(0, 1, 2),
   139  					"1": cpuset.New(3, 4),
   140  				},
   141  			},
   142  			stDefaultCPUSet: cpuset.New(5, 6, 7, 8, 9, 10),
   143  			expErr:          fmt.Errorf("current set of available CPUs \"0-11\" doesn't match with CPUs in state \"0-10\""),
   144  		},
   145  	}
   146  	for _, testCase := range testCases {
   147  		t.Run(testCase.description, func(t *testing.T) {
   148  			p, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.New(), topologymanager.NewFakeManager(), nil)
   149  			policy := p.(*staticPolicy)
   150  			st := &mockState{
   151  				assignments:   testCase.stAssignments,
   152  				defaultCPUSet: testCase.stDefaultCPUSet,
   153  			}
   154  			err := policy.Start(st)
   155  			if !reflect.DeepEqual(err, testCase.expErr) {
   156  				t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
   157  					testCase.description, testCase.expErr, err)
   158  			}
   159  			if err != nil {
   160  				return
   161  			}
   162  
   163  			if !testCase.stDefaultCPUSet.IsEmpty() {
   164  				for cpuid := 1; cpuid < policy.topology.NumCPUs; cpuid++ {
   165  					if !st.defaultCPUSet.Contains(cpuid) {
   166  						t.Errorf("StaticPolicy Start() error. expected cpuid %d to be present in defaultCPUSet", cpuid)
   167  					}
   168  				}
   169  			}
   170  			if !st.GetDefaultCPUSet().Equals(testCase.expCSet) {
   171  				t.Errorf("State CPUSet is different than expected. Have %q wants: %q", st.GetDefaultCPUSet(),
   172  					testCase.expCSet)
   173  			}
   174  
   175  		})
   176  	}
   177  }
   178  
   179  func TestStaticPolicyAdd(t *testing.T) {
   180  	var largeTopoCPUids []int
   181  	var largeTopoSock0CPUids []int
   182  	var largeTopoSock1CPUids []int
   183  	largeTopo := *topoQuadSocketFourWayHT
   184  	for cpuid, val := range largeTopo.CPUDetails {
   185  		largeTopoCPUids = append(largeTopoCPUids, cpuid)
   186  		if val.SocketID == 0 {
   187  			largeTopoSock0CPUids = append(largeTopoSock0CPUids, cpuid)
   188  		} else if val.SocketID == 1 {
   189  			largeTopoSock1CPUids = append(largeTopoSock1CPUids, cpuid)
   190  		}
   191  	}
   192  	largeTopoCPUSet := cpuset.New(largeTopoCPUids...)
   193  	largeTopoSock0CPUSet := cpuset.New(largeTopoSock0CPUids...)
   194  	largeTopoSock1CPUSet := cpuset.New(largeTopoSock1CPUids...)
   195  
   196  	// these are the cases which must behave the same regardless the policy options.
   197  	// So we will permutate the options to ensure this holds true.
   198  
   199  	optionsInsensitiveTestCases := []staticPolicyTest{
   200  		{
   201  			description:     "GuPodMultipleCores, SingleSocketHT, ExpectAllocOneCore",
   202  			topo:            topoSingleSocketHT,
   203  			numReservedCPUs: 1,
   204  			stAssignments: state.ContainerCPUAssignments{
   205  				"fakePod": map[string]cpuset.CPUSet{
   206  					"fakeContainer100": cpuset.New(2, 3, 6, 7),
   207  				},
   208  			},
   209  			stDefaultCPUSet: cpuset.New(0, 1, 4, 5),
   210  			pod:             makePod("fakePod", "fakeContainer3", "2000m", "2000m"),
   211  			expErr:          nil,
   212  			expCPUAlloc:     true,
   213  			expCSet:         cpuset.New(1, 5),
   214  		},
   215  		{
   216  			description:     "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocket",
   217  			topo:            topoDualSocketHT,
   218  			numReservedCPUs: 1,
   219  			stAssignments: state.ContainerCPUAssignments{
   220  				"fakePod": map[string]cpuset.CPUSet{
   221  					"fakeContainer100": cpuset.New(2),
   222  				},
   223  			},
   224  			stDefaultCPUSet: cpuset.New(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   225  			pod:             makePod("fakePod", "fakeContainer3", "6000m", "6000m"),
   226  			expErr:          nil,
   227  			expCPUAlloc:     true,
   228  			expCSet:         cpuset.New(1, 3, 5, 7, 9, 11),
   229  		},
   230  		{
   231  			description:     "GuPodMultipleCores, DualSocketHT, ExpectAllocThreeCores",
   232  			topo:            topoDualSocketHT,
   233  			numReservedCPUs: 1,
   234  			stAssignments: state.ContainerCPUAssignments{
   235  				"fakePod": map[string]cpuset.CPUSet{
   236  					"fakeContainer100": cpuset.New(1, 5),
   237  				},
   238  			},
   239  			stDefaultCPUSet: cpuset.New(0, 2, 3, 4, 6, 7, 8, 9, 10, 11),
   240  			pod:             makePod("fakePod", "fakeContainer3", "6000m", "6000m"),
   241  			expErr:          nil,
   242  			expCPUAlloc:     true,
   243  			expCSet:         cpuset.New(2, 3, 4, 8, 9, 10),
   244  		},
   245  		{
   246  			description:     "GuPodMultipleCores, DualSocketNoHT, ExpectAllocOneSocket",
   247  			topo:            topoDualSocketNoHT,
   248  			numReservedCPUs: 1,
   249  			stAssignments: state.ContainerCPUAssignments{
   250  				"fakePod": map[string]cpuset.CPUSet{
   251  					"fakeContainer100": cpuset.New(),
   252  				},
   253  			},
   254  			stDefaultCPUSet: cpuset.New(0, 1, 3, 4, 5, 6, 7),
   255  			pod:             makePod("fakePod", "fakeContainer1", "4000m", "4000m"),
   256  			expErr:          nil,
   257  			expCPUAlloc:     true,
   258  			expCSet:         cpuset.New(4, 5, 6, 7),
   259  		},
   260  		{
   261  			description:     "GuPodMultipleCores, DualSocketNoHT, ExpectAllocFourCores",
   262  			topo:            topoDualSocketNoHT,
   263  			numReservedCPUs: 1,
   264  			stAssignments: state.ContainerCPUAssignments{
   265  				"fakePod": map[string]cpuset.CPUSet{
   266  					"fakeContainer100": cpuset.New(4, 5),
   267  				},
   268  			},
   269  			stDefaultCPUSet: cpuset.New(0, 1, 3, 6, 7),
   270  			pod:             makePod("fakePod", "fakeContainer1", "4000m", "4000m"),
   271  			expErr:          nil,
   272  			expCPUAlloc:     true,
   273  			expCSet:         cpuset.New(1, 3, 6, 7),
   274  		},
   275  		{
   276  			description:     "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocketOneCore",
   277  			topo:            topoDualSocketHT,
   278  			numReservedCPUs: 1,
   279  			stAssignments: state.ContainerCPUAssignments{
   280  				"fakePod": map[string]cpuset.CPUSet{
   281  					"fakeContainer100": cpuset.New(2),
   282  				},
   283  			},
   284  			stDefaultCPUSet: cpuset.New(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   285  			pod:             makePod("fakePod", "fakeContainer3", "8000m", "8000m"),
   286  			expErr:          nil,
   287  			expCPUAlloc:     true,
   288  			expCSet:         cpuset.New(1, 3, 4, 5, 7, 9, 10, 11),
   289  		},
   290  		{
   291  			description:     "NonGuPod, SingleSocketHT, NoAlloc",
   292  			topo:            topoSingleSocketHT,
   293  			numReservedCPUs: 1,
   294  			stAssignments:   state.ContainerCPUAssignments{},
   295  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   296  			pod:             makePod("fakePod", "fakeContainer1", "1000m", "2000m"),
   297  			expErr:          nil,
   298  			expCPUAlloc:     false,
   299  			expCSet:         cpuset.New(),
   300  		},
   301  		{
   302  			description:     "GuPodNonIntegerCore, SingleSocketHT, NoAlloc",
   303  			topo:            topoSingleSocketHT,
   304  			numReservedCPUs: 1,
   305  			stAssignments:   state.ContainerCPUAssignments{},
   306  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   307  			pod:             makePod("fakePod", "fakeContainer4", "977m", "977m"),
   308  			expErr:          nil,
   309  			expCPUAlloc:     false,
   310  			expCSet:         cpuset.New(),
   311  		},
   312  		{
   313  			// All the CPUs from Socket 0 are available. Some CPUs from each
   314  			// Socket have been already assigned.
   315  			// Expect all CPUs from Socket 0.
   316  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocSock0",
   317  			topo:        topoQuadSocketFourWayHT,
   318  			stAssignments: state.ContainerCPUAssignments{
   319  				"fakePod": map[string]cpuset.CPUSet{
   320  					"fakeContainer100": cpuset.New(3, 11, 4, 5, 6, 7),
   321  				},
   322  			},
   323  			stDefaultCPUSet: largeTopoCPUSet.Difference(cpuset.New(3, 11, 4, 5, 6, 7)),
   324  			pod:             makePod("fakePod", "fakeContainer5", "72000m", "72000m"),
   325  			expErr:          nil,
   326  			expCPUAlloc:     true,
   327  			expCSet:         largeTopoSock0CPUSet,
   328  		},
   329  		{
   330  			// Only 2 full cores from three Sockets and some partial cores are available.
   331  			// Expect CPUs from the 2 full cores available from the three Sockets.
   332  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllFullCoresFromThreeSockets",
   333  			topo:        topoQuadSocketFourWayHT,
   334  			stAssignments: state.ContainerCPUAssignments{
   335  				"fakePod": map[string]cpuset.CPUSet{
   336  					"fakeContainer100": largeTopoCPUSet.Difference(cpuset.New(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51,
   337  						53, 173, 113, 233, 54, 61)),
   338  				},
   339  			},
   340  			stDefaultCPUSet: cpuset.New(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51, 53, 173, 113, 233, 54, 61),
   341  			pod:             makePod("fakePod", "fakeCcontainer5", "12000m", "12000m"),
   342  			expErr:          nil,
   343  			expCPUAlloc:     true,
   344  			expCSet:         cpuset.New(1, 25, 13, 38, 11, 35, 23, 48, 53, 173, 113, 233),
   345  		},
   346  		{
   347  			// All CPUs from Socket 1, 1 full core and some partial cores are available.
   348  			// Expect all CPUs from Socket 1 and the hyper-threads from the full core.
   349  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllSock1+FullCore",
   350  			topo:        topoQuadSocketFourWayHT,
   351  			stAssignments: state.ContainerCPUAssignments{
   352  				"fakePod": map[string]cpuset.CPUSet{
   353  					"fakeContainer100": largeTopoCPUSet.Difference(largeTopoSock1CPUSet.Union(cpuset.New(10, 34, 22, 47, 53,
   354  						173, 61, 181, 108, 228, 115, 235))),
   355  				},
   356  			},
   357  			stDefaultCPUSet: largeTopoSock1CPUSet.Union(cpuset.New(10, 34, 22, 47, 53, 173, 61, 181, 108, 228,
   358  				115, 235)),
   359  			pod:         makePod("fakePod", "fakeContainer5", "76000m", "76000m"),
   360  			expErr:      nil,
   361  			expCPUAlloc: true,
   362  			expCSet:     largeTopoSock1CPUSet.Union(cpuset.New(10, 34, 22, 47)),
   363  		},
   364  	}
   365  
   366  	// testcases for the default behaviour of the policy.
   367  	defaultOptionsTestCases := []staticPolicyTest{
   368  		{
   369  			description:     "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
   370  			topo:            topoSingleSocketHT,
   371  			numReservedCPUs: 1,
   372  			stAssignments:   state.ContainerCPUAssignments{},
   373  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   374  			pod:             makePod("fakePod", "fakeContainer2", "1000m", "1000m"),
   375  			expErr:          nil,
   376  			expCPUAlloc:     true,
   377  			expCSet:         cpuset.New(4), // expect sibling of partial core
   378  		},
   379  		{
   380  			// Only partial cores are available in the entire system.
   381  			// Expect allocation of all the CPUs from the partial cores.
   382  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocCPUs",
   383  			topo:        topoQuadSocketFourWayHT,
   384  			stAssignments: state.ContainerCPUAssignments{
   385  				"fakePod": map[string]cpuset.CPUSet{
   386  					"fakeContainer100": largeTopoCPUSet.Difference(cpuset.New(10, 11, 53, 37, 55, 67, 52)),
   387  				},
   388  			},
   389  			stDefaultCPUSet: cpuset.New(10, 11, 53, 67, 52),
   390  			pod:             makePod("fakePod", "fakeContainer5", "5000m", "5000m"),
   391  			expErr:          nil,
   392  			expCPUAlloc:     true,
   393  			expCSet:         cpuset.New(10, 11, 53, 67, 52),
   394  		},
   395  		{
   396  			description:     "GuPodSingleCore, SingleSocketHT, ExpectError",
   397  			topo:            topoSingleSocketHT,
   398  			numReservedCPUs: 1,
   399  			stAssignments:   state.ContainerCPUAssignments{},
   400  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   401  			pod:             makePod("fakePod", "fakeContainer2", "8000m", "8000m"),
   402  			expErr:          fmt.Errorf("not enough cpus available to satisfy request: requested=8, available=7"),
   403  			expCPUAlloc:     false,
   404  			expCSet:         cpuset.New(),
   405  		},
   406  		{
   407  			description:     "GuPodMultipleCores, SingleSocketHT, ExpectSameAllocation",
   408  			topo:            topoSingleSocketHT,
   409  			numReservedCPUs: 1,
   410  			stAssignments: state.ContainerCPUAssignments{
   411  				"fakePod": map[string]cpuset.CPUSet{
   412  					"fakeContainer3": cpuset.New(2, 3, 6, 7),
   413  				},
   414  			},
   415  			stDefaultCPUSet: cpuset.New(0, 1, 4, 5),
   416  			pod:             makePod("fakePod", "fakeContainer3", "4000m", "4000m"),
   417  			expErr:          nil,
   418  			expCPUAlloc:     true,
   419  			expCSet:         cpuset.New(2, 3, 6, 7),
   420  		},
   421  		{
   422  			description:     "GuPodMultipleCores, DualSocketHT, NoAllocExpectError",
   423  			topo:            topoDualSocketHT,
   424  			numReservedCPUs: 1,
   425  			stAssignments: state.ContainerCPUAssignments{
   426  				"fakePod": map[string]cpuset.CPUSet{
   427  					"fakeContainer100": cpuset.New(1, 2, 3),
   428  				},
   429  			},
   430  			stDefaultCPUSet: cpuset.New(0, 4, 5, 6, 7, 8, 9, 10, 11),
   431  			pod:             makePod("fakePod", "fakeContainer5", "10000m", "10000m"),
   432  			expErr:          fmt.Errorf("not enough cpus available to satisfy request: requested=10, available=8"),
   433  			expCPUAlloc:     false,
   434  			expCSet:         cpuset.New(),
   435  		},
   436  		{
   437  			description:     "GuPodMultipleCores, SingleSocketHT, NoAllocExpectError",
   438  			topo:            topoSingleSocketHT,
   439  			numReservedCPUs: 1,
   440  			stAssignments: state.ContainerCPUAssignments{
   441  				"fakePod": map[string]cpuset.CPUSet{
   442  					"fakeContainer100": cpuset.New(1, 2, 3, 4, 5, 6),
   443  				},
   444  			},
   445  			stDefaultCPUSet: cpuset.New(0, 7),
   446  			pod:             makePod("fakePod", "fakeContainer5", "2000m", "2000m"),
   447  			expErr:          fmt.Errorf("not enough cpus available to satisfy request: requested=2, available=1"),
   448  			expCPUAlloc:     false,
   449  			expCSet:         cpuset.New(),
   450  		},
   451  		{
   452  			// Only 7 CPUs are available.
   453  			// Pod requests 76 cores.
   454  			// Error is expected since available CPUs are less than the request.
   455  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, NoAlloc",
   456  			topo:        topoQuadSocketFourWayHT,
   457  			stAssignments: state.ContainerCPUAssignments{
   458  				"fakePod": map[string]cpuset.CPUSet{
   459  					"fakeContainer100": largeTopoCPUSet.Difference(cpuset.New(10, 11, 53, 37, 55, 67, 52)),
   460  				},
   461  			},
   462  			stDefaultCPUSet: cpuset.New(10, 11, 53, 37, 55, 67, 52),
   463  			pod:             makePod("fakePod", "fakeContainer5", "76000m", "76000m"),
   464  			expErr:          fmt.Errorf("not enough cpus available to satisfy request: requested=76, available=7"),
   465  			expCPUAlloc:     false,
   466  			expCSet:         cpuset.New(),
   467  		},
   468  	}
   469  
   470  	// testcases for the FullPCPUsOnlyOption
   471  	smtalignOptionTestCases := []staticPolicyTest{
   472  		{
   473  			description: "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
   474  			topo:        topoSingleSocketHT,
   475  			options: map[string]string{
   476  				FullPCPUsOnlyOption: "true",
   477  			},
   478  			numReservedCPUs: 1,
   479  			stAssignments:   state.ContainerCPUAssignments{},
   480  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   481  			pod:             makePod("fakePod", "fakeContainer2", "1000m", "1000m"),
   482  			expErr:          SMTAlignmentError{RequestedCPUs: 1, CpusPerCore: 2},
   483  			expCPUAlloc:     false,
   484  			expCSet:         cpuset.New(), // reject allocation of sibling of partial core
   485  		},
   486  		{
   487  			// test SMT-level != 2 - which is the default on x86_64
   488  			description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocOneCPUs",
   489  			topo:        topoQuadSocketFourWayHT,
   490  			options: map[string]string{
   491  				FullPCPUsOnlyOption: "true",
   492  			},
   493  			numReservedCPUs: 8,
   494  			stAssignments:   state.ContainerCPUAssignments{},
   495  			stDefaultCPUSet: largeTopoCPUSet,
   496  			pod:             makePod("fakePod", "fakeContainer15", "15000m", "15000m"),
   497  			expErr:          SMTAlignmentError{RequestedCPUs: 15, CpusPerCore: 4},
   498  			expCPUAlloc:     false,
   499  			expCSet:         cpuset.New(),
   500  		},
   501  		{
   502  			description: "GuPodManyCores, topoDualSocketHT, ExpectDoNotAllocPartialCPU",
   503  			topo:        topoDualSocketHT,
   504  			options: map[string]string{
   505  				FullPCPUsOnlyOption: "true",
   506  			},
   507  			numReservedCPUs: 2,
   508  			reservedCPUs:    newCPUSetPtr(1, 6),
   509  			stAssignments:   state.ContainerCPUAssignments{},
   510  			stDefaultCPUSet: cpuset.New(0, 2, 3, 4, 5, 7, 8, 9, 10, 11),
   511  			pod:             makePod("fakePod", "fakeContainerBug113537_1", "10000m", "10000m"),
   512  			expErr:          SMTAlignmentError{RequestedCPUs: 10, CpusPerCore: 2, AvailablePhysicalCPUs: 8},
   513  			expCPUAlloc:     false,
   514  			expCSet:         cpuset.New(),
   515  		},
   516  		{
   517  			description: "GuPodManyCores, topoDualSocketHT, AutoReserve, ExpectAllocAllCPUs",
   518  			topo:        topoDualSocketHT,
   519  			options: map[string]string{
   520  				FullPCPUsOnlyOption: "true",
   521  			},
   522  			numReservedCPUs: 2,
   523  			stAssignments:   state.ContainerCPUAssignments{},
   524  			stDefaultCPUSet: cpuset.New(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
   525  			pod:             makePod("fakePod", "fakeContainerBug113537_2", "10000m", "10000m"),
   526  			expErr:          nil,
   527  			expCPUAlloc:     true,
   528  			expCSet:         cpuset.New(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
   529  		},
   530  		{
   531  			description: "GuPodManyCores, topoDualSocketHT, ExpectAllocAllCPUs",
   532  			topo:        topoDualSocketHT,
   533  			options: map[string]string{
   534  				FullPCPUsOnlyOption: "true",
   535  			},
   536  			numReservedCPUs: 2,
   537  			reservedCPUs:    newCPUSetPtr(0, 6),
   538  			stAssignments:   state.ContainerCPUAssignments{},
   539  			stDefaultCPUSet: cpuset.New(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
   540  			pod:             makePod("fakePod", "fakeContainerBug113537_2", "10000m", "10000m"),
   541  			expErr:          nil,
   542  			expCPUAlloc:     true,
   543  			expCSet:         cpuset.New(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
   544  		},
   545  	}
   546  	newNUMAAffinity := func(bits ...int) bitmask.BitMask {
   547  		affinity, _ := bitmask.NewBitMask(bits...)
   548  		return affinity
   549  	}
   550  	alignBySocketOptionTestCases := []staticPolicyTest{
   551  		{
   552  			description: "Align by socket: true, cpu's within same socket of numa in hint are part of allocation",
   553  			topo:        topoDualSocketMultiNumaPerSocketHT,
   554  			options: map[string]string{
   555  				AlignBySocketOption: "true",
   556  			},
   557  			numReservedCPUs: 1,
   558  			stAssignments:   state.ContainerCPUAssignments{},
   559  			stDefaultCPUSet: cpuset.New(2, 11, 21, 22),
   560  			pod:             makePod("fakePod", "fakeContainer2", "2000m", "2000m"),
   561  			topologyHint:    &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(0, 2), Preferred: true},
   562  			expErr:          nil,
   563  			expCPUAlloc:     true,
   564  			expCSet:         cpuset.New(2, 11),
   565  		},
   566  		{
   567  			description: "Align by socket: false, cpu's are taken strictly from NUMA nodes in hint",
   568  			topo:        topoDualSocketMultiNumaPerSocketHT,
   569  			options: map[string]string{
   570  				AlignBySocketOption: "false",
   571  			},
   572  			numReservedCPUs: 1,
   573  			stAssignments:   state.ContainerCPUAssignments{},
   574  			stDefaultCPUSet: cpuset.New(2, 11, 21, 22),
   575  			pod:             makePod("fakePod", "fakeContainer2", "2000m", "2000m"),
   576  			topologyHint:    &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(0, 2), Preferred: true},
   577  			expErr:          nil,
   578  			expCPUAlloc:     true,
   579  			expCSet:         cpuset.New(2, 21),
   580  		},
   581  	}
   582  
   583  	for _, testCase := range optionsInsensitiveTestCases {
   584  		for _, options := range []map[string]string{
   585  			nil,
   586  			{
   587  				FullPCPUsOnlyOption: "true",
   588  			},
   589  		} {
   590  			tCase := testCase.PseudoClone()
   591  			tCase.description = fmt.Sprintf("options=%v %s", options, testCase.description)
   592  			tCase.options = options
   593  			runStaticPolicyTestCase(t, tCase)
   594  		}
   595  	}
   596  
   597  	for _, testCase := range defaultOptionsTestCases {
   598  		runStaticPolicyTestCase(t, testCase)
   599  	}
   600  	for _, testCase := range smtalignOptionTestCases {
   601  		runStaticPolicyTestCase(t, testCase)
   602  	}
   603  	for _, testCase := range alignBySocketOptionTestCases {
   604  		runStaticPolicyTestCaseWithFeatureGate(t, testCase)
   605  	}
   606  }
   607  
   608  func runStaticPolicyTestCase(t *testing.T, testCase staticPolicyTest) {
   609  	tm := topologymanager.NewFakeManager()
   610  	if testCase.topologyHint != nil {
   611  		tm = topologymanager.NewFakeManagerWithHint(testCase.topologyHint)
   612  	}
   613  	cpus := cpuset.New()
   614  	if testCase.reservedCPUs != nil {
   615  		cpus = testCase.reservedCPUs.Clone()
   616  	}
   617  	policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpus, tm, testCase.options)
   618  
   619  	st := &mockState{
   620  		assignments:   testCase.stAssignments,
   621  		defaultCPUSet: testCase.stDefaultCPUSet,
   622  	}
   623  
   624  	container := &testCase.pod.Spec.Containers[0]
   625  	err := policy.Allocate(st, testCase.pod, container)
   626  	if !reflect.DeepEqual(err, testCase.expErr) {
   627  		t.Errorf("StaticPolicy Allocate() error (%v). expected add error: %q but got: %q",
   628  			testCase.description, testCase.expErr, err)
   629  	}
   630  
   631  	if testCase.expCPUAlloc {
   632  		cset, found := st.assignments[string(testCase.pod.UID)][container.Name]
   633  		if !found {
   634  			t.Errorf("StaticPolicy Allocate() error (%v). expected container %v to be present in assignments %v",
   635  				testCase.description, container.Name, st.assignments)
   636  		}
   637  
   638  		if !reflect.DeepEqual(cset, testCase.expCSet) {
   639  			t.Errorf("StaticPolicy Allocate() error (%v). expected cpuset %v but got %v",
   640  				testCase.description, testCase.expCSet, cset)
   641  		}
   642  
   643  		if !cset.Intersection(st.defaultCPUSet).IsEmpty() {
   644  			t.Errorf("StaticPolicy Allocate() error (%v). expected cpuset %v to be disoint from the shared cpuset %v",
   645  				testCase.description, cset, st.defaultCPUSet)
   646  		}
   647  	}
   648  
   649  	if !testCase.expCPUAlloc {
   650  		_, found := st.assignments[string(testCase.pod.UID)][container.Name]
   651  		if found {
   652  			t.Errorf("StaticPolicy Allocate() error (%v). Did not expect container %v to be present in assignments %v",
   653  				testCase.description, container.Name, st.assignments)
   654  		}
   655  	}
   656  }
   657  
   658  func runStaticPolicyTestCaseWithFeatureGate(t *testing.T, testCase staticPolicyTest) {
   659  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true)()
   660  	runStaticPolicyTestCase(t, testCase)
   661  }
   662  
   663  func TestStaticPolicyReuseCPUs(t *testing.T) {
   664  	testCases := []struct {
   665  		staticPolicyTest
   666  		expCSetAfterAlloc  cpuset.CPUSet
   667  		expCSetAfterRemove cpuset.CPUSet
   668  	}{
   669  		{
   670  			staticPolicyTest: staticPolicyTest{
   671  				description: "SingleSocketHT, DeAllocOneInitContainer",
   672  				topo:        topoSingleSocketHT,
   673  				pod: makeMultiContainerPod(
   674  					[]struct{ request, limit string }{
   675  						{"4000m", "4000m"}}, // 0, 1, 4, 5
   676  					[]struct{ request, limit string }{
   677  						{"2000m", "2000m"}}), // 0, 4
   678  				containerName:   "initContainer-0",
   679  				stAssignments:   state.ContainerCPUAssignments{},
   680  				stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   681  			},
   682  			expCSetAfterAlloc:  cpuset.New(2, 3, 6, 7),
   683  			expCSetAfterRemove: cpuset.New(1, 2, 3, 5, 6, 7),
   684  		},
   685  	}
   686  
   687  	for _, testCase := range testCases {
   688  		policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.New(), topologymanager.NewFakeManager(), nil)
   689  
   690  		st := &mockState{
   691  			assignments:   testCase.stAssignments,
   692  			defaultCPUSet: testCase.stDefaultCPUSet,
   693  		}
   694  		pod := testCase.pod
   695  
   696  		// allocate
   697  		for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
   698  			policy.Allocate(st, pod, &container)
   699  		}
   700  		if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSetAfterAlloc) {
   701  			t.Errorf("StaticPolicy Allocate() error (%v). expected default cpuset %v but got %v",
   702  				testCase.description, testCase.expCSetAfterAlloc, st.defaultCPUSet)
   703  		}
   704  
   705  		// remove
   706  		policy.RemoveContainer(st, string(pod.UID), testCase.containerName)
   707  
   708  		if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSetAfterRemove) {
   709  			t.Errorf("StaticPolicy RemoveContainer() error (%v). expected default cpuset %v but got %v",
   710  				testCase.description, testCase.expCSetAfterRemove, st.defaultCPUSet)
   711  		}
   712  		if _, found := st.assignments[string(pod.UID)][testCase.containerName]; found {
   713  			t.Errorf("StaticPolicy RemoveContainer() error (%v). expected (pod %v, container %v) not be in assignments %v",
   714  				testCase.description, testCase.podUID, testCase.containerName, st.assignments)
   715  		}
   716  	}
   717  }
   718  
   719  func TestStaticPolicyDoNotReuseCPUs(t *testing.T) {
   720  	testCases := []struct {
   721  		staticPolicyTest
   722  		expCSetAfterAlloc cpuset.CPUSet
   723  	}{
   724  		{
   725  			staticPolicyTest: staticPolicyTest{
   726  				description: "SingleSocketHT, Don't reuse CPUs of a restartable init container",
   727  				topo:        topoSingleSocketHT,
   728  				pod: makeMultiContainerPodWithOptions(
   729  					[]*containerOptions{
   730  						{request: "4000m", limit: "4000m", restartPolicy: v1.ContainerRestartPolicyAlways}}, // 0, 1, 4, 5
   731  					[]*containerOptions{
   732  						{request: "2000m", limit: "2000m"}}), // 2, 6
   733  				stAssignments:   state.ContainerCPUAssignments{},
   734  				stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   735  			},
   736  			expCSetAfterAlloc: cpuset.New(3, 7),
   737  		},
   738  	}
   739  
   740  	for _, testCase := range testCases {
   741  		policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.New(), topologymanager.NewFakeManager(), nil)
   742  
   743  		st := &mockState{
   744  			assignments:   testCase.stAssignments,
   745  			defaultCPUSet: testCase.stDefaultCPUSet,
   746  		}
   747  		pod := testCase.pod
   748  
   749  		// allocate
   750  		for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
   751  			err := policy.Allocate(st, pod, &container)
   752  			if err != nil {
   753  				t.Errorf("StaticPolicy Allocate() error (%v). expected no error but got %v",
   754  					testCase.description, err)
   755  			}
   756  		}
   757  		if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSetAfterAlloc) {
   758  			t.Errorf("StaticPolicy Allocate() error (%v). expected default cpuset %v but got %v",
   759  				testCase.description, testCase.expCSetAfterAlloc, st.defaultCPUSet)
   760  		}
   761  	}
   762  }
   763  
   764  func TestStaticPolicyRemove(t *testing.T) {
   765  	testCases := []staticPolicyTest{
   766  		{
   767  			description:   "SingleSocketHT, DeAllocOneContainer",
   768  			topo:          topoSingleSocketHT,
   769  			podUID:        "fakePod",
   770  			containerName: "fakeContainer1",
   771  			stAssignments: state.ContainerCPUAssignments{
   772  				"fakePod": map[string]cpuset.CPUSet{
   773  					"fakeContainer1": cpuset.New(1, 2, 3),
   774  				},
   775  			},
   776  			stDefaultCPUSet: cpuset.New(4, 5, 6, 7),
   777  			expCSet:         cpuset.New(1, 2, 3, 4, 5, 6, 7),
   778  		},
   779  		{
   780  			description:   "SingleSocketHT, DeAllocOneContainer, BeginEmpty",
   781  			topo:          topoSingleSocketHT,
   782  			podUID:        "fakePod",
   783  			containerName: "fakeContainer1",
   784  			stAssignments: state.ContainerCPUAssignments{
   785  				"fakePod": map[string]cpuset.CPUSet{
   786  					"fakeContainer1": cpuset.New(1, 2, 3),
   787  					"fakeContainer2": cpuset.New(4, 5, 6, 7),
   788  				},
   789  			},
   790  			stDefaultCPUSet: cpuset.New(),
   791  			expCSet:         cpuset.New(1, 2, 3),
   792  		},
   793  		{
   794  			description:   "SingleSocketHT, DeAllocTwoContainer",
   795  			topo:          topoSingleSocketHT,
   796  			podUID:        "fakePod",
   797  			containerName: "fakeContainer1",
   798  			stAssignments: state.ContainerCPUAssignments{
   799  				"fakePod": map[string]cpuset.CPUSet{
   800  					"fakeContainer1": cpuset.New(1, 3, 5),
   801  					"fakeContainer2": cpuset.New(2, 4),
   802  				},
   803  			},
   804  			stDefaultCPUSet: cpuset.New(6, 7),
   805  			expCSet:         cpuset.New(1, 3, 5, 6, 7),
   806  		},
   807  		{
   808  			description:   "SingleSocketHT, NoDeAlloc",
   809  			topo:          topoSingleSocketHT,
   810  			podUID:        "fakePod",
   811  			containerName: "fakeContainer2",
   812  			stAssignments: state.ContainerCPUAssignments{
   813  				"fakePod": map[string]cpuset.CPUSet{
   814  					"fakeContainer1": cpuset.New(1, 3, 5),
   815  				},
   816  			},
   817  			stDefaultCPUSet: cpuset.New(2, 4, 6, 7),
   818  			expCSet:         cpuset.New(2, 4, 6, 7),
   819  		},
   820  	}
   821  
   822  	for _, testCase := range testCases {
   823  		policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.New(), topologymanager.NewFakeManager(), nil)
   824  
   825  		st := &mockState{
   826  			assignments:   testCase.stAssignments,
   827  			defaultCPUSet: testCase.stDefaultCPUSet,
   828  		}
   829  
   830  		policy.RemoveContainer(st, testCase.podUID, testCase.containerName)
   831  
   832  		if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSet) {
   833  			t.Errorf("StaticPolicy RemoveContainer() error (%v). expected default cpuset %v but got %v",
   834  				testCase.description, testCase.expCSet, st.defaultCPUSet)
   835  		}
   836  
   837  		if _, found := st.assignments[testCase.podUID][testCase.containerName]; found {
   838  			t.Errorf("StaticPolicy RemoveContainer() error (%v). expected (pod %v, container %v) not be in assignments %v",
   839  				testCase.description, testCase.podUID, testCase.containerName, st.assignments)
   840  		}
   841  	}
   842  }
   843  
   844  func TestTopologyAwareAllocateCPUs(t *testing.T) {
   845  	testCases := []struct {
   846  		description     string
   847  		topo            *topology.CPUTopology
   848  		stAssignments   state.ContainerCPUAssignments
   849  		stDefaultCPUSet cpuset.CPUSet
   850  		numRequested    int
   851  		socketMask      bitmask.BitMask
   852  		expCSet         cpuset.CPUSet
   853  	}{
   854  		{
   855  			description:     "Request 2 CPUs, No BitMask",
   856  			topo:            topoDualSocketHT,
   857  			stAssignments:   state.ContainerCPUAssignments{},
   858  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   859  			numRequested:    2,
   860  			socketMask:      nil,
   861  			expCSet:         cpuset.New(0, 6),
   862  		},
   863  		{
   864  			description:     "Request 2 CPUs, BitMask on Socket 0",
   865  			topo:            topoDualSocketHT,
   866  			stAssignments:   state.ContainerCPUAssignments{},
   867  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   868  			numRequested:    2,
   869  			socketMask: func() bitmask.BitMask {
   870  				mask, _ := bitmask.NewBitMask(0)
   871  				return mask
   872  			}(),
   873  			expCSet: cpuset.New(0, 6),
   874  		},
   875  		{
   876  			description:     "Request 2 CPUs, BitMask on Socket 1",
   877  			topo:            topoDualSocketHT,
   878  			stAssignments:   state.ContainerCPUAssignments{},
   879  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   880  			numRequested:    2,
   881  			socketMask: func() bitmask.BitMask {
   882  				mask, _ := bitmask.NewBitMask(1)
   883  				return mask
   884  			}(),
   885  			expCSet: cpuset.New(1, 7),
   886  		},
   887  		{
   888  			description:     "Request 8 CPUs, BitMask on Socket 0",
   889  			topo:            topoDualSocketHT,
   890  			stAssignments:   state.ContainerCPUAssignments{},
   891  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   892  			numRequested:    8,
   893  			socketMask: func() bitmask.BitMask {
   894  				mask, _ := bitmask.NewBitMask(0)
   895  				return mask
   896  			}(),
   897  			expCSet: cpuset.New(0, 6, 2, 8, 4, 10, 1, 7),
   898  		},
   899  		{
   900  			description:     "Request 8 CPUs, BitMask on Socket 1",
   901  			topo:            topoDualSocketHT,
   902  			stAssignments:   state.ContainerCPUAssignments{},
   903  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   904  			numRequested:    8,
   905  			socketMask: func() bitmask.BitMask {
   906  				mask, _ := bitmask.NewBitMask(1)
   907  				return mask
   908  			}(),
   909  			expCSet: cpuset.New(1, 7, 3, 9, 5, 11, 0, 6),
   910  		},
   911  	}
   912  	for _, tc := range testCases {
   913  		p, _ := NewStaticPolicy(tc.topo, 0, cpuset.New(), topologymanager.NewFakeManager(), nil)
   914  		policy := p.(*staticPolicy)
   915  		st := &mockState{
   916  			assignments:   tc.stAssignments,
   917  			defaultCPUSet: tc.stDefaultCPUSet,
   918  		}
   919  		err := policy.Start(st)
   920  		if err != nil {
   921  			t.Errorf("StaticPolicy Start() error (%v)", err)
   922  			continue
   923  		}
   924  
   925  		cset, err := policy.allocateCPUs(st, tc.numRequested, tc.socketMask, cpuset.New())
   926  		if err != nil {
   927  			t.Errorf("StaticPolicy allocateCPUs() error (%v). expected CPUSet %v not error %v",
   928  				tc.description, tc.expCSet, err)
   929  			continue
   930  		}
   931  
   932  		if !reflect.DeepEqual(tc.expCSet, cset) {
   933  			t.Errorf("StaticPolicy allocateCPUs() error (%v). expected CPUSet %v but got %v",
   934  				tc.description, tc.expCSet, cset)
   935  		}
   936  	}
   937  }
   938  
   939  // above test cases are without kubelet --reserved-cpus cmd option
   940  // the following tests are with --reserved-cpus configured
   941  type staticPolicyTestWithResvList struct {
   942  	description     string
   943  	topo            *topology.CPUTopology
   944  	numReservedCPUs int
   945  	reserved        cpuset.CPUSet
   946  	stAssignments   state.ContainerCPUAssignments
   947  	stDefaultCPUSet cpuset.CPUSet
   948  	pod             *v1.Pod
   949  	expErr          error
   950  	expNewErr       error
   951  	expCPUAlloc     bool
   952  	expCSet         cpuset.CPUSet
   953  }
   954  
   955  func TestStaticPolicyStartWithResvList(t *testing.T) {
   956  	testCases := []staticPolicyTestWithResvList{
   957  		{
   958  			description:     "empty cpuset",
   959  			topo:            topoDualSocketHT,
   960  			numReservedCPUs: 2,
   961  			reserved:        cpuset.New(0, 1),
   962  			stAssignments:   state.ContainerCPUAssignments{},
   963  			stDefaultCPUSet: cpuset.New(),
   964  			expCSet:         cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   965  		},
   966  		{
   967  			description:     "reserved cores 0 & 1 are not present in available cpuset",
   968  			topo:            topoDualSocketHT,
   969  			numReservedCPUs: 2,
   970  			reserved:        cpuset.New(0, 1),
   971  			stAssignments:   state.ContainerCPUAssignments{},
   972  			stDefaultCPUSet: cpuset.New(2, 3, 4, 5),
   973  			expErr:          fmt.Errorf("not all reserved cpus: \"0-1\" are present in defaultCpuSet: \"2-5\""),
   974  		},
   975  		{
   976  			description:     "inconsistency between numReservedCPUs and reserved",
   977  			topo:            topoDualSocketHT,
   978  			numReservedCPUs: 1,
   979  			reserved:        cpuset.New(0, 1),
   980  			stAssignments:   state.ContainerCPUAssignments{},
   981  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   982  			expNewErr:       fmt.Errorf("[cpumanager] unable to reserve the required amount of CPUs (size of 0-1 did not equal 1)"),
   983  		},
   984  	}
   985  	for _, testCase := range testCases {
   986  		t.Run(testCase.description, func(t *testing.T) {
   987  			p, err := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, testCase.reserved, topologymanager.NewFakeManager(), nil)
   988  			if !reflect.DeepEqual(err, testCase.expNewErr) {
   989  				t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
   990  					testCase.description, testCase.expNewErr, err)
   991  			}
   992  			if err != nil {
   993  				return
   994  			}
   995  			policy := p.(*staticPolicy)
   996  			st := &mockState{
   997  				assignments:   testCase.stAssignments,
   998  				defaultCPUSet: testCase.stDefaultCPUSet,
   999  			}
  1000  			err = policy.Start(st)
  1001  			if !reflect.DeepEqual(err, testCase.expErr) {
  1002  				t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
  1003  					testCase.description, testCase.expErr, err)
  1004  			}
  1005  			if err != nil {
  1006  				return
  1007  			}
  1008  
  1009  			if !st.GetDefaultCPUSet().Equals(testCase.expCSet) {
  1010  				t.Errorf("State CPUSet is different than expected. Have %q wants: %q", st.GetDefaultCPUSet(),
  1011  					testCase.expCSet)
  1012  			}
  1013  
  1014  		})
  1015  	}
  1016  }
  1017  
  1018  func TestStaticPolicyAddWithResvList(t *testing.T) {
  1019  
  1020  	testCases := []staticPolicyTestWithResvList{
  1021  		{
  1022  			description:     "GuPodSingleCore, SingleSocketHT, ExpectError",
  1023  			topo:            topoSingleSocketHT,
  1024  			numReservedCPUs: 1,
  1025  			reserved:        cpuset.New(0),
  1026  			stAssignments:   state.ContainerCPUAssignments{},
  1027  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
  1028  			pod:             makePod("fakePod", "fakeContainer2", "8000m", "8000m"),
  1029  			expErr:          fmt.Errorf("not enough cpus available to satisfy request: requested=8, available=7"),
  1030  			expCPUAlloc:     false,
  1031  			expCSet:         cpuset.New(),
  1032  		},
  1033  		{
  1034  			description:     "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
  1035  			topo:            topoSingleSocketHT,
  1036  			numReservedCPUs: 2,
  1037  			reserved:        cpuset.New(0, 1),
  1038  			stAssignments:   state.ContainerCPUAssignments{},
  1039  			stDefaultCPUSet: cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
  1040  			pod:             makePod("fakePod", "fakeContainer2", "1000m", "1000m"),
  1041  			expErr:          nil,
  1042  			expCPUAlloc:     true,
  1043  			expCSet:         cpuset.New(4), // expect sibling of partial core
  1044  		},
  1045  		{
  1046  			description:     "GuPodMultipleCores, SingleSocketHT, ExpectAllocOneCore",
  1047  			topo:            topoSingleSocketHT,
  1048  			numReservedCPUs: 2,
  1049  			reserved:        cpuset.New(0, 1),
  1050  			stAssignments: state.ContainerCPUAssignments{
  1051  				"fakePod": map[string]cpuset.CPUSet{
  1052  					"fakeContainer100": cpuset.New(2, 3, 6, 7),
  1053  				},
  1054  			},
  1055  			stDefaultCPUSet: cpuset.New(0, 1, 4, 5),
  1056  			pod:             makePod("fakePod", "fakeContainer3", "2000m", "2000m"),
  1057  			expErr:          nil,
  1058  			expCPUAlloc:     true,
  1059  			expCSet:         cpuset.New(4, 5),
  1060  		},
  1061  	}
  1062  
  1063  	for _, testCase := range testCases {
  1064  		policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, testCase.reserved, topologymanager.NewFakeManager(), nil)
  1065  
  1066  		st := &mockState{
  1067  			assignments:   testCase.stAssignments,
  1068  			defaultCPUSet: testCase.stDefaultCPUSet,
  1069  		}
  1070  
  1071  		container := &testCase.pod.Spec.Containers[0]
  1072  		err := policy.Allocate(st, testCase.pod, container)
  1073  		if !reflect.DeepEqual(err, testCase.expErr) {
  1074  			t.Errorf("StaticPolicy Allocate() error (%v). expected add error: %v but got: %v",
  1075  				testCase.description, testCase.expErr, err)
  1076  		}
  1077  
  1078  		if testCase.expCPUAlloc {
  1079  			cset, found := st.assignments[string(testCase.pod.UID)][container.Name]
  1080  			if !found {
  1081  				t.Errorf("StaticPolicy Allocate() error (%v). expected container %v to be present in assignments %v",
  1082  					testCase.description, container.Name, st.assignments)
  1083  			}
  1084  
  1085  			if !reflect.DeepEqual(cset, testCase.expCSet) {
  1086  				t.Errorf("StaticPolicy Allocate() error (%v). expected cpuset %v but got %v",
  1087  					testCase.description, testCase.expCSet, cset)
  1088  			}
  1089  
  1090  			if !cset.Intersection(st.defaultCPUSet).IsEmpty() {
  1091  				t.Errorf("StaticPolicy Allocate() error (%v). expected cpuset %v to be disoint from the shared cpuset %v",
  1092  					testCase.description, cset, st.defaultCPUSet)
  1093  			}
  1094  		}
  1095  
  1096  		if !testCase.expCPUAlloc {
  1097  			_, found := st.assignments[string(testCase.pod.UID)][container.Name]
  1098  			if found {
  1099  				t.Errorf("StaticPolicy Allocate() error (%v). Did not expect container %v to be present in assignments %v",
  1100  					testCase.description, container.Name, st.assignments)
  1101  			}
  1102  		}
  1103  	}
  1104  }
  1105  
  1106  type staticPolicyOptionTestCase struct {
  1107  	description   string
  1108  	policyOptions map[string]string
  1109  	expectedError bool
  1110  	expectedValue StaticPolicyOptions
  1111  }
  1112  
  1113  func TestStaticPolicyOptions(t *testing.T) {
  1114  	testCases := []staticPolicyOptionTestCase{
  1115  		{
  1116  			description:   "nil args",
  1117  			policyOptions: nil,
  1118  			expectedError: false,
  1119  			expectedValue: StaticPolicyOptions{},
  1120  		},
  1121  		{
  1122  			description:   "empty args",
  1123  			policyOptions: map[string]string{},
  1124  			expectedError: false,
  1125  			expectedValue: StaticPolicyOptions{},
  1126  		},
  1127  		{
  1128  			description: "bad single arg",
  1129  			policyOptions: map[string]string{
  1130  				"badValue1": "",
  1131  			},
  1132  			expectedError: true,
  1133  		},
  1134  		{
  1135  			description: "bad multiple arg",
  1136  			policyOptions: map[string]string{
  1137  				"badValue1": "",
  1138  				"badvalue2": "aaaa",
  1139  			},
  1140  			expectedError: true,
  1141  		},
  1142  		{
  1143  			description: "good arg",
  1144  			policyOptions: map[string]string{
  1145  				FullPCPUsOnlyOption: "true",
  1146  			},
  1147  			expectedError: false,
  1148  			expectedValue: StaticPolicyOptions{
  1149  				FullPhysicalCPUsOnly: true,
  1150  			},
  1151  		},
  1152  		{
  1153  			description: "good arg, bad value",
  1154  			policyOptions: map[string]string{
  1155  				FullPCPUsOnlyOption: "enabled!",
  1156  			},
  1157  			expectedError: true,
  1158  		},
  1159  
  1160  		{
  1161  			description: "bad arg intermixed",
  1162  			policyOptions: map[string]string{
  1163  				FullPCPUsOnlyOption: "1",
  1164  				"badvalue2":         "lorem ipsum",
  1165  			},
  1166  			expectedError: true,
  1167  		},
  1168  	}
  1169  
  1170  	for _, testCase := range testCases {
  1171  		t.Run(testCase.description, func(t *testing.T) {
  1172  			opts, err := NewStaticPolicyOptions(testCase.policyOptions)
  1173  			gotError := (err != nil)
  1174  			if gotError != testCase.expectedError {
  1175  				t.Fatalf("error with args %v expected error %v got %v: %v",
  1176  					testCase.policyOptions, testCase.expectedError, gotError, err)
  1177  			}
  1178  
  1179  			if testCase.expectedError {
  1180  				return
  1181  			}
  1182  
  1183  			if !reflect.DeepEqual(opts, testCase.expectedValue) {
  1184  				t.Fatalf("value mismatch with args %v expected value %v got %v",
  1185  					testCase.policyOptions, testCase.expectedValue, opts)
  1186  			}
  1187  		})
  1188  	}
  1189  }
  1190  
  1191  func newCPUSetPtr(cpus ...int) *cpuset.CPUSet {
  1192  	ret := cpuset.New(cpus...)
  1193  	return &ret
  1194  }
  1195  

View as plain text