1
16
17 package volumebinding
18
19 import (
20 "fmt"
21 "testing"
22
23 v1 "k8s.io/api/core/v1"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/component-helpers/storage/volume"
26 "k8s.io/klog/v2/ktesting"
27 )
28
29 func verifyListPVs(t *testing.T, cache PVAssumeCache, expectedPVs map[string]*v1.PersistentVolume, storageClassName string) {
30 pvList := cache.ListPVs(storageClassName)
31 if len(pvList) != len(expectedPVs) {
32 t.Errorf("ListPVs() returned %v PVs, expected %v", len(pvList), len(expectedPVs))
33 }
34 for _, pv := range pvList {
35 expectedPV, ok := expectedPVs[pv.Name]
36 if !ok {
37 t.Errorf("ListPVs() returned unexpected PV %q", pv.Name)
38 }
39 if expectedPV != pv {
40 t.Errorf("ListPVs() returned PV %p, expected %p", pv, expectedPV)
41 }
42 }
43 }
44
45 func verifyPV(cache PVAssumeCache, name string, expectedPV *v1.PersistentVolume) error {
46 pv, err := cache.GetPV(name)
47 if err != nil {
48 return err
49 }
50 if pv != expectedPV {
51 return fmt.Errorf("GetPV() returned %p, expected %p", pv, expectedPV)
52 }
53 return nil
54 }
55
56 func TestAssumePV(t *testing.T) {
57 logger, _ := ktesting.NewTestContext(t)
58 scenarios := map[string]struct {
59 oldPV *v1.PersistentVolume
60 newPV *v1.PersistentVolume
61 shouldSucceed bool
62 }{
63 "success-same-version": {
64 oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
65 newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
66 shouldSucceed: true,
67 },
68 "success-storageclass-same-version": {
69 oldPV: makePV("pv1", "class1").withVersion("5").PersistentVolume,
70 newPV: makePV("pv1", "class1").withVersion("5").PersistentVolume,
71 shouldSucceed: true,
72 },
73 "success-new-higher-version": {
74 oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
75 newPV: makePV("pv1", "").withVersion("6").PersistentVolume,
76 shouldSucceed: true,
77 },
78 "fail-old-not-found": {
79 oldPV: makePV("pv2", "").withVersion("5").PersistentVolume,
80 newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
81 shouldSucceed: false,
82 },
83 "fail-new-lower-version": {
84 oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
85 newPV: makePV("pv1", "").withVersion("4").PersistentVolume,
86 shouldSucceed: false,
87 },
88 "fail-new-bad-version": {
89 oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
90 newPV: makePV("pv1", "").withVersion("a").PersistentVolume,
91 shouldSucceed: false,
92 },
93 "fail-old-bad-version": {
94 oldPV: makePV("pv1", "").withVersion("a").PersistentVolume,
95 newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
96 shouldSucceed: false,
97 },
98 }
99
100 for name, scenario := range scenarios {
101 cache := NewPVAssumeCache(logger, nil)
102 internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
103 if !ok {
104 t.Fatalf("Failed to get internal cache")
105 }
106
107
108 internalCache.add(scenario.oldPV)
109 if err := verifyPV(cache, scenario.oldPV.Name, scenario.oldPV); err != nil {
110 t.Errorf("Failed to GetPV() after initial update: %v", err)
111 continue
112 }
113
114
115 err := cache.Assume(scenario.newPV)
116 if scenario.shouldSucceed && err != nil {
117 t.Errorf("Test %q failed: Assume() returned error %v", name, err)
118 }
119 if !scenario.shouldSucceed && err == nil {
120 t.Errorf("Test %q failed: Assume() returned success but expected error", name)
121 }
122
123
124 expectedPV := scenario.newPV
125 if !scenario.shouldSucceed {
126 expectedPV = scenario.oldPV
127 }
128 if err := verifyPV(cache, scenario.oldPV.Name, expectedPV); err != nil {
129 t.Errorf("Failed to GetPV() after initial update: %v", err)
130 }
131 }
132 }
133
134 func TestRestorePV(t *testing.T) {
135 logger, _ := ktesting.NewTestContext(t)
136 cache := NewPVAssumeCache(logger, nil)
137 internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
138 if !ok {
139 t.Fatalf("Failed to get internal cache")
140 }
141
142 oldPV := makePV("pv1", "").withVersion("5").PersistentVolume
143 newPV := makePV("pv1", "").withVersion("5").PersistentVolume
144
145
146 cache.Restore("nothing")
147
148
149 internalCache.add(oldPV)
150 if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
151 t.Fatalf("Failed to GetPV() after initial update: %v", err)
152 }
153
154
155 cache.Restore(oldPV.Name)
156 if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
157 t.Fatalf("Failed to GetPV() after initial restore: %v", err)
158 }
159
160
161 if err := cache.Assume(newPV); err != nil {
162 t.Fatalf("Assume() returned error %v", err)
163 }
164 if err := verifyPV(cache, oldPV.Name, newPV); err != nil {
165 t.Fatalf("Failed to GetPV() after Assume: %v", err)
166 }
167
168
169 cache.Restore(oldPV.Name)
170 if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
171 t.Fatalf("Failed to GetPV() after restore: %v", err)
172 }
173 }
174
175 func TestBasicPVCache(t *testing.T) {
176 logger, _ := ktesting.NewTestContext(t)
177 cache := NewPVAssumeCache(logger, nil)
178 internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
179 if !ok {
180 t.Fatalf("Failed to get internal cache")
181 }
182
183
184 pv, err := cache.GetPV("nothere")
185 if err == nil {
186 t.Errorf("GetPV() returned unexpected success")
187 }
188 if pv != nil {
189 t.Errorf("GetPV() returned unexpected PV %q", pv.Name)
190 }
191
192
193 pvs := map[string]*v1.PersistentVolume{}
194 for i := 0; i < 10; i++ {
195 pv := makePV(fmt.Sprintf("test-pv%v", i), "").withVersion("1").PersistentVolume
196 pvs[pv.Name] = pv
197 internalCache.add(pv)
198 }
199
200
201 verifyListPVs(t, cache, pvs, "")
202
203
204 updatedPV := makePV("test-pv3", "").withVersion("2").PersistentVolume
205 pvs[updatedPV.Name] = updatedPV
206 internalCache.update(nil, updatedPV)
207
208
209 verifyListPVs(t, cache, pvs, "")
210
211
212 deletedPV := pvs["test-pv7"]
213 delete(pvs, deletedPV.Name)
214 internalCache.delete(deletedPV)
215
216
217 verifyListPVs(t, cache, pvs, "")
218 }
219
220 func TestPVCacheWithStorageClasses(t *testing.T) {
221 logger, _ := ktesting.NewTestContext(t)
222 cache := NewPVAssumeCache(logger, nil)
223 internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
224 if !ok {
225 t.Fatalf("Failed to get internal cache")
226 }
227
228
229 pvs1 := map[string]*v1.PersistentVolume{}
230 for i := 0; i < 10; i++ {
231 pv := makePV(fmt.Sprintf("test-pv%v", i), "class1").withVersion("1").PersistentVolume
232 pvs1[pv.Name] = pv
233 internalCache.add(pv)
234 }
235
236
237 pvs2 := map[string]*v1.PersistentVolume{}
238 for i := 0; i < 10; i++ {
239 pv := makePV(fmt.Sprintf("test2-pv%v", i), "class2").withVersion("1").PersistentVolume
240 pvs2[pv.Name] = pv
241 internalCache.add(pv)
242 }
243
244
245 verifyListPVs(t, cache, pvs1, "class1")
246 verifyListPVs(t, cache, pvs2, "class2")
247
248
249 updatedPV := makePV("test-pv3", "class1").withVersion("2").PersistentVolume
250 pvs1[updatedPV.Name] = updatedPV
251 internalCache.update(nil, updatedPV)
252
253
254 verifyListPVs(t, cache, pvs1, "class1")
255 verifyListPVs(t, cache, pvs2, "class2")
256
257
258 deletedPV := pvs1["test-pv7"]
259 delete(pvs1, deletedPV.Name)
260 internalCache.delete(deletedPV)
261
262
263 verifyListPVs(t, cache, pvs1, "class1")
264 verifyListPVs(t, cache, pvs2, "class2")
265 }
266
267 func TestAssumeUpdatePVCache(t *testing.T) {
268 logger, _ := ktesting.NewTestContext(t)
269 cache := NewPVAssumeCache(logger, nil)
270 internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
271 if !ok {
272 t.Fatalf("Failed to get internal cache")
273 }
274
275 pvName := "test-pv0"
276
277
278 pv := makePV(pvName, "").withVersion("1").PersistentVolume
279 internalCache.add(pv)
280 if err := verifyPV(cache, pvName, pv); err != nil {
281 t.Fatalf("failed to get PV: %v", err)
282 }
283
284
285 newPV := pv.DeepCopy()
286 newPV.Spec.ClaimRef = &v1.ObjectReference{Name: "test-claim"}
287 if err := cache.Assume(newPV); err != nil {
288 t.Fatalf("failed to assume PV: %v", err)
289 }
290 if err := verifyPV(cache, pvName, newPV); err != nil {
291 t.Fatalf("failed to get PV after assume: %v", err)
292 }
293
294
295 internalCache.add(pv)
296 if err := verifyPV(cache, pvName, newPV); err != nil {
297 t.Fatalf("failed to get PV after old PV added: %v", err)
298 }
299 }
300
301 func makeClaim(name, version, namespace string) *v1.PersistentVolumeClaim {
302 return &v1.PersistentVolumeClaim{
303 ObjectMeta: metav1.ObjectMeta{
304 Name: name,
305 Namespace: namespace,
306 ResourceVersion: version,
307 Annotations: map[string]string{},
308 },
309 }
310 }
311
312 func verifyPVC(cache PVCAssumeCache, pvcKey string, expectedPVC *v1.PersistentVolumeClaim) error {
313 pvc, err := cache.GetPVC(pvcKey)
314 if err != nil {
315 return err
316 }
317 if pvc != expectedPVC {
318 return fmt.Errorf("GetPVC() returned %p, expected %p", pvc, expectedPVC)
319 }
320 return nil
321 }
322
323 func TestAssumePVC(t *testing.T) {
324 logger, _ := ktesting.NewTestContext(t)
325 scenarios := map[string]struct {
326 oldPVC *v1.PersistentVolumeClaim
327 newPVC *v1.PersistentVolumeClaim
328 shouldSucceed bool
329 }{
330 "success-same-version": {
331 oldPVC: makeClaim("pvc1", "5", "ns1"),
332 newPVC: makeClaim("pvc1", "5", "ns1"),
333 shouldSucceed: true,
334 },
335 "success-new-higher-version": {
336 oldPVC: makeClaim("pvc1", "5", "ns1"),
337 newPVC: makeClaim("pvc1", "6", "ns1"),
338 shouldSucceed: true,
339 },
340 "fail-old-not-found": {
341 oldPVC: makeClaim("pvc2", "5", "ns1"),
342 newPVC: makeClaim("pvc1", "5", "ns1"),
343 shouldSucceed: false,
344 },
345 "fail-new-lower-version": {
346 oldPVC: makeClaim("pvc1", "5", "ns1"),
347 newPVC: makeClaim("pvc1", "4", "ns1"),
348 shouldSucceed: false,
349 },
350 "fail-new-bad-version": {
351 oldPVC: makeClaim("pvc1", "5", "ns1"),
352 newPVC: makeClaim("pvc1", "a", "ns1"),
353 shouldSucceed: false,
354 },
355 "fail-old-bad-version": {
356 oldPVC: makeClaim("pvc1", "a", "ns1"),
357 newPVC: makeClaim("pvc1", "5", "ns1"),
358 shouldSucceed: false,
359 },
360 }
361
362 for name, scenario := range scenarios {
363 cache := NewPVCAssumeCache(logger, nil)
364 internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
365 if !ok {
366 t.Fatalf("Failed to get internal cache")
367 }
368
369
370 internalCache.add(scenario.oldPVC)
371 if err := verifyPVC(cache, getPVCName(scenario.oldPVC), scenario.oldPVC); err != nil {
372 t.Errorf("Failed to GetPVC() after initial update: %v", err)
373 continue
374 }
375
376
377 err := cache.Assume(scenario.newPVC)
378 if scenario.shouldSucceed && err != nil {
379 t.Errorf("Test %q failed: Assume() returned error %v", name, err)
380 }
381 if !scenario.shouldSucceed && err == nil {
382 t.Errorf("Test %q failed: Assume() returned success but expected error", name)
383 }
384
385
386 expectedPV := scenario.newPVC
387 if !scenario.shouldSucceed {
388 expectedPV = scenario.oldPVC
389 }
390 if err := verifyPVC(cache, getPVCName(scenario.oldPVC), expectedPV); err != nil {
391 t.Errorf("Failed to GetPVC() after initial update: %v", err)
392 }
393 }
394 }
395
396 func TestRestorePVC(t *testing.T) {
397 logger, _ := ktesting.NewTestContext(t)
398 cache := NewPVCAssumeCache(logger, nil)
399 internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
400 if !ok {
401 t.Fatalf("Failed to get internal cache")
402 }
403
404 oldPVC := makeClaim("pvc1", "5", "ns1")
405 newPVC := makeClaim("pvc1", "5", "ns1")
406
407
408 cache.Restore("nothing")
409
410
411 internalCache.add(oldPVC)
412 if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
413 t.Fatalf("Failed to GetPVC() after initial update: %v", err)
414 }
415
416
417 cache.Restore(getPVCName(oldPVC))
418 if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
419 t.Fatalf("Failed to GetPVC() after initial restore: %v", err)
420 }
421
422
423 if err := cache.Assume(newPVC); err != nil {
424 t.Fatalf("Assume() returned error %v", err)
425 }
426 if err := verifyPVC(cache, getPVCName(oldPVC), newPVC); err != nil {
427 t.Fatalf("Failed to GetPVC() after Assume: %v", err)
428 }
429
430
431 cache.Restore(getPVCName(oldPVC))
432 if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
433 t.Fatalf("Failed to GetPVC() after restore: %v", err)
434 }
435 }
436
437 func TestAssumeUpdatePVCCache(t *testing.T) {
438 logger, _ := ktesting.NewTestContext(t)
439 cache := NewPVCAssumeCache(logger, nil)
440 internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
441 if !ok {
442 t.Fatalf("Failed to get internal cache")
443 }
444
445 pvcName := "test-pvc0"
446 pvcNamespace := "test-ns"
447
448
449 pvc := makeClaim(pvcName, "1", pvcNamespace)
450 internalCache.add(pvc)
451 if err := verifyPVC(cache, getPVCName(pvc), pvc); err != nil {
452 t.Fatalf("failed to get PVC: %v", err)
453 }
454
455
456 newPVC := pvc.DeepCopy()
457 newPVC.Annotations[volume.AnnSelectedNode] = "test-node"
458 if err := cache.Assume(newPVC); err != nil {
459 t.Fatalf("failed to assume PVC: %v", err)
460 }
461 if err := verifyPVC(cache, getPVCName(pvc), newPVC); err != nil {
462 t.Fatalf("failed to get PVC after assume: %v", err)
463 }
464
465
466 internalCache.add(pvc)
467 if err := verifyPVC(cache, getPVCName(pvc), newPVC); err != nil {
468 t.Fatalf("failed to get PVC after old PVC added: %v", err)
469 }
470 }
471
View as plain text