Skip to content

Commit 160da35

Browse files
committed
e2e storage: public API for testsuites, support CSIInlineVolume type for generic resource
Implementing a test suite was impossible outside of the k8s.io/kubernetes/test/e2e/storage/testsuites package because all interfaces and structs used by them were private. As part of revamping the API, genericVolumeTestResource also gets exported because it is useful for other test suites. Because the TestResource interface became obsolete a while ago and isn't used anymore, the new name is just testsuites.VolumeResource. testpatterns.CSIInlineVolume needs special handling in a few places. It can now be used in a test pattern for a test suite that uses a VolumeResource instance.
1 parent bea2ca7 commit 160da35

File tree

15 files changed

+333
-298
lines changed

15 files changed

+333
-298
lines changed

test/e2e/storage/testpatterns/testpattern.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ var (
7676
Name: "Inline-volume (default fs)",
7777
VolType: InlineVolume,
7878
}
79+
// DefaultFsEphemeralVolume is TestPattern for "Ephemeral-volume (default fs)"
80+
DefaultFsEphemeralVolume = TestPattern{
81+
Name: "Ephemeral-volume (default fs)",
82+
VolType: CSIInlineVolume,
83+
}
7984
// DefaultFsPreprovisionedPV is TestPattern for "Pre-provisioned PV (default fs)"
8085
DefaultFsPreprovisionedPV = TestPattern{
8186
Name: "Pre-provisioned PV (default fs)",
@@ -95,6 +100,12 @@ var (
95100
VolType: InlineVolume,
96101
FsType: "ext3",
97102
}
103+
// Ext3EphemeralVolume is TestPattern for "Ephemeral-volume (ext3)"
104+
Ext3EphemeralVolume = TestPattern{
105+
Name: "Ephemeral-volume (ext3)",
106+
VolType: InlineVolume,
107+
FsType: "ext3",
108+
}
98109
// Ext3PreprovisionedPV is TestPattern for "Pre-provisioned PV (ext3)"
99110
Ext3PreprovisionedPV = TestPattern{
100111
Name: "Pre-provisioned PV (ext3)",
@@ -116,6 +127,12 @@ var (
116127
VolType: InlineVolume,
117128
FsType: "ext4",
118129
}
130+
// Ext4EphemeralVolume is TestPattern for "Ephemeral-volume (ext4)"
131+
Ext4EphemeralVolume = TestPattern{
132+
Name: "Ephemeral-volume (ext4)",
133+
VolType: CSIInlineVolume,
134+
FsType: "ext4",
135+
}
119136
// Ext4PreprovisionedPV is TestPattern for "Pre-provisioned PV (ext4)"
120137
Ext4PreprovisionedPV = TestPattern{
121138
Name: "Pre-provisioned PV (ext4)",
@@ -138,6 +155,13 @@ var (
138155
FsType: "xfs",
139156
FeatureTag: "[Slow]",
140157
}
158+
// XfsEphemeralVolume is TestPattern for "Ephemeral-volume (xfs)"
159+
XfsEphemeralVolume = TestPattern{
160+
Name: "Ephemeral-volume (xfs)",
161+
VolType: CSIInlineVolume,
162+
FsType: "xfs",
163+
FeatureTag: "[Slow]",
164+
}
141165
// XfsPreprovisionedPV is TestPattern for "Pre-provisioned PV (xfs)"
142166
XfsPreprovisionedPV = TestPattern{
143167
Name: "Pre-provisioned PV (xfs)",
@@ -162,6 +186,13 @@ var (
162186
FsType: "ntfs",
163187
FeatureTag: "[sig-windows]",
164188
}
189+
// NtfsEphemeralVolume is TestPattern for "Ephemeral-volume (ntfs)"
190+
NtfsEphemeralVolume = TestPattern{
191+
Name: "Ephemeral-volume (ntfs)",
192+
VolType: CSIInlineVolume,
193+
FsType: "ntfs",
194+
FeatureTag: "[sig-windows]",
195+
}
165196
// NtfsPreprovisionedPV is TestPattern for "Pre-provisioned PV (ntfs)"
166197
NtfsPreprovisionedPV = TestPattern{
167198
Name: "Pre-provisioned PV (ntfs)",

test/e2e/storage/testsuites/base.go

Lines changed: 84 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -62,48 +62,42 @@ type opCounts map[string]int64
6262

6363
// TestSuite represents an interface for a set of tests which works with TestDriver
6464
type TestSuite interface {
65-
// getTestSuiteInfo returns the TestSuiteInfo for this TestSuite
66-
getTestSuiteInfo() TestSuiteInfo
67-
// defineTest defines tests of the testpattern for the driver.
65+
// GetTestSuiteInfo returns the TestSuiteInfo for this TestSuite
66+
GetTestSuiteInfo() TestSuiteInfo
67+
// DefineTests defines tests of the testpattern for the driver.
6868
// Called inside a Ginkgo context that reflects the current driver and test pattern,
6969
// so the test suite can define tests directly with ginkgo.It.
70-
defineTests(TestDriver, testpatterns.TestPattern)
71-
// skipRedundantSuite will skip the test suite based on the given TestPattern and TestDriver
72-
skipRedundantSuite(TestDriver, testpatterns.TestPattern)
70+
DefineTests(TestDriver, testpatterns.TestPattern)
71+
// SkipRedundantSuite will skip the test suite based on the given TestPattern and TestDriver
72+
SkipRedundantSuite(TestDriver, testpatterns.TestPattern)
7373
}
7474

7575
// TestSuiteInfo represents a set of parameters for TestSuite
7676
type TestSuiteInfo struct {
77-
name string // name of the TestSuite
78-
featureTag string // featureTag for the TestSuite
79-
testPatterns []testpatterns.TestPattern // Slice of TestPattern for the TestSuite
80-
supportedSizeRange volume.SizeRange // Size range supported by the test suite
81-
}
82-
83-
// TestResource represents an interface for resources that is used by TestSuite
84-
type TestResource interface {
85-
// cleanupResource cleans up the test resources created when setting up the resource
86-
cleanupResource() error
77+
Name string // name of the TestSuite
78+
FeatureTag string // featureTag for the TestSuite
79+
TestPatterns []testpatterns.TestPattern // Slice of TestPattern for the TestSuite
80+
SupportedSizeRange volume.SizeRange // Size range supported by the test suite
8781
}
8882

8983
func getTestNameStr(suite TestSuite, pattern testpatterns.TestPattern) string {
90-
tsInfo := suite.getTestSuiteInfo()
91-
return fmt.Sprintf("[Testpattern: %s]%s %s%s", pattern.Name, pattern.FeatureTag, tsInfo.name, tsInfo.featureTag)
84+
tsInfo := suite.GetTestSuiteInfo()
85+
return fmt.Sprintf("[Testpattern: %s]%s %s%s", pattern.Name, pattern.FeatureTag, tsInfo.Name, tsInfo.FeatureTag)
9286
}
9387

9488
// DefineTestSuite defines tests for all testpatterns and all testSuites for a driver
9589
func DefineTestSuite(driver TestDriver, tsInits []func() TestSuite) {
9690
for _, testSuiteInit := range tsInits {
9791
suite := testSuiteInit()
98-
for _, pattern := range suite.getTestSuiteInfo().testPatterns {
92+
for _, pattern := range suite.GetTestSuiteInfo().TestPatterns {
9993
p := pattern
10094
ginkgo.Context(getTestNameStr(suite, p), func() {
10195
ginkgo.BeforeEach(func() {
10296
// Skip unsupported tests to avoid unnecessary resource initialization
103-
suite.skipRedundantSuite(driver, p)
97+
suite.SkipRedundantSuite(driver, p)
10498
skipUnsupportedTest(driver, p)
10599
})
106-
suite.defineTests(driver, p)
100+
suite.DefineTests(driver, p)
107101
})
108102
}
109103
}
@@ -117,7 +111,7 @@ func DefineTestSuite(driver TestDriver, tsInits []func() TestSuite) {
117111
// 3. Check if fsType is supported
118112
// 4. Check with driver specific logic
119113
//
120-
// Test suites can also skip tests inside their own defineTests function or in
114+
// Test suites can also skip tests inside their own DefineTests function or in
121115
// individual tests.
122116
func skipUnsupportedTest(driver TestDriver, pattern testpatterns.TestPattern) {
123117
dInfo := driver.GetDriverInfo()
@@ -170,54 +164,52 @@ func skipUnsupportedTest(driver TestDriver, pattern testpatterns.TestPattern) {
170164
driver.SkipUnsupportedTest(pattern)
171165
}
172166

173-
// genericVolumeTestResource is a generic implementation of TestResource that wil be able to
167+
// VolumeResource is a generic implementation of TestResource that wil be able to
174168
// be used in most of TestSuites.
175169
// See volume_io.go or volumes.go in test/e2e/storage/testsuites/ for how to use this resource.
176170
// Also, see subpath.go in the same directory for how to extend and use it.
177-
type genericVolumeTestResource struct {
178-
driver TestDriver
179-
config *PerTestConfig
180-
pattern testpatterns.TestPattern
181-
volType string
182-
volSource *v1.VolumeSource
183-
pvc *v1.PersistentVolumeClaim
184-
pv *v1.PersistentVolume
185-
sc *storagev1.StorageClass
186-
187-
volume TestVolume
171+
type VolumeResource struct {
172+
Config *PerTestConfig
173+
Pattern testpatterns.TestPattern
174+
VolType string
175+
VolSource *v1.VolumeSource
176+
Pvc *v1.PersistentVolumeClaim
177+
Pv *v1.PersistentVolume
178+
Sc *storagev1.StorageClass
179+
180+
Volume TestVolume
188181
}
189182

190-
var _ TestResource = &genericVolumeTestResource{}
191-
192-
func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, pattern testpatterns.TestPattern, testVolumeSizeRange volume.SizeRange) *genericVolumeTestResource {
193-
r := genericVolumeTestResource{
194-
driver: driver,
195-
config: config,
196-
pattern: pattern,
183+
// CreateVolumeResource constructs a VolumeResource for the current test. It knows how to deal with
184+
// different test pattern volume types.
185+
func CreateVolumeResource(driver TestDriver, config *PerTestConfig, pattern testpatterns.TestPattern, testVolumeSizeRange volume.SizeRange) *VolumeResource {
186+
r := VolumeResource{
187+
Config: config,
188+
Pattern: pattern,
197189
}
198190
dInfo := driver.GetDriverInfo()
199191
f := config.Framework
200192
cs := f.ClientSet
201193

202194
// Create volume for pre-provisioned volume tests
203-
r.volume = CreateVolume(driver, config, pattern.VolType)
195+
r.Volume = CreateVolume(driver, config, pattern.VolType)
204196

205197
switch pattern.VolType {
206198
case testpatterns.InlineVolume:
207199
framework.Logf("Creating resource for inline volume")
208200
if iDriver, ok := driver.(InlineVolumeTestDriver); ok {
209-
r.volSource = iDriver.GetVolumeSource(false, pattern.FsType, r.volume)
210-
r.volType = dInfo.Name
201+
r.VolSource = iDriver.GetVolumeSource(false, pattern.FsType, r.Volume)
202+
r.VolType = dInfo.Name
211203
}
212204
case testpatterns.PreprovisionedPV:
213205
framework.Logf("Creating resource for pre-provisioned PV")
214206
if pDriver, ok := driver.(PreprovisionedPVTestDriver); ok {
215-
pvSource, volumeNodeAffinity := pDriver.GetPersistentVolumeSource(false, pattern.FsType, r.volume)
207+
pvSource, volumeNodeAffinity := pDriver.GetPersistentVolumeSource(false, pattern.FsType, r.Volume)
216208
if pvSource != nil {
217-
r.pv, r.pvc = createPVCPV(f, dInfo.Name, pvSource, volumeNodeAffinity, pattern.VolMode, dInfo.RequiredAccessModes)
218-
r.volSource = createVolumeSource(r.pvc.Name, false /* readOnly */)
209+
r.Pv, r.Pvc = createPVCPV(f, dInfo.Name, pvSource, volumeNodeAffinity, pattern.VolMode, dInfo.RequiredAccessModes)
210+
r.VolSource = createVolumeSource(r.Pvc.Name, false /* readOnly */)
219211
}
220-
r.volType = fmt.Sprintf("%s-preprovisionedPV", dInfo.Name)
212+
r.VolType = fmt.Sprintf("%s-preprovisionedPV", dInfo.Name)
221213
}
222214
case testpatterns.DynamicPV:
223215
framework.Logf("Creating resource for dynamic PV")
@@ -227,32 +219,44 @@ func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, p
227219
claimSize, err := getSizeRangesIntersection(testVolumeSizeRange, driverVolumeSizeRange)
228220
framework.ExpectNoError(err, "determine intersection of test size range %+v and driver size range %+v", testVolumeSizeRange, driverVolumeSizeRange)
229221
framework.Logf("Using claimSize:%s, test suite supported size:%v, driver(%s) supported size:%v ", claimSize, testVolumeSizeRange, dDriver.GetDriverInfo().Name, testVolumeSizeRange)
230-
r.sc = dDriver.GetDynamicProvisionStorageClass(r.config, pattern.FsType)
222+
r.Sc = dDriver.GetDynamicProvisionStorageClass(r.Config, pattern.FsType)
231223

232224
if pattern.BindingMode != "" {
233-
r.sc.VolumeBindingMode = &pattern.BindingMode
225+
r.Sc.VolumeBindingMode = &pattern.BindingMode
234226
}
235227
if pattern.AllowExpansion != false {
236-
r.sc.AllowVolumeExpansion = &pattern.AllowExpansion
228+
r.Sc.AllowVolumeExpansion = &pattern.AllowExpansion
237229
}
238230

239-
ginkgo.By("creating a StorageClass " + r.sc.Name)
231+
ginkgo.By("creating a StorageClass " + r.Sc.Name)
240232

241-
r.sc, err = cs.StorageV1().StorageClasses().Create(r.sc)
233+
r.Sc, err = cs.StorageV1().StorageClasses().Create(r.Sc)
242234
framework.ExpectNoError(err)
243235

244-
if r.sc != nil {
245-
r.pv, r.pvc = createPVCPVFromDynamicProvisionSC(
246-
f, dInfo.Name, claimSize, r.sc, pattern.VolMode, dInfo.RequiredAccessModes)
247-
r.volSource = createVolumeSource(r.pvc.Name, false /* readOnly */)
236+
if r.Sc != nil {
237+
r.Pv, r.Pvc = createPVCPVFromDynamicProvisionSC(
238+
f, dInfo.Name, claimSize, r.Sc, pattern.VolMode, dInfo.RequiredAccessModes)
239+
r.VolSource = createVolumeSource(r.Pvc.Name, false /* readOnly */)
240+
}
241+
r.VolType = fmt.Sprintf("%s-dynamicPV", dInfo.Name)
242+
}
243+
case testpatterns.CSIInlineVolume:
244+
framework.Logf("Creating resource for CSI ephemeral inline volume")
245+
if eDriver, ok := driver.(EphemeralTestDriver); ok {
246+
r.VolType = fmt.Sprintf("%s-ephemeral", dInfo.Name)
247+
attributes, _, _ := eDriver.GetVolume(config, 0)
248+
r.VolSource = &v1.VolumeSource{
249+
CSI: &v1.CSIVolumeSource{
250+
Driver: eDriver.GetCSIDriverName(config),
251+
VolumeAttributes: attributes,
252+
},
248253
}
249-
r.volType = fmt.Sprintf("%s-dynamicPV", dInfo.Name)
250254
}
251255
default:
252-
framework.Failf("genericVolumeTestResource doesn't support: %s", pattern.VolType)
256+
framework.Failf("VolumeResource doesn't support: %s", pattern.VolType)
253257
}
254258

255-
if r.volSource == nil {
259+
if r.VolSource == nil {
256260
framework.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.VolType)
257261
}
258262

@@ -269,52 +273,52 @@ func createVolumeSource(pvcName string, readOnly bool) *v1.VolumeSource {
269273

270274
}
271275

272-
// cleanupResource cleans up genericVolumeTestResource
273-
func (r *genericVolumeTestResource) cleanupResource() error {
274-
f := r.config.Framework
276+
// CleanupResource cleans up VolumeResource
277+
func (r *VolumeResource) CleanupResource() error {
278+
f := r.Config.Framework
275279
var cleanUpErrs []error
276-
if r.pvc != nil || r.pv != nil {
277-
switch r.pattern.VolType {
280+
if r.Pvc != nil || r.Pv != nil {
281+
switch r.Pattern.VolType {
278282
case testpatterns.PreprovisionedPV:
279283
ginkgo.By("Deleting pv and pvc")
280-
if errs := e2epv.PVPVCCleanup(f.ClientSet, f.Namespace.Name, r.pv, r.pvc); len(errs) != 0 {
284+
if errs := e2epv.PVPVCCleanup(f.ClientSet, f.Namespace.Name, r.Pv, r.Pvc); len(errs) != 0 {
281285
framework.Failf("Failed to delete PVC or PV: %v", utilerrors.NewAggregate(errs))
282286
}
283287
case testpatterns.DynamicPV:
284288
ginkgo.By("Deleting pvc")
285289
// We only delete the PVC so that PV (and disk) can be cleaned up by dynamic provisioner
286-
if r.pv != nil && r.pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimDelete {
290+
if r.Pv != nil && r.Pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimDelete {
287291
framework.Failf("Test framework does not currently support Dynamically Provisioned Persistent Volume %v specified with reclaim policy that isnt %v",
288-
r.pv.Name, v1.PersistentVolumeReclaimDelete)
292+
r.Pv.Name, v1.PersistentVolumeReclaimDelete)
289293
}
290-
if r.pvc != nil {
291-
err := e2epv.DeletePersistentVolumeClaim(f.ClientSet, r.pvc.Name, f.Namespace.Name)
294+
if r.Pvc != nil {
295+
err := e2epv.DeletePersistentVolumeClaim(f.ClientSet, r.Pvc.Name, f.Namespace.Name)
292296
if err != nil {
293-
cleanUpErrs = append(cleanUpErrs, errors.Wrapf(err, "Failed to delete PVC %v", r.pvc.Name))
297+
cleanUpErrs = append(cleanUpErrs, errors.Wrapf(err, "Failed to delete PVC %v", r.Pvc.Name))
294298
}
295-
if r.pv != nil {
296-
err = framework.WaitForPersistentVolumeDeleted(f.ClientSet, r.pv.Name, 5*time.Second, 5*time.Minute)
299+
if r.Pv != nil {
300+
err = framework.WaitForPersistentVolumeDeleted(f.ClientSet, r.Pv.Name, 5*time.Second, 5*time.Minute)
297301
if err != nil {
298302
cleanUpErrs = append(cleanUpErrs, errors.Wrapf(err,
299-
"Persistent Volume %v not deleted by dynamic provisioner", r.pv.Name))
303+
"Persistent Volume %v not deleted by dynamic provisioner", r.Pv.Name))
300304
}
301305
}
302306
}
303307
default:
304-
framework.Failf("Found PVC (%v) or PV (%v) but not running Preprovisioned or Dynamic test pattern", r.pvc, r.pv)
308+
framework.Failf("Found PVC (%v) or PV (%v) but not running Preprovisioned or Dynamic test pattern", r.Pvc, r.Pv)
305309
}
306310
}
307311

308-
if r.sc != nil {
312+
if r.Sc != nil {
309313
ginkgo.By("Deleting sc")
310-
if err := deleteStorageClass(f.ClientSet, r.sc.Name); err != nil {
311-
cleanUpErrs = append(cleanUpErrs, errors.Wrapf(err, "Failed to delete StorageClass %v", r.sc.Name))
314+
if err := deleteStorageClass(f.ClientSet, r.Sc.Name); err != nil {
315+
cleanUpErrs = append(cleanUpErrs, errors.Wrapf(err, "Failed to delete StorageClass %v", r.Sc.Name))
312316
}
313317
}
314318

315319
// Cleanup volume for pre-provisioned volume tests
316-
if r.volume != nil {
317-
if err := tryFunc(r.volume.DeleteVolume); err != nil {
320+
if r.Volume != nil {
321+
if err := tryFunc(r.Volume.DeleteVolume); err != nil {
318322
cleanUpErrs = append(cleanUpErrs, errors.Wrap(err, "Failed to delete Volume"))
319323
}
320324
}

0 commit comments

Comments
 (0)