1
16
17 package nodeunschedulable
18
19 import (
20 "reflect"
21 "testing"
22
23 v1 "k8s.io/api/core/v1"
24 "k8s.io/kubernetes/pkg/scheduler/framework"
25 "k8s.io/kubernetes/test/utils/ktesting"
26 )
27
28 func TestNodeUnschedulable(t *testing.T) {
29 testCases := []struct {
30 name string
31 pod *v1.Pod
32 node *v1.Node
33 wantStatus *framework.Status
34 }{
35 {
36 name: "Does not schedule pod to unschedulable node (node.Spec.Unschedulable==true)",
37 pod: &v1.Pod{},
38 node: &v1.Node{
39 Spec: v1.NodeSpec{
40 Unschedulable: true,
41 },
42 },
43 wantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonUnschedulable),
44 },
45 {
46 name: "Schedule pod to normal node",
47 pod: &v1.Pod{},
48 node: &v1.Node{
49 Spec: v1.NodeSpec{
50 Unschedulable: false,
51 },
52 },
53 },
54 {
55 name: "Schedule pod with toleration to unschedulable node (node.Spec.Unschedulable==true)",
56 pod: &v1.Pod{
57 Spec: v1.PodSpec{
58 Tolerations: []v1.Toleration{
59 {
60 Key: v1.TaintNodeUnschedulable,
61 Effect: v1.TaintEffectNoSchedule,
62 },
63 },
64 },
65 },
66 node: &v1.Node{
67 Spec: v1.NodeSpec{
68 Unschedulable: true,
69 },
70 },
71 },
72 }
73
74 for _, test := range testCases {
75 nodeInfo := framework.NewNodeInfo()
76 nodeInfo.SetNode(test.node)
77 _, ctx := ktesting.NewTestContext(t)
78 p, err := New(ctx, nil, nil)
79 if err != nil {
80 t.Fatalf("creating plugin: %v", err)
81 }
82 gotStatus := p.(framework.FilterPlugin).Filter(ctx, nil, test.pod, nodeInfo)
83 if !reflect.DeepEqual(gotStatus, test.wantStatus) {
84 t.Errorf("status does not match: %v, want: %v", gotStatus, test.wantStatus)
85 }
86 }
87 }
88
89 func TestIsSchedulableAfterNodeChange(t *testing.T) {
90 testCases := []struct {
91 name string
92 pod *v1.Pod
93 oldObj, newObj interface{}
94 expectedHint framework.QueueingHint
95 expectedErr bool
96 }{
97 {
98 name: "backoff-wrong-new-object",
99 pod: &v1.Pod{},
100 newObj: "not-a-node",
101 expectedHint: framework.Queue,
102 expectedErr: true,
103 },
104 {
105 name: "backoff-wrong-old-object",
106 pod: &v1.Pod{},
107 newObj: &v1.Node{
108 Spec: v1.NodeSpec{
109 Unschedulable: true,
110 },
111 },
112 oldObj: "not-a-node",
113 expectedHint: framework.Queue,
114 expectedErr: true,
115 },
116 {
117 name: "skip-queue-on-unschedulable-node-added",
118 pod: &v1.Pod{},
119 newObj: &v1.Node{
120 Spec: v1.NodeSpec{
121 Unschedulable: true,
122 },
123 },
124 expectedHint: framework.QueueSkip,
125 },
126 {
127 name: "queue-on-schedulable-node-added",
128 pod: &v1.Pod{},
129 newObj: &v1.Node{
130 Spec: v1.NodeSpec{
131 Unschedulable: false,
132 },
133 },
134 expectedHint: framework.Queue,
135 },
136 {
137 name: "skip-unrelated-change",
138 pod: &v1.Pod{},
139 newObj: &v1.Node{
140 Spec: v1.NodeSpec{
141 Unschedulable: true,
142 Taints: []v1.Taint{
143 {
144 Key: v1.TaintNodeNotReady,
145 Effect: v1.TaintEffectNoExecute,
146 },
147 },
148 },
149 },
150 oldObj: &v1.Node{
151 Spec: v1.NodeSpec{
152 Unschedulable: true,
153 },
154 },
155 expectedHint: framework.QueueSkip,
156 },
157 {
158 name: "queue-on-unschedulable-field-change",
159 pod: &v1.Pod{},
160 newObj: &v1.Node{
161 Spec: v1.NodeSpec{
162 Unschedulable: false,
163 },
164 },
165 oldObj: &v1.Node{
166 Spec: v1.NodeSpec{
167 Unschedulable: true,
168 },
169 },
170 expectedHint: framework.Queue,
171 },
172 }
173
174 for _, testCase := range testCases {
175 t.Run(testCase.name, func(t *testing.T) {
176 logger, _ := ktesting.NewTestContext(t)
177 pl := &NodeUnschedulable{}
178 got, err := pl.isSchedulableAfterNodeChange(logger, testCase.pod, testCase.oldObj, testCase.newObj)
179 if err != nil && !testCase.expectedErr {
180 t.Errorf("unexpected error: %v", err)
181 }
182 if got != testCase.expectedHint {
183 t.Errorf("isSchedulableAfterNodeChange() = %v, want %v", got, testCase.expectedHint)
184 }
185 })
186 }
187 }
188
View as plain text