1
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
53
54 func (spt staticPolicyTest) PseudoClone() staticPolicyTest {
55 return staticPolicyTest{
56 description: spt.description,
57 topo: spt.topo,
58 numReservedCPUs: spt.numReservedCPUs,
59 podUID: spt.podUID,
60 options: spt.options,
61 containerName: spt.containerName,
62 stAssignments: spt.stAssignments.Clone(),
63 stDefaultCPUSet: spt.stDefaultCPUSet.Clone(),
64 pod: spt.pod,
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
197
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
314
315
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
331
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
348
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
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),
378 },
379 {
380
381
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
453
454
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
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(),
485 },
486 {
487
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"}},
676 []struct{ request, limit string }{
677 {"2000m", "2000m"}}),
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
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
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}},
731 []*containerOptions{
732 {request: "2000m", limit: "2000m"}}),
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
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
940
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),
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