Skip to content

Commit 54d8f16

Browse files
committed
e2e/storage: improve PV checking
TestDynamicProvisioning had multiple ways of choosing additional checks: - the PvCheck callback - the builtin write/read check controlled by a boolean - the snapshot testing Complicating matters further, that builtin write/read test had been more customizable with new fields `NodeSelector` and `ExpectUnschedulable` which were only set by one particular test (see kubernetes#70941). That is confusing and will only get more confusing when adding more checks in the future. Therefore the write/read check is now a separate function that must be enabled explicitly by tests that want to run it. The snapshot checking is also defined only for the snapshot test. The test that expects unschedulable pods now also checks for that particular situation itself. Instead of testing it with two pods (the behavior from the write/read check) that both fail to start, only a single unschedulable pod is created. Because node name, node selector and the `ExpectUnschedulable` were only used for checking, it is possible to simplify `StorageClassTest` by removing all of these fields. Expect(err).NotTo(HaveOccurred()) is an anti-pattern in Ginkgo testing because a test failure doesn't explain what failed (see kubernetes#34059). We avoid it now by making the check function itself responsible for checking errors and including more information in those checks.
1 parent 5b8826b commit 54d8f16

File tree

4 files changed

+194
-137
lines changed

4 files changed

+194
-137
lines changed

test/e2e/storage/csi_volumes.go

+23-15
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,11 @@ var _ = utils.SIGDescribe("CSI Volumes", func() {
261261
Parameters: sc.Parameters,
262262
ClaimSize: "1Gi",
263263
ExpectedSize: "1Gi",
264-
NodeName: nodeName,
265264
}
266-
class, claim, pod := startPausePod(cs, scTest, ns.Name)
265+
nodeSelection := testsuites.NodeSelection{
266+
Name: nodeName,
267+
}
268+
class, claim, pod := startPausePod(cs, scTest, nodeSelection, ns.Name)
267269
if class != nil {
268270
defer cs.StorageV1().StorageClasses().Delete(class.Name, nil)
269271
}
@@ -381,16 +383,16 @@ var _ = utils.SIGDescribe("CSI Volumes", func() {
381383
Parameters: sc.Parameters,
382384
ClaimSize: "1Gi",
383385
ExpectedSize: "1Gi",
384-
// The mock driver only works when everything runs on a single node.
385-
NodeName: nodeName,
386386
// Provisioner and storage class name must match what's used in
387387
// csi-storageclass.yaml, plus the test-specific suffix.
388388
Provisioner: sc.Provisioner,
389389
StorageClassName: "csi-mock-sc-" + f.UniqueName,
390-
// Mock driver does not provide any persistency.
391-
SkipWriteReadCheck: true,
392390
}
393-
class, claim, pod := startPausePod(cs, scTest, ns.Name)
391+
nodeSelection := testsuites.NodeSelection{
392+
// The mock driver only works when everything runs on a single node.
393+
Name: nodeName,
394+
}
395+
class, claim, pod := startPausePod(cs, scTest, nodeSelection, ns.Name)
394396
if class != nil {
395397
defer cs.StorageV1().StorageClasses().Delete(class.Name, nil)
396398
}
@@ -429,7 +431,7 @@ func testTopologyPositive(cs clientset.Interface, suffix, namespace string, dela
429431
claim.Spec.StorageClassName = &class.Name
430432

431433
if delayBinding {
432-
_, node := testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class)
434+
_, node := testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class, nil /* node selector */, false /* expect unschedulable */)
433435
Expect(node).ToNot(BeNil(), "Unexpected nil node found")
434436
} else {
435437
testsuites.TestDynamicProvisioning(test, cs, claim, class)
@@ -450,16 +452,22 @@ func testTopologyNegative(cs clientset.Interface, suffix, namespace string, dela
450452

451453
test := createGCEPDStorageClassTest()
452454
test.DelayBinding = delayBinding
453-
test.NodeSelector = map[string]string{v1.LabelZoneFailureDomain: podZone}
454-
test.ExpectUnschedulable = true
455+
nodeSelector := map[string]string{v1.LabelZoneFailureDomain: podZone}
455456

456457
class := newStorageClass(test, namespace, suffix)
457458
addSingleCSIZoneAllowedTopologyToStorageClass(cs, class, pvZone)
458459
claim := newClaim(test, namespace, suffix)
459460
claim.Spec.StorageClassName = &class.Name
460461
if delayBinding {
461-
testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class)
462+
testsuites.TestBindingWaitForFirstConsumer(test, cs, claim, class, nodeSelector, true /* expect unschedulable */)
462463
} else {
464+
test.PvCheck = func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) {
465+
// Ensure that a pod cannot be scheduled in an unsuitable zone.
466+
pod := testsuites.StartInPodWithVolume(cs, namespace, claim.Name, "pvc-tester-unschedulable", "sleep 100000",
467+
testsuites.NodeSelection{Selector: nodeSelector})
468+
defer testsuites.StopPod(cs, pod)
469+
framework.ExpectNoError(framework.WaitForPodNameUnschedulableInNamespace(cs, pod.Name, pod.Namespace), "pod should be unschedulable")
470+
}
463471
testsuites.TestDynamicProvisioning(test, cs, claim, class)
464472
}
465473
}
@@ -500,7 +508,7 @@ func getVolumeHandle(cs clientset.Interface, claim *v1.PersistentVolumeClaim) st
500508
return pv.Spec.CSI.VolumeHandle
501509
}
502510

