mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			991 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			991 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2017 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 predicates
 | 
						|
 | 
						|
import (
 | 
						|
	"reflect"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	v1 "k8s.io/api/core/v1"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/labels"
 | 
						|
	nodeinfosnapshot "k8s.io/kubernetes/pkg/scheduler/nodeinfo/snapshot"
 | 
						|
	st "k8s.io/kubernetes/pkg/scheduler/testing"
 | 
						|
)
 | 
						|
 | 
						|
func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
 | 
						|
	fooSelector := st.MakeLabelSelector().Exists("foo").Obj()
 | 
						|
	barSelector := st.MakeLabelSelector().Exists("bar").Obj()
 | 
						|
	tests := []struct {
 | 
						|
		name         string
 | 
						|
		pod          *v1.Pod
 | 
						|
		nodes        []*v1.Node
 | 
						|
		existingPods []*v1.Pod
 | 
						|
		want         *PodTopologySpreadMetadata
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "clean cluster with one spreadConstraint",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
 | 
						|
				5, "zone", hardSpread, st.MakeLabelSelector().Label("foo", "bar").Obj(),
 | 
						|
			).Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     5,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Label("foo", "bar").Obj()),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 0}, {"zone2", 0}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 0,
 | 
						|
					{key: "zone", value: "zone2"}: 0,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "normal case with one spreadConstraint",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
 | 
						|
				1, "zone", hardSpread, fooSelector,
 | 
						|
			).Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 2}, {"zone1", 3}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 3,
 | 
						|
					{key: "zone", value: "zone2"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "normal case with one spreadConstraint, on a 3-zone cluster",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
 | 
						|
				1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(),
 | 
						|
			).Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
				st.MakeNode().Name("node-o").Label("zone", "zone3").Label("node", "node-o").Obj(),
 | 
						|
				st.MakeNode().Name("node-p").Label("zone", "zone3").Label("node", "node-p").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone3", 0}, {"zone2", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 3,
 | 
						|
					{key: "zone", value: "zone2"}: 2,
 | 
						|
					{key: "zone", value: "zone3"}: 0,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "namespace mismatch doesn't count",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
 | 
						|
				1, "zone", hardSpread, fooSelector,
 | 
						|
			).Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Namespace("ns2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 1}, {"zone1", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 2,
 | 
						|
					{key: "zone", value: "zone2"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "normal case with two spreadConstraints",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, fooSelector).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 3}, {"zone2", 4}},
 | 
						|
					"node": {{"node-x", 0}, {"node-b", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  4,
 | 
						|
					{key: "node", value: "node-a"}: 2,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 0,
 | 
						|
					{key: "node", value: "node-y"}: 4,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "soft spreadConstraints should be bypassed",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", softSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", softSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, fooSelector).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 3}, {"zone2", 4}},
 | 
						|
					"node": {{"node-b", 1}, {"node-a", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  4,
 | 
						|
					{key: "node", value: "node-a"}: 2,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-y"}: 4,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "different labelSelectors - simple version",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, barSelector).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b").Node("node-b").Label("bar", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, barSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 0}, {"zone1", 1}},
 | 
						|
					"node": {{"node-a", 0}, {"node-y", 0}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  1,
 | 
						|
					{key: "zone", value: "zone2"}:  0,
 | 
						|
					{key: "node", value: "node-a"}: 0,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-y"}: 0,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "different labelSelectors - complex pods",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, barSelector).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, barSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 3}, {"zone2", 4}},
 | 
						|
					"node": {{"node-b", 0}, {"node-a", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  4,
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-b"}: 0,
 | 
						|
					{key: "node", value: "node-y"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "two spreadConstraints, and with podAffinity",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				NodeAffinityNotIn("node", []string{"node-x"}). // exclude node-x
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, fooSelector).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, fooSelector).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "zone",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, fooSelector),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 3}, {"zone2", 4}},
 | 
						|
					"node": {{"node-b", 1}, {"node-a", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  4,
 | 
						|
					{key: "node", value: "node-a"}: 2,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-y"}: 4,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(tt.existingPods, tt.nodes))
 | 
						|
			l, _ := s.NodeInfos().List()
 | 
						|
			got, _ := GetPodTopologySpreadMetadata(tt.pod, l)
 | 
						|
			got.sortCriticalPaths()
 | 
						|
			if !reflect.DeepEqual(got, tt.want) {
 | 
						|
				t.Errorf("getEvenPodsSpreadMetadata() = %#v, want %#v", *got, *tt.want)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPodSpreadCache_addPod(t *testing.T) {
 | 
						|
	nodeConstraint := topologySpreadConstraint{
 | 
						|
		maxSkew:     1,
 | 
						|
		topologyKey: "node",
 | 
						|
		selector:    mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("foo").Obj()),
 | 
						|
	}
 | 
						|
	zoneConstraint := nodeConstraint
 | 
						|
	zoneConstraint.topologyKey = "zone"
 | 
						|
	tests := []struct {
 | 
						|
		name         string
 | 
						|
		preemptor    *v1.Pod
 | 
						|
		addedPod     *v1.Pod
 | 
						|
		existingPods []*v1.Pod
 | 
						|
		nodeIdx      int // denotes which node 'addedPod' belongs to
 | 
						|
		nodes        []*v1.Node
 | 
						|
		want         *PodTopologySpreadMetadata
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "node a and b both impact current min match",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod:     st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: nil, // it's an empty cluster
 | 
						|
			nodeIdx:      0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"node": {{"node-b", 0}, {"node-a", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-b"}: 0,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "only node a impacts current min match",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"node": {{"node-a", 1}, {"node-b", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "add a pod with mis-matched namespace doesn't change topologyKeyToMinPodsMap",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"node": {{"node-a", 0}, {"node-b", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "node", value: "node-a"}: 0,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "add pod on non-critical node won't trigger re-calculation",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-b2").Node("node-b").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 1,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"node": {{"node-a", 0}, {"node-b", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "node", value: "node-a"}: 0,
 | 
						|
					{key: "node", value: "node-b"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "node a and x both impact topologyKeyToMinPodsMap on zone and node",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod:     st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: nil, // it's an empty cluster
 | 
						|
			nodeIdx:      0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint, nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 0}, {"zone1", 1}},
 | 
						|
					"node": {{"node-x", 0}, {"node-a", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  1,
 | 
						|
					{key: "zone", value: "zone2"}:  0,
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 0,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "only node a impacts topologyKeyToMinPodsMap on zone and node",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint, nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 1}, {"zone2", 1}},
 | 
						|
					"node": {{"node-a", 1}, {"node-x", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  1,
 | 
						|
					{key: "zone", value: "zone2"}:  1,
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "node a impacts topologyKeyToMinPodsMap on node, node x impacts topologyKeyToMinPodsMap on zone",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b2").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint, nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 1}, {"zone1", 3}},
 | 
						|
					"node": {{"node-a", 1}, {"node-x", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  1,
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-b"}: 2,
 | 
						|
					{key: "node", value: "node-x"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on zone",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("bar").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x2").Node("node-x").Label("bar", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					zoneConstraint,
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("bar").Obj()),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 1}, {"zone1", 2}},
 | 
						|
					"node": {{"node-a", 0}, {"node-b", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  2,
 | 
						|
					{key: "zone", value: "zone2"}:  1,
 | 
						|
					{key: "node", value: "node-a"}: 0,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on both zone and node",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("bar").Obj()).
 | 
						|
				Obj(),
 | 
						|
			addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x2").Node("node-x").Label("bar", "").Obj(),
 | 
						|
			},
 | 
						|
			nodeIdx: 0,
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{
 | 
						|
					zoneConstraint,
 | 
						|
					{
 | 
						|
						maxSkew:     1,
 | 
						|
						topologyKey: "node",
 | 
						|
						selector:    mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("bar").Obj()),
 | 
						|
					},
 | 
						|
				},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 1}, {"zone2", 1}},
 | 
						|
					"node": {{"node-a", 1}, {"node-b", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  1,
 | 
						|
					{key: "zone", value: "zone2"}:  1,
 | 
						|
					{key: "node", value: "node-a"}: 1,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(tt.existingPods, tt.nodes))
 | 
						|
			l, _ := s.NodeInfos().List()
 | 
						|
			podTopologySpreadMeta, _ := GetPodTopologySpreadMetadata(tt.preemptor, l)
 | 
						|
			podTopologySpreadMeta.AddPod(tt.addedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
 | 
						|
			podTopologySpreadMeta.sortCriticalPaths()
 | 
						|
			if !reflect.DeepEqual(podTopologySpreadMeta, tt.want) {
 | 
						|
				t.Errorf("podTopologySpreadMeta#addPod() = %v, want %v", podTopologySpreadMeta, tt.want)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPodSpreadCache_removePod(t *testing.T) {
 | 
						|
	nodeConstraint := topologySpreadConstraint{
 | 
						|
		maxSkew:     1,
 | 
						|
		topologyKey: "node",
 | 
						|
		selector:    mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("foo").Obj()),
 | 
						|
	}
 | 
						|
	zoneConstraint := nodeConstraint
 | 
						|
	zoneConstraint.topologyKey = "zone"
 | 
						|
	tests := []struct {
 | 
						|
		name          string
 | 
						|
		preemptor     *v1.Pod // preemptor pod
 | 
						|
		nodes         []*v1.Node
 | 
						|
		existingPods  []*v1.Pod
 | 
						|
		deletedPodIdx int     // need to reuse *Pod of existingPods[i]
 | 
						|
		deletedPod    *v1.Pod // this field is used only when deletedPodIdx is -1
 | 
						|
		nodeIdx       int     // denotes which node "deletedPod" belongs to
 | 
						|
		want          *PodTopologySpreadMetadata
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			// A high priority pod may not be scheduled due to node taints or resource shortage.
 | 
						|
			// So preemption is triggered.
 | 
						|
			name: "one spreadConstraint on zone, topologyKeyToMinPodsMap unchanged",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			deletedPodIdx: 0, // remove pod "p-a1"
 | 
						|
			nodeIdx:       0, // node-a
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 1}, {"zone2", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 1,
 | 
						|
					{key: "zone", value: "zone2"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "one spreadConstraint on node, topologyKeyToMinPodsMap changed",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			deletedPodIdx: 0, // remove pod "p-a1"
 | 
						|
			nodeIdx:       0, // node-a
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 1}, {"zone2", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 1,
 | 
						|
					{key: "zone", value: "zone2"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "delete an irrelevant pod won't help",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a0").Node("node-a").Label("bar", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			deletedPodIdx: 0, // remove pod "p-a0"
 | 
						|
			nodeIdx:       0, // node-a
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 2}, {"zone2", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 2,
 | 
						|
					{key: "zone", value: "zone2"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "delete a non-existing pod won't help",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
				st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			deletedPodIdx: -1,
 | 
						|
			deletedPod:    st.MakePod().Name("p-a0").Node("node-a").Label("bar", "").Obj(),
 | 
						|
			nodeIdx:       0, // node-a
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone1", 2}, {"zone2", 2}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}: 2,
 | 
						|
					{key: "zone", value: "zone2"}: 2,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "two spreadConstraints",
 | 
						|
			preemptor: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			nodes: []*v1.Node{
 | 
						|
				st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
 | 
						|
				st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
 | 
						|
				st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
 | 
						|
			},
 | 
						|
			existingPods: []*v1.Pod{
 | 
						|
				st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
 | 
						|
				st.MakePod().Name("p-x2").Node("node-x").Label("foo", "").Obj(),
 | 
						|
			},
 | 
						|
			deletedPodIdx: 3, // remove pod "p-x1"
 | 
						|
			nodeIdx:       2, // node-x
 | 
						|
			want: &PodTopologySpreadMetadata{
 | 
						|
				constraints: []topologySpreadConstraint{zoneConstraint, nodeConstraint},
 | 
						|
				tpKeyToCriticalPaths: map[string]*criticalPaths{
 | 
						|
					"zone": {{"zone2", 1}, {"zone1", 3}},
 | 
						|
					"node": {{"node-b", 1}, {"node-x", 1}},
 | 
						|
				},
 | 
						|
				tpPairToMatchNum: map[topologyPair]int32{
 | 
						|
					{key: "zone", value: "zone1"}:  3,
 | 
						|
					{key: "zone", value: "zone2"}:  1,
 | 
						|
					{key: "node", value: "node-a"}: 2,
 | 
						|
					{key: "node", value: "node-b"}: 1,
 | 
						|
					{key: "node", value: "node-x"}: 1,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(tt.existingPods, tt.nodes))
 | 
						|
			l, _ := s.NodeInfos().List()
 | 
						|
			podTopologySpreadMeta, _ := GetPodTopologySpreadMetadata(tt.preemptor, l)
 | 
						|
 | 
						|
			var deletedPod *v1.Pod
 | 
						|
			if tt.deletedPodIdx < len(tt.existingPods) && tt.deletedPodIdx >= 0 {
 | 
						|
				deletedPod = tt.existingPods[tt.deletedPodIdx]
 | 
						|
			} else {
 | 
						|
				deletedPod = tt.deletedPod
 | 
						|
			}
 | 
						|
			podTopologySpreadMeta.RemovePod(deletedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
 | 
						|
			podTopologySpreadMeta.sortCriticalPaths()
 | 
						|
			if !reflect.DeepEqual(podTopologySpreadMeta, tt.want) {
 | 
						|
				t.Errorf("podTopologySpreadMeta#removePod() = %v, want %v", podTopologySpreadMeta, tt.want)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkTestGetTPMapMatchingSpreadConstraints(b *testing.B) {
 | 
						|
	tests := []struct {
 | 
						|
		name             string
 | 
						|
		pod              *v1.Pod
 | 
						|
		existingPodsNum  int
 | 
						|
		allNodesNum      int
 | 
						|
		filteredNodesNum int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "1000nodes/single-constraint-zone",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, v1.LabelZoneFailureDomain, hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			existingPodsNum:  10000,
 | 
						|
			allNodesNum:      1000,
 | 
						|
			filteredNodesNum: 500,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "1000nodes/single-constraint-node",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").
 | 
						|
				SpreadConstraint(1, v1.LabelHostname, hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				Obj(),
 | 
						|
			existingPodsNum:  10000,
 | 
						|
			allNodesNum:      1000,
 | 
						|
			filteredNodesNum: 500,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "1000nodes/two-constraints-zone-node",
 | 
						|
			pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
 | 
						|
				SpreadConstraint(1, v1.LabelZoneFailureDomain, hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
 | 
						|
				SpreadConstraint(1, v1.LabelHostname, hardSpread, st.MakeLabelSelector().Exists("bar").Obj()).
 | 
						|
				Obj(),
 | 
						|
			existingPodsNum:  10000,
 | 
						|
			allNodesNum:      1000,
 | 
						|
			filteredNodesNum: 500,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		b.Run(tt.name, func(b *testing.B) {
 | 
						|
			existingPods, allNodes, _ := st.MakeNodesAndPodsForEvenPodsSpread(tt.pod.Labels, tt.existingPodsNum, tt.allNodesNum, tt.filteredNodesNum)
 | 
						|
			s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(existingPods, allNodes))
 | 
						|
			l, _ := s.NodeInfos().List()
 | 
						|
			b.ResetTimer()
 | 
						|
			for i := 0; i < b.N; i++ {
 | 
						|
				GetPodTopologySpreadMetadata(tt.pod, l)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	hardSpread = v1.DoNotSchedule
 | 
						|
	softSpread = v1.ScheduleAnyway
 | 
						|
)
 | 
						|
 | 
						|
// sortCriticalPaths is only served for testing purpose.
 | 
						|
func (m *PodTopologySpreadMetadata) sortCriticalPaths() {
 | 
						|
	for _, paths := range m.tpKeyToCriticalPaths {
 | 
						|
		// If two paths both hold minimum matching number, and topologyValue is unordered.
 | 
						|
		if paths[0].matchNum == paths[1].matchNum && paths[0].topologyValue > paths[1].topologyValue {
 | 
						|
			// Swap topologyValue to make them sorted alphabetically.
 | 
						|
			paths[0].topologyValue, paths[1].topologyValue = paths[1].topologyValue, paths[0].topologyValue
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func mustConvertLabelSelectorAsSelector(t *testing.T, ls *metav1.LabelSelector) labels.Selector {
 | 
						|
	t.Helper()
 | 
						|
	s, err := metav1.LabelSelectorAsSelector(ls)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	return s
 | 
						|
}
 |