kubernetes/pkg/kubelet/cm/topologymanager/policy_test.go
Kevin Klues b5f52e6072 Modularize TopologyManager policy Merge() tests
These changes make it so that a set of common test cases can be used for
all merge strategies, with specific test cases being able to be
specified on a policy-by-policy basis.
2019-11-04 18:43:07 +01:00

669 lines
14 KiB
Go

/*
Copyright 2019 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 topologymanager
import (
"testing"
"k8s.io/api/core/v1"
)
type policyMergeTestCase struct {
name string
hp []HintProvider
expected TopologyHint
}
func commonPolicyMergeTestCases(numaNodes []int) []policyMergeTestCase {
return []policyMergeTestCase{
{
name: "TopologyHint not set",
hp: []HintProvider{},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: true,
},
},
{
name: "HintProvider returns empty non-nil map[string][]TopologyHint",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: true,
},
},
{
name: "HintProvider returns -nil map[string][]TopologyHint from provider",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource": nil,
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: true,
},
},
{
name: "HintProvider returns empty non-nil map[string][]TopologyHint from provider",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource": {},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: false,
},
},
{
name: "Single TopologyHint with Preferred as true and NUMANodeAffinity as nil",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource": {
{
NUMANodeAffinity: nil,
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: true,
},
},
{
name: "Single TopologyHint with Preferred as false and NUMANodeAffinity as nil",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource": {
{
NUMANodeAffinity: nil,
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: false,
},
},
{
name: "Two providers, 1 hint each, same mask, both preferred 1/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
{
name: "Two providers, 1 hint each, same mask, both preferred 2/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
{
name: "Two providers, 1 hint each, no common mask",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(numaNodes...),
Preferred: false,
},
},
{
name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 1/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: false,
},
},
{
name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 2/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: false,
},
},
{
name: "Two providers, 1 no hints, 1 single hint preferred 1/2",
hp: []HintProvider{
&mockHintProvider{},
&mockHintProvider{
map[string][]TopologyHint{
"resource": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
{
name: "Two providers, 1 no hints, 1 single hint preferred 2/2",
hp: []HintProvider{
&mockHintProvider{},
&mockHintProvider{
map[string][]TopologyHint{
"resource": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
{
name: "Two providers, 1 with 2 hints, 1 with single hint matching 1/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
{
name: "Two providers, 1 with 2 hints, 1 with single hint matching 2/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
{
name: "Two providers, 1 with 2 hints, 1 with single non-preferred hint matching",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: false,
},
},
{
name: "Two providers, both with 2 hints, matching narrower preferred hint from both",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
{
name: "Ensure less narrow preferred hints are chosen over narrower non-preferred hints",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
{
name: "Multiple resources, same provider",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
}
}
func (p *bestEffortPolicy) mergeTestCases(numaNodes []int) []policyMergeTestCase {
return []policyMergeTestCase{
{
name: "Two providers, 1 hint each, 1 wider mask, both preferred 1/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
{
name: "Two providers, 1 hint each, 1 wider mask, both preferred 1/2",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
},
},
&mockHintProvider{
map[string][]TopologyHint{
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: true,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
},
}
}
func (p *singleNumaNodePolicy) mergeTestCases(numaNodes []int) []policyMergeTestCase {
return []policyMergeTestCase{
{
name: "Single NUMA hint generation",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: true,
},
},
"resource2": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: false,
},
},
{
name: "One no-preference provider",
hp: []HintProvider{
&mockHintProvider{
map[string][]TopologyHint{
"resource1": {
{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(1),
Preferred: true,
},
{
NUMANodeAffinity: NewTestBitMask(0, 1),
Preferred: false,
},
},
},
},
&mockHintProvider{
nil,
},
},
expected: TopologyHint{
NUMANodeAffinity: NewTestBitMask(0),
Preferred: true,
},
},
}
}
func testPolicyMerge(policy Policy, tcases []policyMergeTestCase, t *testing.T) {
for _, tc := range tcases {
var providersHints []map[string][]TopologyHint
for _, provider := range tc.hp {
hints := provider.GetTopologyHints(v1.Pod{}, v1.Container{})
providersHints = append(providersHints, hints)
}
actual, _ := policy.Merge(providersHints)
if !actual.NUMANodeAffinity.IsEqual(tc.expected.NUMANodeAffinity) {
t.Errorf("%v: Expected NUMANodeAffinity in result to be %v, got %v", tc.name, tc.expected.NUMANodeAffinity, actual.NUMANodeAffinity)
}
if actual.Preferred != tc.expected.Preferred {
t.Errorf("%v: Expected Affinity preference in result to be %v, got %v", tc.name, tc.expected.Preferred, actual.Preferred)
}
}
}