1
16
17 package validation
18
19 import (
20 "testing"
21
22 "k8s.io/apimachinery/pkg/api/resource"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/kubernetes/pkg/apis/core"
25 "k8s.io/kubernetes/pkg/apis/node"
26 utilpointer "k8s.io/utils/pointer"
27
28 "github.com/stretchr/testify/assert"
29 )
30
31 func TestValidateRuntimeClass(t *testing.T) {
32 tests := []struct {
33 name string
34 rc node.RuntimeClass
35 expectError bool
36 }{{
37 name: "invalid name",
38 expectError: true,
39 rc: node.RuntimeClass{
40 ObjectMeta: metav1.ObjectMeta{Name: "&!@#"},
41 Handler: "foo",
42 },
43 }, {
44 name: "invalid Handler name",
45 expectError: true,
46 rc: node.RuntimeClass{
47 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
48 Handler: "&@#$",
49 },
50 }, {
51 name: "invalid empty RuntimeClass",
52 expectError: true,
53 rc: node.RuntimeClass{
54 ObjectMeta: metav1.ObjectMeta{Name: "empty"},
55 },
56 }, {
57 name: "valid Handler",
58 expectError: false,
59 rc: node.RuntimeClass{
60 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
61 Handler: "bar-baz",
62 },
63 }}
64
65 for _, test := range tests {
66 t.Run(test.name, func(t *testing.T) {
67 errs := ValidateRuntimeClass(&test.rc)
68 if test.expectError {
69 assert.NotEmpty(t, errs)
70 } else {
71 assert.Empty(t, errs)
72 }
73 })
74 }
75 }
76
77 func TestValidateRuntimeUpdate(t *testing.T) {
78 old := node.RuntimeClass{
79 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
80 Handler: "bar",
81 }
82 tests := []struct {
83 name string
84 expectError bool
85 old, new node.RuntimeClass
86 }{{
87 name: "valid metadata update",
88 old: old,
89 new: node.RuntimeClass{
90 ObjectMeta: metav1.ObjectMeta{
91 Name: "foo",
92 Labels: map[string]string{"foo": "bar"},
93 },
94 Handler: "bar",
95 },
96 }, {
97 name: "invalid metadata update",
98 expectError: true,
99 old: old,
100 new: node.RuntimeClass{
101 ObjectMeta: metav1.ObjectMeta{
102 Name: "empty",
103 Namespace: "somethingelse",
104 },
105 Handler: "bar",
106 },
107 }, {
108 name: "invalid Handler update",
109 expectError: true,
110 old: old,
111 new: node.RuntimeClass{
112 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
113 Handler: "somethingelse",
114 },
115 }}
116
117 for _, test := range tests {
118 t.Run(test.name, func(t *testing.T) {
119
120 test.old.ObjectMeta.ResourceVersion = "1"
121 test.new.ObjectMeta.ResourceVersion = "1"
122
123 errs := ValidateRuntimeClassUpdate(&test.new, &test.old)
124 if test.expectError {
125 assert.NotEmpty(t, errs)
126 } else {
127 assert.Empty(t, errs)
128 }
129 })
130 }
131 }
132
133 func TestValidateOverhead(t *testing.T) {
134 successCase := []struct {
135 Name string
136 overhead *node.Overhead
137 }{{
138 Name: "Overhead with valid cpu and memory resources",
139 overhead: &node.Overhead{
140 PodFixed: core.ResourceList{
141 core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
142 core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
143 },
144 },
145 }}
146
147 for _, tc := range successCase {
148 rc := &node.RuntimeClass{
149 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
150 Handler: "bar",
151 Overhead: tc.overhead,
152 }
153 if errs := ValidateRuntimeClass(rc); len(errs) != 0 {
154 t.Errorf("%q unexpected error: %v", tc.Name, errs)
155 }
156 }
157
158 errorCase := []struct {
159 Name string
160 overhead *node.Overhead
161 }{{
162 Name: "Invalid Resources",
163 overhead: &node.Overhead{
164 PodFixed: core.ResourceList{
165 core.ResourceName("my.org"): resource.MustParse("10m"),
166 },
167 },
168 }}
169 for _, tc := range errorCase {
170 rc := &node.RuntimeClass{
171 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
172 Handler: "bar",
173 Overhead: tc.overhead,
174 }
175 if errs := ValidateRuntimeClass(rc); len(errs) == 0 {
176 t.Errorf("%q expected error", tc.Name)
177 }
178 }
179 }
180
181 func TestValidateScheduling(t *testing.T) {
182 tests := []struct {
183 name string
184 scheduling *node.Scheduling
185 expectErrs int
186 }{{
187 name: "valid scheduling",
188 scheduling: &node.Scheduling{
189 NodeSelector: map[string]string{"valid": "yes"},
190 Tolerations: []core.Toleration{{
191 Key: "valid",
192 Operator: core.TolerationOpExists,
193 Effect: core.TaintEffectNoSchedule,
194 }},
195 },
196 }, {
197 name: "empty scheduling",
198 scheduling: &node.Scheduling{},
199 }, {
200 name: "invalid nodeSelector",
201 scheduling: &node.Scheduling{
202 NodeSelector: map[string]string{"not a valid key!!!": "nope"},
203 },
204 expectErrs: 1,
205 }, {
206 name: "invalid toleration",
207 scheduling: &node.Scheduling{
208 Tolerations: []core.Toleration{{
209 Key: "valid",
210 Operator: core.TolerationOpExists,
211 Effect: core.TaintEffectNoSchedule,
212 }, {
213 Key: "not a valid key!!!",
214 Operator: core.TolerationOpExists,
215 Effect: core.TaintEffectNoSchedule,
216 }},
217 },
218 expectErrs: 1,
219 }, {
220 name: "duplicate tolerations",
221 scheduling: &node.Scheduling{
222 Tolerations: []core.Toleration{{
223 Key: "valid",
224 Operator: core.TolerationOpExists,
225 Effect: core.TaintEffectNoExecute,
226 TolerationSeconds: utilpointer.Int64(5),
227 }, {
228 Key: "valid",
229 Operator: core.TolerationOpExists,
230 Effect: core.TaintEffectNoExecute,
231 TolerationSeconds: utilpointer.Int64(10),
232 }},
233 },
234 expectErrs: 1,
235 }, {
236 name: "invalid scheduling",
237 scheduling: &node.Scheduling{
238 NodeSelector: map[string]string{"not a valid key!!!": "nope"},
239 Tolerations: []core.Toleration{{
240 Key: "valid",
241 Operator: core.TolerationOpExists,
242 Effect: core.TaintEffectNoSchedule,
243 }, {
244 Key: "not a valid toleration key!!!",
245 Operator: core.TolerationOpExists,
246 Effect: core.TaintEffectNoSchedule,
247 }},
248 },
249 expectErrs: 2,
250 }}
251
252 for _, test := range tests {
253 t.Run(test.name, func(t *testing.T) {
254 rc := &node.RuntimeClass{
255 ObjectMeta: metav1.ObjectMeta{Name: "foo"},
256 Handler: "bar",
257 Scheduling: test.scheduling,
258 }
259 assert.Len(t, ValidateRuntimeClass(rc), test.expectErrs)
260 })
261 }
262 }
263
View as plain text