503-
func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns string) (*storagev1.StorageClass, *v1.PersistentVolumeClaim, *v1.Pod) {
511+
func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, node testsuites.NodeSelection, ns string) (*storagev1.StorageClass, *v1.PersistentVolumeClaim, *v1.Pod) {
504512
class := newStorageClass(t, ns, "")
505513
class, err := cs.StorageV1().StorageClasses().Create(class)
506514
framework.ExpectNoError(err, "Failed to create class : %v", err)
@@ -514,6 +522,9 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str
514522
GenerateName: "pvc-volume-tester-",
515523
},
516524
Spec: v1.PodSpec{
525+
NodeName: node.Name,
526+
NodeSelector: node.Selector,
527+
Affinity: node.Affinity,
517528
Containers: []v1.Container{
518529
{
519530
Name: "volume-tester",
@@ -541,9 +552,6 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str
541552
},
542553
}
543554

544-
if len(t.NodeName) != 0 {
545-
pod.Spec.NodeName = t.NodeName
546-
}
547555
pod, err = cs.CoreV1().Pods(ns).Create(pod)
548556
framework.ExpectNoError(err, "Failed to create pod: %v", err)
549557
return class, claim, pod

test/e2e/storage/regional_pd.go

+19-17
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,14 @@ func testVolumeProvisioning(c clientset.Interface, ns string) {
108108
},
109109
ClaimSize: "1.5Gi",
110110
ExpectedSize: "2Gi",
111-
PvCheck: func(volume *v1.PersistentVolume) error {
112-
err := checkGCEPD(volume, "pd-standard")
113-
if err != nil {
114-
return err
115-
}
116-
return verifyZonesInPV(volume, sets.NewString(cloudZones...), true /* match */)
111+
PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) {
112+
var err error
113+
err = checkGCEPD(volume, "pd-standard")
114+
Expect(err).NotTo(HaveOccurred(), "checkGCEPD")
115+
err = verifyZonesInPV(volume, sets.NewString(cloudZones...), true /* match */)
116+
Expect(err).NotTo(HaveOccurred(), "verifyZonesInPV")
117+
118+
testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{})
117119
},
118120
},
119121
{
@@ -126,16 +128,16 @@ func testVolumeProvisioning(c clientset.Interface, ns string) {
126128
},
127129
ClaimSize: "1.5Gi",
128130
ExpectedSize: "2Gi",
129-
PvCheck: func(volume *v1.PersistentVolume) error {
130-
err := checkGCEPD(volume, "pd-standard")
131-
if err != nil {
132-
return err
133-
}
131+
PvCheck: func(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) {
132+
var err error
133+
err = checkGCEPD(volume, "pd-standard")
134+
Expect(err).NotTo(HaveOccurred(), "checkGCEPD")
134135
zones, err := framework.GetClusterZones(c)
135-
if err != nil {
136-
return err
137-
}
138-
return verifyZonesInPV(volume, zones, false /* match */)
136+
Expect(err).NotTo(HaveOccurred(), "GetClusterZones")
137+
err = verifyZonesInPV(volume, zones, false /* match */)
138+
Expect(err).NotTo(HaveOccurred(), "verifyZonesInPV")
139+
140+
testsuites.PVWriteReadCheck(c, claim, volume, testsuites.NodeSelection{})
139141
},
140142
},
141143
}
@@ -317,7 +319,7 @@ func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int)
317319
claim.Spec.StorageClassName = &class.Name
318320
claims = append(claims, claim)
319321
}
320-
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class)
322+
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */)
321323
if node == nil {
322324
framework.Failf("unexpected nil node found")
323325
}
@@ -374,7 +376,7 @@ func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns s
374376
claim.Spec.StorageClassName = &class.Name
375377
claims = append(claims, claim)
376378
}
377-
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class)
379+
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */)
378380
if node == nil {
379381
framework.Failf("unexpected nil node found")
380382
}

0 commit comments

Comments
 (0)