@@ -42,132 +42,240 @@ import (
42
42
"sigs.k8s.io/scheduler-plugins/test/util"
43
43
)
44
44
45
- func TestQOSPlugin (t * testing.T ) {
46
- testCtx := & testContext {}
47
- testCtx .Ctx , testCtx .CancelFn = context .WithCancel (context .Background ())
48
-
49
- cs := kubernetes .NewForConfigOrDie (globalKubeConfig )
50
- testCtx .ClientSet = cs
51
- testCtx .KubeConfig = globalKubeConfig
52
-
53
- cfg , err := util .NewDefaultSchedulerComponentConfig ()
54
- if err != nil {
55
- t .Fatal (err )
56
- }
57
- cfg .Profiles [0 ].Plugins .QueueSort = schedapi.PluginSet {
58
- Enabled : []schedapi.Plugin {{Name : qos .Name }},
59
- Disabled : []schedapi.Plugin {{Name : "*" }},
60
- }
61
-
62
- testCtx = initTestSchedulerWithOptions (
63
- t ,
64
- testCtx ,
65
- scheduler .WithProfiles (cfg .Profiles ... ),
66
- scheduler .WithFrameworkOutOfTreeRegistry (fwkruntime.Registry {qos .Name : qos .New }),
67
- )
68
- syncInformerFactory (testCtx )
69
- // Do not start the scheduler.
70
- // go testCtx.Scheduler.Run(testCtx.Ctx)
71
- defer cleanupTest (t , testCtx )
72
-
73
- ns := fmt .Sprintf ("integration-test-%v" , string (uuid .NewUUID ()))
74
- createNamespace (t , testCtx , ns )
75
-
76
- // Create a Node.
77
- nodeName := "fake-node"
78
- node := st .MakeNode ().Name ("fake-node" ).Label ("node" , nodeName ).Obj ()
79
- node .Status .Capacity = v1.ResourceList {
80
- v1 .ResourcePods : * resource .NewQuantity (32 , resource .DecimalSI ),
81
- v1 .ResourceCPU : * resource .NewMilliQuantity (500 , resource .DecimalSI ),
82
- v1 .ResourceMemory : * resource .NewQuantity (500 , resource .DecimalSI ),
83
- }
84
- node , err = cs .CoreV1 ().Nodes ().Create (testCtx .Ctx , node , metav1.CreateOptions {})
85
- if err != nil {
86
- t .Fatalf ("Failed to create Node %q: %v" , nodeName , err )
87
- }
88
-
89
- // Create 3 Pods.
90
- var pods []* v1.Pod
91
- podNames := []string {"bestefforts" , "burstable" , "guaranteed" }
92
- pause := imageutils .GetPauseImageName ()
93
- for i := 0 ; i < len (podNames ); i ++ {
94
- pod := st .MakePod ().Namespace (ns ).Name (podNames [i ]).Container (pause ).Obj ()
95
- pods = append (pods , pod )
96
- }
97
- // Make pods[0] BestEfforts (i.e., do nothing).
98
- // Make pods[1] Burstable.
99
- pods [1 ].Spec .Containers [0 ].Resources = v1.ResourceRequirements {
100
- Requests : v1.ResourceList {
101
- v1 .ResourceCPU : * resource .NewMilliQuantity (50 , resource .DecimalSI ),
102
- v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
103
- },
104
- Limits : v1.ResourceList {
105
- v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
106
- v1 .ResourceMemory : * resource .NewQuantity (200 , resource .DecimalSI ),
107
- },
108
- }
109
- // Make pods[2] Guaranteed.
110
- pods [2 ].Spec .Containers [0 ].Resources = v1.ResourceRequirements {
111
- Requests : v1.ResourceList {
112
- v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
113
- v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
114
- },
115
- Limits : v1.ResourceList {
116
- v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
117
- v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
118
- },
119
- }
120
-
121
- // Create 3 Pods with the order: BestEfforts, Burstable, Guaranteed.
122
- // We will expect them to be scheduled in a reversed order.
123
- t .Logf ("Start to create 3 Pods." )
124
- // Concurrently create all Pods.
125
- var wg sync.WaitGroup
126
- for _ , pod := range pods {
127
- wg .Add (1 )
128
- go func (p * v1.Pod ) {
129
- defer wg .Done ()
130
- _ , err = cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , p , metav1.CreateOptions {})
45
+ func TestQOSPluginSuite (t * testing.T ) {
46
+ t .Run ("DifferentQoS" , func (t * testing.T ) {
47
+ testCtx := & testContext {}
48
+ testCtx .Ctx , testCtx .CancelFn = context .WithCancel (context .Background ())
49
+
50
+ cs := kubernetes .NewForConfigOrDie (globalKubeConfig )
51
+ testCtx .ClientSet = cs
52
+ testCtx .KubeConfig = globalKubeConfig
53
+
54
+ cfg , err := util .NewDefaultSchedulerComponentConfig ()
55
+ if err != nil {
56
+ t .Fatal (err )
57
+ }
58
+ cfg .Profiles [0 ].Plugins .QueueSort = schedapi.PluginSet {
59
+ Enabled : []schedapi.Plugin {{Name : qos .Name }},
60
+ Disabled : []schedapi.Plugin {{Name : "*" }},
61
+ }
62
+
63
+ testCtx = initTestSchedulerWithOptions (
64
+ t ,
65
+ testCtx ,
66
+ scheduler .WithProfiles (cfg .Profiles ... ),
67
+ scheduler .WithFrameworkOutOfTreeRegistry (fwkruntime.Registry {qos .Name : qos .New }),
68
+ )
69
+ syncInformerFactory (testCtx )
70
+ // Do not start the scheduler.
71
+ // go testCtx.Scheduler.Run(testCtx.Ctx)
72
+ defer cleanupTest (t , testCtx )
73
+
74
+ ns := fmt .Sprintf ("integration-test-%v" , string (uuid .NewUUID ()))
75
+ createNamespace (t , testCtx , ns )
76
+
77
+ // Create a Node.
78
+ nodeName := "fake-node"
79
+ node := st .MakeNode ().Name ("fake-node" ).Label ("node" , nodeName ).Obj ()
80
+ node .Status .Capacity = v1.ResourceList {
81
+ v1 .ResourcePods : * resource .NewQuantity (32 , resource .DecimalSI ),
82
+ v1 .ResourceCPU : * resource .NewMilliQuantity (500 , resource .DecimalSI ),
83
+ v1 .ResourceMemory : * resource .NewQuantity (500 , resource .DecimalSI ),
84
+ }
85
+ node , err = cs .CoreV1 ().Nodes ().Create (testCtx .Ctx , node , metav1.CreateOptions {})
86
+ if err != nil {
87
+ t .Fatalf ("Failed to create Node %q: %v" , nodeName , err )
88
+ }
89
+
90
+ // Create 3 Pods.
91
+ var pods []* v1.Pod
92
+ podNames := []string {"bestefforts" , "burstable" , "guaranteed" }
93
+ pause := imageutils .GetPauseImageName ()
94
+ for i := 0 ; i < len (podNames ); i ++ {
95
+ pod := st .MakePod ().Namespace (ns ).Name (podNames [i ]).Container (pause ).Obj ()
96
+ pods = append (pods , pod )
97
+ }
98
+ // Make pods[0] BestEfforts (i.e., do nothing).
99
+ // Make pods[1] Burstable.
100
+ pods [1 ].Spec .Containers [0 ].Resources = v1.ResourceRequirements {
101
+ Requests : v1.ResourceList {
102
+ v1 .ResourceCPU : * resource .NewMilliQuantity (50 , resource .DecimalSI ),
103
+ v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
104
+ },
105
+ Limits : v1.ResourceList {
106
+ v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
107
+ v1 .ResourceMemory : * resource .NewQuantity (200 , resource .DecimalSI ),
108
+ },
109
+ }
110
+ // Make pods[2] Guaranteed.
111
+ pods [2 ].Spec .Containers [0 ].Resources = v1.ResourceRequirements {
112
+ Requests : v1.ResourceList {
113
+ v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
114
+ v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
115
+ },
116
+ Limits : v1.ResourceList {
117
+ v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
118
+ v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
119
+ },
120
+ }
121
+
122
+ // Create 3 Pods with the order: BestEfforts, Burstable, Guaranteed.
123
+ // We will expect them to be scheduled in a reversed order.
124
+ t .Logf ("Start to create 3 Pods." )
125
+ // Concurrently create all Pods.
126
+ var wg sync.WaitGroup
127
+ for _ , pod := range pods {
128
+ wg .Add (1 )
129
+ go func (p * v1.Pod ) {
130
+ defer wg .Done ()
131
+ _ , err = cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , p , metav1.CreateOptions {})
132
+ if err != nil {
133
+ t .Errorf ("Failed to create Pod %q: %v" , p .Name , err )
134
+ } else {
135
+ t .Logf ("Created Pod %q" , p .Name )
136
+ }
137
+ }(pod )
138
+ }
139
+ wg .Wait ()
140
+ defer cleanupPods (t , testCtx , pods )
141
+
142
+ // Wait for all Pods are in the scheduling queue.
143
+ err = wait .PollUntilContextTimeout (testCtx .Ctx , time .Millisecond * 200 , wait .ForeverTestTimeout , false , func (ctx context.Context ) (bool , error ) {
144
+ pendingPods , _ := testCtx .Scheduler .SchedulingQueue .PendingPods ()
145
+ if len (pendingPods ) == len (pods ) {
146
+ // Collect Pod names into a slice.
147
+ podNames := make ([]string , len (pendingPods ))
148
+ for i , podInfo := range pendingPods {
149
+ podNames [i ] = podInfo .Name
150
+ }
151
+ t .Logf ("All Pods are in the pending queue: %v" , strings .Join (podNames , ", " ))
152
+ return true , nil
153
+ }
154
+ return false , nil
155
+ })
156
+ if err != nil {
157
+ t .Fatal (err )
158
+ }
159
+
160
+ // Expect Pods are popped in the QoS class order.
161
+ logger := klog .FromContext (testCtx .Ctx )
162
+ expectedOrder := []string {"guaranteed" , "burstable" , "bestefforts" }
163
+ actualOrder := make ([]string , len (expectedOrder ))
164
+ for i := 0 ; i < len (expectedOrder ); i ++ {
165
+ podInfo , _ := testCtx .Scheduler .NextPod (logger )
166
+ actualOrder [i ] = podInfo .Pod .Name
167
+ t .Logf ("Popped Pod %q" , podInfo .Pod .Name )
168
+ }
169
+ if ! reflect .DeepEqual (actualOrder , expectedOrder ) {
170
+ t .Errorf ("Expected Pod order %v, but got %v" , expectedOrder , actualOrder )
171
+ } else {
172
+ t .Logf ("Pods were popped out in the expected order." )
173
+ }
174
+ })
175
+ t .Run ("SameQoSDifferentCreationTime" , func (t * testing.T ) {
176
+ testCtx := & testContext {}
177
+ testCtx .Ctx , testCtx .CancelFn = context .WithCancel (context .Background ())
178
+
179
+ cs := kubernetes .NewForConfigOrDie (globalKubeConfig )
180
+ testCtx .ClientSet = cs
181
+ testCtx .KubeConfig = globalKubeConfig
182
+
183
+ cfg , err := util .NewDefaultSchedulerComponentConfig ()
184
+ if err != nil {
185
+ t .Fatal (err )
186
+ }
187
+ cfg .Profiles [0 ].Plugins .QueueSort = schedapi.PluginSet {
188
+ Enabled : []schedapi.Plugin {{Name : qos .Name }},
189
+ Disabled : []schedapi.Plugin {{Name : "*" }},
190
+ }
191
+
192
+ testCtx = initTestSchedulerWithOptions (
193
+ t ,
194
+ testCtx ,
195
+ scheduler .WithProfiles (cfg .Profiles ... ),
196
+ scheduler .WithFrameworkOutOfTreeRegistry (fwkruntime.Registry {qos .Name : qos .New }),
197
+ )
198
+ syncInformerFactory (testCtx )
199
+ defer cleanupTest (t , testCtx )
200
+
201
+ ns := fmt .Sprintf ("integration-test-same-qos-%v" , string (uuid .NewUUID ()))
202
+ createNamespace (t , testCtx , ns )
203
+
204
+ // Create a Node.
205
+ nodeName := "fake-node"
206
+ node := st .MakeNode ().Name (nodeName ).Label ("node" , nodeName ).Obj ()
207
+ node .Status .Capacity = v1.ResourceList {
208
+ v1 .ResourcePods : * resource .NewQuantity (32 , resource .DecimalSI ),
209
+ v1 .ResourceCPU : * resource .NewMilliQuantity (500 , resource .DecimalSI ),
210
+ v1 .ResourceMemory : * resource .NewQuantity (500 , resource .DecimalSI ),
211
+ }
212
+ node , err = cs .CoreV1 ().Nodes ().Create (testCtx .Ctx , node , metav1.CreateOptions {})
213
+ if err != nil {
214
+ t .Fatalf ("Failed to create Node %q: %v" , nodeName , err )
215
+ }
216
+
217
+ // Create 3 Pods with the same QoS class (Guaranteed) but different creation times.
218
+ var pods []* v1.Pod
219
+ podNames := []string {"guaranteed-1" , "guaranteed-2" , "guaranteed-3" }
220
+ pause := imageutils .GetPauseImageName ()
221
+ for i := 0 ; i < len (podNames ); i ++ {
222
+ pod := st .MakePod ().Namespace (ns ).Name (podNames [i ]).Container (pause ).Obj ()
223
+ pod .Spec .Containers [0 ].Resources = v1.ResourceRequirements {
224
+ Requests : v1.ResourceList {
225
+ v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
226
+ v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
227
+ },
228
+ Limits : v1.ResourceList {
229
+ v1 .ResourceCPU : * resource .NewMilliQuantity (100 , resource .DecimalSI ),
230
+ v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
231
+ },
232
+ }
233
+ pods = append (pods , pod )
234
+ }
235
+
236
+ // Create Pods sequentially with a delay between each creation to ensure different creation timestamps.
237
+ t .Logf ("Start to create 3 Guaranteed Pods sequentially." )
238
+ for _ , pod := range pods {
239
+ _ , err = cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , pod , metav1.CreateOptions {})
131
240
if err != nil {
132
- t .Errorf ("Failed to create Pod %q: %v" , p .Name , err )
241
+ t .Errorf ("Failed to create Pod %q: %v" , pod .Name , err )
133
242
} else {
134
- t .Logf ("Created Pod %q" , p .Name )
243
+ t .Logf ("Created Pod %q" , pod .Name )
135
244
}
136
- }(pod )
137
- }
138
- wg .Wait ()
139
- defer cleanupPods (t , testCtx , pods )
140
-
141
- // Wait for all Pods are in the scheduling queue.
142
- err = wait .PollUntilContextTimeout (testCtx .Ctx , time .Millisecond * 200 , wait .ForeverTestTimeout , false , func (ctx context.Context ) (bool , error ) {
143
- pendingPods , _ := testCtx .Scheduler .SchedulingQueue .PendingPods ()
144
- if len (pendingPods ) == len (pods ) {
145
- // Collect Pod names into a slice.
146
- podNames := make ([]string , len (pendingPods ))
147
- for i , podInfo := range pendingPods {
148
- podNames [i ] = podInfo .Name
245
+ }
246
+ defer cleanupPods (t , testCtx , pods )
247
+
248
+ // Wait for all Pods are in the scheduling queue.
249
+ err = wait .PollUntilContextTimeout (testCtx .Ctx , time .Millisecond * 200 , wait .ForeverTestTimeout , false , func (ctx context.Context ) (bool , error ) {
250
+ pendingPods , _ := testCtx .Scheduler .SchedulingQueue .PendingPods ()
251
+ if len (pendingPods ) == len (pods ) {
252
+ // Collect Pod names into a slice.
253
+ podNames := make ([]string , len (pendingPods ))
254
+ for i , podInfo := range pendingPods {
255
+ podNames [i ] = podInfo .Name
256
+ }
257
+ t .Logf ("All Pods are in the pending queue: %v" , strings .Join (podNames , ", " ))
258
+ return true , nil
149
259
}
150
- t .Logf ("All Pods are in the pending queue: %v" , strings .Join (podNames , ", " ))
151
- return true , nil
260
+ return false , nil
261
+ })
262
+ if err != nil {
263
+ t .Fatal (err )
264
+ }
265
+
266
+ // Expect Pods are popped in the order of their creation time (earliest first).
267
+ logger := klog .FromContext (testCtx .Ctx )
268
+ expectedOrder := podNames
269
+ actualOrder := make ([]string , len (expectedOrder ))
270
+ for i := 0 ; i < len (expectedOrder ); i ++ {
271
+ podInfo , _ := testCtx .Scheduler .NextPod (logger )
272
+ actualOrder [i ] = podInfo .Pod .Name
273
+ t .Logf ("Popped Pod %q" , podInfo .Pod .Name )
274
+ }
275
+ if ! reflect .DeepEqual (actualOrder , expectedOrder ) {
276
+ t .Errorf ("Expected Pod order %v, but got %v" , expectedOrder , actualOrder )
277
+ } else {
278
+ t .Logf ("Pods were popped out in the expected order based on creation time." )
152
279
}
153
- return false , nil
154
280
})
155
- if err != nil {
156
- t .Fatal (err )
157
- }
158
-
159
- // Expect Pods are popped in the QoS class order.
160
- logger := klog .FromContext (testCtx .Ctx )
161
- expectedOrder := []string {"guaranteed" , "burstable" , "bestefforts" }
162
- actualOrder := make ([]string , len (expectedOrder ))
163
- for i := 0 ; i < len (expectedOrder ); i ++ {
164
- podInfo , _ := testCtx .Scheduler .NextPod (logger )
165
- actualOrder [i ] = podInfo .Pod .Name
166
- t .Logf ("Popped Pod %q" , podInfo .Pod .Name )
167
- }
168
- if ! reflect .DeepEqual (actualOrder , expectedOrder ) {
169
- t .Errorf ("Expected Pod order %v, but got %v" , expectedOrder , actualOrder )
170
- } else {
171
- t .Logf ("Pods were popped out in the expected order." )
172
- }
173
281
}
0 commit comments