Commit 05cc3169 authored by Patrick Ohly's avatar Patrick Ohly

e2e/storage: speed up skipping, simplify APIs and test definition

CreateDriver (now called SetupTest) is a potentially expensive operation, depending on the driver. Creating and tearing down a framework instance also takes time (measured at 6 seconds on a fast machine) and produces quite a bit of log output. Both can be avoided for tests that skip based on static information (like for instance the current OS, vendor, driver and test pattern) by making the test suite responsible for creating framework and driver. The lifecycle of the TestConfig instance was confusing because it was stored inside the DriverInfo, a struct which conceptually is static, while the TestConfig is dynamic. It is cleaner to separate the two, even if that means that an additional pointer must be passed into some functions. Now CreateDriver is responsible for initializing the PerTestConfig that is to be used by the test. To make this approach simpler to implement (= less functions which need the pointer) and the tests easier to read, the entire setup and test definition is now contained in a single function. This is how it is normally done in Ginkgo. This is easier to read because one can see at a glance where variables are set, instead of having to trace values though two additional structs (TestResource and TestInput). Because we are changing the API already, also other changes are made: - some function prototypes get simplified - the naming of functions is changed to match their purpose (tests aren't executed by the test suite, they only get defined for later execution) - unused methods get removed (TestSuite.skipUnsupportedTest is redundant)
parent 1cb121d2
...@@ -18,7 +18,6 @@ package storage ...@@ -18,7 +18,6 @@ package storage
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
"k8s.io/kubernetes/test/e2e/framework"
"k8s.io/kubernetes/test/e2e/storage/drivers" "k8s.io/kubernetes/test/e2e/storage/drivers"
"k8s.io/kubernetes/test/e2e/storage/testpatterns" "k8s.io/kubernetes/test/e2e/storage/testpatterns"
"k8s.io/kubernetes/test/e2e/storage/testsuites" "k8s.io/kubernetes/test/e2e/storage/testsuites"
...@@ -26,7 +25,7 @@ import ( ...@@ -26,7 +25,7 @@ import (
) )
// List of testDrivers to be executed in below loop // List of testDrivers to be executed in below loop
var testDrivers = []func(config testsuites.TestConfig) testsuites.TestDriver{ var testDrivers = []func() testsuites.TestDriver{
drivers.InitNFSDriver, drivers.InitNFSDriver,
drivers.InitGlusterFSDriver, drivers.InitGlusterFSDriver,
drivers.InitISCSIDriver, drivers.InitISCSIDriver,
...@@ -65,35 +64,11 @@ func intreeTunePattern(patterns []testpatterns.TestPattern) []testpatterns.TestP ...@@ -65,35 +64,11 @@ func intreeTunePattern(patterns []testpatterns.TestPattern) []testpatterns.TestP
// This executes testSuites for in-tree volumes. // This executes testSuites for in-tree volumes.
var _ = utils.SIGDescribe("In-tree Volumes", func() { var _ = utils.SIGDescribe("In-tree Volumes", func() {
f := framework.NewDefaultFramework("volumes")
var (
// Common configuration options for all drivers.
config = testsuites.TestConfig{
Framework: f,
Prefix: "in-tree",
}
)
for _, initDriver := range testDrivers { for _, initDriver := range testDrivers {
curDriver := initDriver(config) curDriver := initDriver()
curConfig := curDriver.GetDriverInfo().Config
Context(testsuites.GetDriverNameWithFeatureTags(curDriver), func() {
BeforeEach(func() {
// Reset config. The driver might have modified its copy
// in a previous test.
curDriver.GetDriverInfo().Config = curConfig
// setupDriver Context(testsuites.GetDriverNameWithFeatureTags(curDriver), func() {
curDriver.CreateDriver() testsuites.DefineTestSuite(curDriver, testSuites, intreeTunePattern)
})
AfterEach(func() {
// Cleanup driver
curDriver.CleanupDriver()
})
testsuites.RunTestSuite(f, curDriver, testSuites, intreeTunePattern)
}) })
} }
}) })
...@@ -143,10 +143,11 @@ func testVolumeProvisioning(c clientset.Interface, ns string) { ...@@ -143,10 +143,11 @@ func testVolumeProvisioning(c clientset.Interface, ns string) {
} }
for _, test := range tests { for _, test := range tests {
class := newStorageClass(test, ns, "" /* suffix */) test.Client = c
claim := newClaim(test, ns, "" /* suffix */) test.Class = newStorageClass(test, ns, "" /* suffix */)
claim.Spec.StorageClassName = &class.Name test.Claim = newClaim(test, ns, "" /* suffix */)
testsuites.TestDynamicProvisioning(test, c, claim, class) test.Claim.Spec.StorageClassName = &test.Class.Name
test.TestDynamicProvisioning()
} }
} }
...@@ -301,6 +302,7 @@ func addTaint(c clientset.Interface, ns string, nodes []v1.Node, podZone string) ...@@ -301,6 +302,7 @@ func addTaint(c clientset.Interface, ns string, nodes []v1.Node, podZone string)
func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int) { func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int) {
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "Regional PD storage class with waitForFirstConsumer test on GCE", Name: "Regional PD storage class with waitForFirstConsumer test on GCE",
Provisioner: "kubernetes.io/gce-pd", Provisioner: "kubernetes.io/gce-pd",
Parameters: map[string]string{ Parameters: map[string]string{
...@@ -312,14 +314,14 @@ func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int) ...@@ -312,14 +314,14 @@ func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int)
} }
suffix := "delayed-regional" suffix := "delayed-regional"
class := newStorageClass(test, ns, suffix) test.Class = newStorageClass(test, ns, suffix)
var claims []*v1.PersistentVolumeClaim var claims []*v1.PersistentVolumeClaim
for i := 0; i < pvcCount; i++ { for i := 0; i < pvcCount; i++ {
claim := newClaim(test, ns, suffix) claim := newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name claim.Spec.StorageClassName = &test.Class.Name
claims = append(claims, claim) claims = append(claims, claim)
} }
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) pvs, node := test.TestBindingWaitForFirstConsumerMultiPVC(claims, nil /* node selector */, false /* expect unschedulable */)
if node == nil { if node == nil {
framework.Failf("unexpected nil node found") framework.Failf("unexpected nil node found")
} }
...@@ -345,17 +347,20 @@ func testRegionalAllowedTopologies(c clientset.Interface, ns string) { ...@@ -345,17 +347,20 @@ func testRegionalAllowedTopologies(c clientset.Interface, ns string) {
} }
suffix := "topo-regional" suffix := "topo-regional"
class := newStorageClass(test, ns, suffix) test.Client = c
test.Class = newStorageClass(test, ns, suffix)
zones := getTwoRandomZones(c) zones := getTwoRandomZones(c)
addAllowedTopologiesToStorageClass(c, class, zones) addAllowedTopologiesToStorageClass(c, test.Class, zones)
claim := newClaim(test, ns, suffix) test.Claim = newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name test.Claim.Spec.StorageClassName = &test.Class.Name
pv := testsuites.TestDynamicProvisioning(test, c, claim, class)
pv := test.TestDynamicProvisioning()
checkZonesFromLabelAndAffinity(pv, sets.NewString(zones...), true) checkZonesFromLabelAndAffinity(pv, sets.NewString(zones...), true)
} }
func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns string, pvcCount int) { func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns string, pvcCount int) {
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "Regional PD storage class with allowedTopologies and waitForFirstConsumer test on GCE", Name: "Regional PD storage class with allowedTopologies and waitForFirstConsumer test on GCE",
Provisioner: "kubernetes.io/gce-pd", Provisioner: "kubernetes.io/gce-pd",
Parameters: map[string]string{ Parameters: map[string]string{
...@@ -367,16 +372,16 @@ func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns s ...@@ -367,16 +372,16 @@ func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns s
} }
suffix := "topo-delayed-regional" suffix := "topo-delayed-regional"
class := newStorageClass(test, ns, suffix) test.Class = newStorageClass(test, ns, suffix)
topoZones := getTwoRandomZones(c) topoZones := getTwoRandomZones(c)
addAllowedTopologiesToStorageClass(c, class, topoZones) addAllowedTopologiesToStorageClass(c, test.Class, topoZones)
var claims []*v1.PersistentVolumeClaim var claims []*v1.PersistentVolumeClaim
for i := 0; i < pvcCount; i++ { for i := 0; i < pvcCount; i++ {
claim := newClaim(test, ns, suffix) claim := newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name claim.Spec.StorageClassName = &test.Class.Name
claims = append(claims, claim) claims = append(claims, claim)
} }
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) pvs, node := test.TestBindingWaitForFirstConsumerMultiPVC(claims, nil /* node selector */, false /* expect unschedulable */)
if node == nil { if node == nil {
framework.Failf("unexpected nil node found") framework.Failf("unexpected nil node found")
} }
......
...@@ -17,7 +17,9 @@ limitations under the License. ...@@ -17,7 +17,9 @@ limitations under the License.
package testsuites package testsuites
import ( import (
"context"
"fmt" "fmt"
"regexp"
"time" "time"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
...@@ -32,6 +34,7 @@ import ( ...@@ -32,6 +34,7 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
"k8s.io/kubernetes/test/e2e/framework/podlogs"
"k8s.io/kubernetes/test/e2e/storage/testpatterns" "k8s.io/kubernetes/test/e2e/storage/testpatterns"
) )
...@@ -39,10 +42,10 @@ import ( ...@@ -39,10 +42,10 @@ import (
type TestSuite interface { type TestSuite interface {
// getTestSuiteInfo returns the TestSuiteInfo for this TestSuite // getTestSuiteInfo returns the TestSuiteInfo for this TestSuite
getTestSuiteInfo() TestSuiteInfo getTestSuiteInfo() TestSuiteInfo
// skipUnsupportedTest skips the test if this TestSuite is not suitable to be tested with the combination of TestPattern and TestDriver // defineTest defines tests of the testpattern for the driver.
skipUnsupportedTest(testpatterns.TestPattern, TestDriver) // Called inside a Ginkgo context that reflects the current driver and test pattern,
// execTest executes test of the testpattern for the driver // so the test suite can define tests directly with ginkgo.It.
execTest(TestDriver, testpatterns.TestPattern) defineTests(TestDriver, testpatterns.TestPattern)
} }
// TestSuiteInfo represents a set of parameters for TestSuite // TestSuiteInfo represents a set of parameters for TestSuite
...@@ -54,11 +57,8 @@ type TestSuiteInfo struct { ...@@ -54,11 +57,8 @@ type TestSuiteInfo struct {
// TestResource represents an interface for resources that is used by TestSuite // TestResource represents an interface for resources that is used by TestSuite
type TestResource interface { type TestResource interface {
// setupResource sets up test resources to be used for the tests with the // cleanupResource cleans up the test resources created when setting up the resource
// combination of TestDriver and TestPattern cleanupResource()
setupResource(TestDriver, testpatterns.TestPattern)
// cleanupResource clean up the test resources created in SetupResource
cleanupResource(TestDriver, testpatterns.TestPattern)
} }
func getTestNameStr(suite TestSuite, pattern testpatterns.TestPattern) string { func getTestNameStr(suite TestSuite, pattern testpatterns.TestPattern) string {
...@@ -66,27 +66,36 @@ func getTestNameStr(suite TestSuite, pattern testpatterns.TestPattern) string { ...@@ -66,27 +66,36 @@ func getTestNameStr(suite TestSuite, pattern testpatterns.TestPattern) string {
return fmt.Sprintf("[Testpattern: %s]%s %s%s", pattern.Name, pattern.FeatureTag, tsInfo.name, tsInfo.featureTag) return fmt.Sprintf("[Testpattern: %s]%s %s%s", pattern.Name, pattern.FeatureTag, tsInfo.name, tsInfo.featureTag)
} }
// RunTestSuite runs all testpatterns of all testSuites for a driver // DefineTestSuite defines tests for all testpatterns and all testSuites for a driver
func RunTestSuite(f *framework.Framework, driver TestDriver, tsInits []func() TestSuite, tunePatternFunc func([]testpatterns.TestPattern) []testpatterns.TestPattern) { func DefineTestSuite(driver TestDriver, tsInits []func() TestSuite, tunePatternFunc func([]testpatterns.TestPattern) []testpatterns.TestPattern) {
for _, testSuiteInit := range tsInits { for _, testSuiteInit := range tsInits {
suite := testSuiteInit() suite := testSuiteInit()
patterns := tunePatternFunc(suite.getTestSuiteInfo().testPatterns) patterns := tunePatternFunc(suite.getTestSuiteInfo().testPatterns)
for _, pattern := range patterns { for _, pattern := range patterns {
suite.execTest(driver, pattern) p := pattern
Context(getTestNameStr(suite, p), func() {
BeforeEach(func() {
// Skip unsupported tests to avoid unnecessary resource initialization
skipUnsupportedTest(driver, p)
})
suite.defineTests(driver, p)
})
} }
} }
} }
// skipUnsupportedTest will skip tests if the combination of driver, testsuite, and testpattern // skipUnsupportedTest will skip tests if the combination of driver, and testpattern
// is not suitable to be tested. // is not suitable to be tested.
// Whether it needs to be skipped is checked by following steps: // Whether it needs to be skipped is checked by following steps:
// 1. Check if Whether SnapshotType is supported by driver from its interface // 1. Check if Whether SnapshotType is supported by driver from its interface
// 2. Check if Whether volType is supported by driver from its interface // 2. Check if Whether volType is supported by driver from its interface
// 3. Check if fsType is supported // 3. Check if fsType is supported
// 4. Check with driver specific logic // 4. Check with driver specific logic
// 5. Check with testSuite specific logic //
func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpatterns.TestPattern) { // Test suites can also skip tests inside their own defineTests function or in
// individual tests.
func skipUnsupportedTest(driver TestDriver, pattern testpatterns.TestPattern) {
dInfo := driver.GetDriverInfo() dInfo := driver.GetDriverInfo()
var isSupported bool var isSupported bool
...@@ -130,9 +139,6 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern ...@@ -130,9 +139,6 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern
// 4. Check with driver specific logic // 4. Check with driver specific logic
driver.SkipUnsupportedTest(pattern) driver.SkipUnsupportedTest(pattern)
// 5. Check with testSuite specific logic
suite.skipUnsupportedTest(pattern, driver)
} }
// genericVolumeTestResource is a generic implementation of TestResource that wil be able to // genericVolumeTestResource is a generic implementation of TestResource that wil be able to
...@@ -141,6 +147,8 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern ...@@ -141,6 +147,8 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern
// Also, see subpath.go in the same directory for how to extend and use it. // Also, see subpath.go in the same directory for how to extend and use it.
type genericVolumeTestResource struct { type genericVolumeTestResource struct {
driver TestDriver driver TestDriver
config *PerTestConfig
pattern testpatterns.TestPattern
volType string volType string
volSource *v1.VolumeSource volSource *v1.VolumeSource
pvc *v1.PersistentVolumeClaim pvc *v1.PersistentVolumeClaim
...@@ -152,17 +160,20 @@ type genericVolumeTestResource struct { ...@@ -152,17 +160,20 @@ type genericVolumeTestResource struct {
var _ TestResource = &genericVolumeTestResource{} var _ TestResource = &genericVolumeTestResource{}
// setupResource sets up genericVolumeTestResource func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, pattern testpatterns.TestPattern) *genericVolumeTestResource {
func (r *genericVolumeTestResource) setupResource(driver TestDriver, pattern testpatterns.TestPattern) { r := genericVolumeTestResource{
r.driver = driver driver: driver,
config: config,
pattern: pattern,
}
dInfo := driver.GetDriverInfo() dInfo := driver.GetDriverInfo()
f := dInfo.Config.Framework f := config.Framework
cs := f.ClientSet cs := f.ClientSet
fsType := pattern.FsType fsType := pattern.FsType
volType := pattern.VolType volType := pattern.VolType
// Create volume for pre-provisioned volume tests // Create volume for pre-provisioned volume tests
r.volume = CreateVolume(driver, volType) r.volume = CreateVolume(driver, config, volType)
switch volType { switch volType {
case testpatterns.InlineVolume: case testpatterns.InlineVolume:
...@@ -184,7 +195,7 @@ func (r *genericVolumeTestResource) setupResource(driver TestDriver, pattern tes ...@@ -184,7 +195,7 @@ func (r *genericVolumeTestResource) setupResource(driver TestDriver, pattern tes
framework.Logf("Creating resource for dynamic PV") framework.Logf("Creating resource for dynamic PV")
if dDriver, ok := driver.(DynamicPVTestDriver); ok { if dDriver, ok := driver.(DynamicPVTestDriver); ok {
claimSize := dDriver.GetClaimSize() claimSize := dDriver.GetClaimSize()
r.sc = dDriver.GetDynamicProvisionStorageClass(fsType) r.sc = dDriver.GetDynamicProvisionStorageClass(r.config, fsType)
By("creating a StorageClass " + r.sc.Name) By("creating a StorageClass " + r.sc.Name)
var err error var err error
...@@ -204,13 +215,14 @@ func (r *genericVolumeTestResource) setupResource(driver TestDriver, pattern tes ...@@ -204,13 +215,14 @@ func (r *genericVolumeTestResource) setupResource(driver TestDriver, pattern tes
if r.volSource == nil { if r.volSource == nil {
framework.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, volType) framework.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, volType)
} }
return &r
} }
// cleanupResource cleans up genericVolumeTestResource // cleanupResource cleans up genericVolumeTestResource
func (r *genericVolumeTestResource) cleanupResource(driver TestDriver, pattern testpatterns.TestPattern) { func (r *genericVolumeTestResource) cleanupResource() {
dInfo := driver.GetDriverInfo() f := r.config.Framework
f := dInfo.Config.Framework volType := r.pattern.VolType
volType := pattern.VolType
if r.pvc != nil || r.pv != nil { if r.pvc != nil || r.pv != nil {
switch volType { switch volType {
...@@ -356,7 +368,7 @@ func deleteStorageClass(cs clientset.Interface, className string) { ...@@ -356,7 +368,7 @@ func deleteStorageClass(cs clientset.Interface, className string) {
// the testsuites package whereas framework.VolumeTestConfig is merely // the testsuites package whereas framework.VolumeTestConfig is merely
// an implementation detail. It contains fields that have no effect, // an implementation detail. It contains fields that have no effect,
// which makes it unsuitable for use in the testsuits public API. // which makes it unsuitable for use in the testsuits public API.
func convertTestConfig(in *TestConfig) framework.VolumeTestConfig { func convertTestConfig(in *PerTestConfig) framework.VolumeTestConfig {
if in.ServerConfig != nil { if in.ServerConfig != nil {
return *in.ServerConfig return *in.ServerConfig
} }
...@@ -390,3 +402,42 @@ func getSnapshot(claimName string, ns, snapshotClassName string) *unstructured.U ...@@ -390,3 +402,42 @@ func getSnapshot(claimName string, ns, snapshotClassName string) *unstructured.U
return snapshot return snapshot
} }
// StartPodLogs begins capturing log output and events from current
// and future pods running in the namespace of the framework. That
// ends when the returned cleanup function is called.
//
// The output goes to log files (when using --report-dir, as in the
// CI) or the output stream (otherwise).
func StartPodLogs(f *framework.Framework) func() {
ctx, cancel := context.WithCancel(context.Background())
cs := f.ClientSet
ns := f.Namespace
to := podlogs.LogOutput{
StatusWriter: GinkgoWriter,
}
if framework.TestContext.ReportDir == "" {
to.LogWriter = GinkgoWriter
} else {
test := CurrentGinkgoTestDescription()
reg := regexp.MustCompile("[^a-zA-Z0-9_-]+")
// We end the prefix with a slash to ensure that all logs
// end up in a directory named after the current test.
//
// TODO: use a deeper directory hierarchy once gubernator
// supports that (https://github.com/kubernetes/test-infra/issues/10289).
to.LogPathPrefix = framework.TestContext.ReportDir + "/" +
reg.ReplaceAllString(test.FullTestText, "_") + "/"
}
podlogs.CopyAllLogs(ctx, cs, ns.Name, to)
// pod events are something that the framework already collects itself
// after a failed test. Logging them live is only useful for interactive
// debugging, not when we collect reports.
if framework.TestContext.ReportDir == "" {
podlogs.WatchPods(ctx, cs, ns.Name, GinkgoWriter)
}
return cancel
}
...@@ -37,13 +37,13 @@ func GetDriverNameWithFeatureTags(driver TestDriver) string { ...@@ -37,13 +37,13 @@ func GetDriverNameWithFeatureTags(driver TestDriver) string {
} }
// CreateVolume creates volume for test unless dynamicPV test // CreateVolume creates volume for test unless dynamicPV test
func CreateVolume(driver TestDriver, volType testpatterns.TestVolType) TestVolume { func CreateVolume(driver TestDriver, config *PerTestConfig, volType testpatterns.TestVolType) TestVolume {
switch volType { switch volType {
case testpatterns.InlineVolume: case testpatterns.InlineVolume:
fallthrough fallthrough
case testpatterns.PreprovisionedPV: case testpatterns.PreprovisionedPV:
if pDriver, ok := driver.(PreprovisionedVolumeTestDriver); ok { if pDriver, ok := driver.(PreprovisionedVolumeTestDriver); ok {
return pDriver.CreateVolume(volType) return pDriver.CreateVolume(config, volType)
} }
case testpatterns.DynamicPV: case testpatterns.DynamicPV:
// No need to create volume // No need to create volume
...@@ -103,8 +103,3 @@ func GetSnapshotClass( ...@@ -103,8 +103,3 @@ func GetSnapshotClass(
return snapshotClass return snapshotClass
} }
// GetUniqueDriverName returns unique driver name that can be used parallelly in tests
func GetUniqueDriverName(driver TestDriver) string {
return fmt.Sprintf("%s-%s", driver.GetDriverInfo().Name, driver.GetDriverInfo().Config.Framework.UniqueName)
}
...@@ -25,17 +25,29 @@ import ( ...@@ -25,17 +25,29 @@ import (
"k8s.io/kubernetes/test/e2e/storage/testpatterns" "k8s.io/kubernetes/test/e2e/storage/testpatterns"
) )
// TestDriver represents an interface for a driver to be tested in TestSuite // TestDriver represents an interface for a driver to be tested in TestSuite.
// Except for GetDriverInfo, all methods will be called at test runtime and thus
// can use framework.Skipf, framework.Fatal, Gomega assertions, etc.
type TestDriver interface { type TestDriver interface {
// GetDriverInfo returns DriverInfo for the TestDriver // GetDriverInfo returns DriverInfo for the TestDriver. This must be static
// information.
GetDriverInfo() *DriverInfo GetDriverInfo() *DriverInfo
// CreateDriver creates all driver resources that is required for TestDriver method
// except CreateVolume // SkipUnsupportedTest skips test if Testpattern is not
CreateDriver() // suitable to test with the TestDriver. It gets called after
// CreateDriver cleanup all the resources that is created in CreateDriver // parsing parameters of the test suite and before the
CleanupDriver() // framework is initialized. Cheap tests that just check
// SkipUnsupportedTest skips test in Testpattern is not suitable to test with the TestDriver // parameters like the cloud provider can and should be
// done in SkipUnsupportedTest to avoid setting up more
// expensive resources like framework.Framework. Tests that
// depend on a connection to the cluster can be done in
// PrepareTest once the framework is ready.
SkipUnsupportedTest(testpatterns.TestPattern) SkipUnsupportedTest(testpatterns.TestPattern)
// PrepareTest is called at test execution time each time a new test case is about to start.
// It sets up all necessary resources and returns the per-test configuration
// plus a cleanup function that frees all allocated resources.
PrepareTest(f *framework.Framework) (*PerTestConfig, func())
} }
// TestVolume is the result of PreprovisionedVolumeTestDriver.CreateVolume. // TestVolume is the result of PreprovisionedVolumeTestDriver.CreateVolume.
...@@ -49,7 +61,7 @@ type TestVolume interface { ...@@ -49,7 +61,7 @@ type TestVolume interface {
type PreprovisionedVolumeTestDriver interface { type PreprovisionedVolumeTestDriver interface {
TestDriver TestDriver
// CreateVolume creates a pre-provisioned volume of the desired volume type. // CreateVolume creates a pre-provisioned volume of the desired volume type.
CreateVolume(volumeType testpatterns.TestVolType) TestVolume CreateVolume(config *PerTestConfig, volumeType testpatterns.TestVolType) TestVolume
} }
// InlineVolumeTestDriver represents an interface for a TestDriver that supports InlineVolume // InlineVolumeTestDriver represents an interface for a TestDriver that supports InlineVolume
...@@ -68,7 +80,6 @@ type PreprovisionedPVTestDriver interface { ...@@ -68,7 +80,6 @@ type PreprovisionedPVTestDriver interface {
// GetPersistentVolumeSource returns a PersistentVolumeSource with volume node affinity for pre-provisioned Persistent Volume. // GetPersistentVolumeSource returns a PersistentVolumeSource with volume node affinity for pre-provisioned Persistent Volume.
// It will set readOnly and fsType to the PersistentVolumeSource, if TestDriver supports both of them. // It will set readOnly and fsType to the PersistentVolumeSource, if TestDriver supports both of them.
// It will return nil, if the TestDriver doesn't support either of the parameters. // It will return nil, if the TestDriver doesn't support either of the parameters.
// Volume node affinity is optional, it will be nil for volumes which does not have volume node affinity.
GetPersistentVolumeSource(readOnly bool, fsType string, testVolume TestVolume) (*v1.PersistentVolumeSource, *v1.VolumeNodeAffinity) GetPersistentVolumeSource(readOnly bool, fsType string, testVolume TestVolume) (*v1.PersistentVolumeSource, *v1.VolumeNodeAffinity)
} }
...@@ -78,7 +89,7 @@ type DynamicPVTestDriver interface { ...@@ -78,7 +89,7 @@ type DynamicPVTestDriver interface {
// GetDynamicProvisionStorageClass returns a StorageClass dynamic provision Persistent Volume. // GetDynamicProvisionStorageClass returns a StorageClass dynamic provision Persistent Volume.
// It will set fsType to the StorageClass, if TestDriver supports it. // It will set fsType to the StorageClass, if TestDriver supports it.
// It will return nil, if the TestDriver doesn't support it. // It will return nil, if the TestDriver doesn't support it.
GetDynamicProvisionStorageClass(fsType string) *storagev1.StorageClass GetDynamicProvisionStorageClass(config *PerTestConfig, fsType string) *storagev1.StorageClass
// GetClaimSize returns the size of the volume that is to be provisioned ("5Gi", "1Mi"). // GetClaimSize returns the size of the volume that is to be provisioned ("5Gi", "1Mi").
// The size must be chosen so that the resulting volume is large enough for all // The size must be chosen so that the resulting volume is large enough for all
...@@ -91,7 +102,7 @@ type SnapshottableTestDriver interface { ...@@ -91,7 +102,7 @@ type SnapshottableTestDriver interface {
TestDriver TestDriver
// GetSnapshotClass returns a SnapshotClass to create snapshot. // GetSnapshotClass returns a SnapshotClass to create snapshot.
// It will return nil, if the TestDriver doesn't support it. // It will return nil, if the TestDriver doesn't support it.
GetSnapshotClass() *unstructured.Unstructured GetSnapshotClass(config *PerTestConfig) *unstructured.Unstructured
} }
// Capability represents a feature that a volume plugin supports // Capability represents a feature that a volume plugin supports
...@@ -112,7 +123,7 @@ const ( ...@@ -112,7 +123,7 @@ const (
CapMultiPODs Capability = "multipods" CapMultiPODs Capability = "multipods"
) )
// DriverInfo represents a combination of parameters to be used in implementation of TestDriver // DriverInfo represents static information about a TestDriver.
type DriverInfo struct { type DriverInfo struct {
Name string // Name of the driver Name string // Name of the driver
FeatureTag string // FeatureTag for the driver FeatureTag string // FeatureTag for the driver
...@@ -122,14 +133,15 @@ type DriverInfo struct { ...@@ -122,14 +133,15 @@ type DriverInfo struct {
SupportedMountOption sets.String // Map of string for supported mount option SupportedMountOption sets.String // Map of string for supported mount option
RequiredMountOption sets.String // Map of string for required mount option (Optional) RequiredMountOption sets.String // Map of string for required mount option (Optional)
Capabilities map[Capability]bool // Map that represents plugin capabilities Capabilities map[Capability]bool // Map that represents plugin capabilities
Config TestConfig // Test configuration for the current test.
} }
// TestConfig represents parameters that control test execution. // PerTestConfig represents parameters that control test execution.
// They can still be modified after defining tests, for example // One instance gets allocated for each test and is then passed
// in a BeforeEach or when creating the driver. // via pointer to functions involved in the test.
type TestConfig struct { type PerTestConfig struct {
// The test driver for the test.
Driver TestDriver
// Some short word that gets inserted into dynamically // Some short word that gets inserted into dynamically
// generated entities (pods, paths) as first part of the name // generated entities (pods, paths) as first part of the name
// to make debugging easier. Can be the same for different // to make debugging easier. Can be the same for different
...@@ -154,8 +166,9 @@ type TestConfig struct { ...@@ -154,8 +166,9 @@ type TestConfig struct {
// the configuration that then has to be used to run tests. // the configuration that then has to be used to run tests.
// The values above are ignored for such tests. // The values above are ignored for such tests.
ServerConfig *framework.VolumeTestConfig ServerConfig *framework.VolumeTestConfig
}
// TopologyEnabled indicates that the Topology feature gate // GetUniqueDriverName returns unique driver name that can be used parallelly in tests
// should be enabled in external-provisioner func (config *PerTestConfig) GetUniqueDriverName() string {
TopologyEnabled bool return config.Driver.GetDriverInfo().Name + "-" + config.Framework.UniqueName
} }
...@@ -74,87 +74,59 @@ func (t *volumeIOTestSuite) getTestSuiteInfo() TestSuiteInfo { ...@@ -74,87 +74,59 @@ func (t *volumeIOTestSuite) getTestSuiteInfo() TestSuiteInfo {
return t.tsInfo return t.tsInfo
} }
func (t *volumeIOTestSuite) skipUnsupportedTest(pattern testpatterns.TestPattern, driver TestDriver) { func (t *volumeIOTestSuite) defineTests(driver TestDriver, pattern testpatterns.TestPattern) {
} var (
dInfo = driver.GetDriverInfo()
func createVolumeIOTestInput(pattern testpatterns.TestPattern, resource genericVolumeTestResource) volumeIOTestInput { config *PerTestConfig
var fsGroup *int64 testCleanup func()
driver := resource.driver resource *genericVolumeTestResource
dInfo := driver.GetDriverInfo() )
f := dInfo.Config.Framework
fileSizes := createFileSizes(dInfo.MaxFileSize) // No preconditions to test. Normally they would be in a BeforeEach here.
volSource := resource.volSource
// This intentionally comes after checking the preconditions because it
if volSource == nil { // registers its own BeforeEach which creates the namespace. Beware that it
framework.Skipf("Driver %q does not define volumeSource - skipping", dInfo.Name) // also registers an AfterEach which renders f unusable. Any code using
// f must run inside an It or Context callback.
f := framework.NewDefaultFramework("volumeio")
init := func() {
// Now do the more expensive test initialization.
config, testCleanup = driver.PrepareTest(f)
resource = createGenericVolumeTestResource(driver, config, pattern)
if resource.volSource == nil {
framework.Skipf("Driver %q does not define volumeSource - skipping", dInfo.Name)
}
} }
if dInfo.Capabilities[CapFsGroup] { cleanup := func() {
fsGroupVal := int64(1234) if resource != nil {
fsGroup = &fsGroupVal resource.cleanupResource()
} resource = nil
}
return volumeIOTestInput{ if testCleanup != nil {
f: f, testCleanup()
name: dInfo.Name, testCleanup = nil
config: &dInfo.Config, }
volSource: *volSource,
testFile: fmt.Sprintf("%s_io_test_%s", dInfo.Name, f.Namespace.Name),
podSec: v1.PodSecurityContext{
FSGroup: fsGroup,
},
fileSizes: fileSizes,
} }
}
func (t *volumeIOTestSuite) execTest(driver TestDriver, pattern testpatterns.TestPattern) {
Context(getTestNameStr(t, pattern), func() {
var (
resource genericVolumeTestResource
input volumeIOTestInput
needsCleanup bool
)
BeforeEach(func() {
needsCleanup = false
// Skip unsupported tests to avoid unnecessary resource initialization
skipUnsupportedTest(t, driver, pattern)
needsCleanup = true
// Setup test resource for driver and testpattern
resource = genericVolumeTestResource{}
resource.setupResource(driver, pattern)
// Create test input
input = createVolumeIOTestInput(pattern, resource)
})
AfterEach(func() {
if needsCleanup {
resource.cleanupResource(driver, pattern)
}
})
execTestVolumeIO(&input)
})
}
type volumeIOTestInput struct {
f *framework.Framework
name string
config *TestConfig
volSource v1.VolumeSource
testFile string
podSec v1.PodSecurityContext
fileSizes []int64
}
func execTestVolumeIO(input *volumeIOTestInput) {
It("should write files of various sizes, verify size, validate content [Slow]", func() { It("should write files of various sizes, verify size, validate content [Slow]", func() {
f := input.f init()
cs := f.ClientSet defer cleanup()
err := testVolumeIO(f, cs, convertTestConfig(input.config), input.volSource, &input.podSec, input.testFile, input.fileSizes) cs := f.ClientSet
fileSizes := createFileSizes(dInfo.MaxFileSize)
testFile := fmt.Sprintf("%s_io_test_%s", dInfo.Name, f.Namespace.Name)
var fsGroup *int64
if dInfo.Capabilities[CapFsGroup] {
fsGroupVal := int64(1234)
fsGroup = &fsGroupVal
}
podSec := v1.PodSecurityContext{
FSGroup: fsGroup,
}
err := testVolumeIO(f, cs, convertTestConfig(config), *resource.volSource, &podSec, testFile, fileSizes)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
} }
......
...@@ -89,101 +89,76 @@ func skipExecTest(driver TestDriver) { ...@@ -89,101 +89,76 @@ func skipExecTest(driver TestDriver) {
} }
} }
func createVolumesTestInput(pattern testpatterns.TestPattern, resource genericVolumeTestResource) volumesTestInput { func (t *volumesTestSuite) defineTests(driver TestDriver, pattern testpatterns.TestPattern) {
var fsGroup *int64 var (
driver := resource.driver dInfo = driver.GetDriverInfo()
dInfo := driver.GetDriverInfo() config *PerTestConfig
f := dInfo.Config.Framework testCleanup func()
volSource := resource.volSource resource *genericVolumeTestResource
)
if volSource == nil { // No preconditions to test. Normally they would be in a BeforeEach here.
framework.Skipf("Driver %q does not define volumeSource - skipping", dInfo.Name)
// This intentionally comes after checking the preconditions because it
// registers its own BeforeEach which creates the namespace. Beware that it
// also registers an AfterEach which renders f unusable. Any code using
// f must run inside an It or Context callback.
f := framework.NewDefaultFramework("volumeio")
init := func() {
// Now do the more expensive test initialization.
config, testCleanup = driver.PrepareTest(f)
resource = createGenericVolumeTestResource(driver, config, pattern)
if resource.volSource == nil {
framework.Skipf("Driver %q does not define volumeSource - skipping", dInfo.Name)
}
} }
if dInfo.Capabilities[CapFsGroup] { cleanup := func() {
fsGroupVal := int64(1234) if resource != nil {
fsGroup = &fsGroupVal resource.cleanupResource()
resource = nil
}
if testCleanup != nil {
testCleanup()
testCleanup = nil
}
} }
return volumesTestInput{ It("should be mountable", func() {
f: f, skipPersistenceTest(driver)
name: dInfo.Name, init()
config: &dInfo.Config, defer func() {
fsGroup: fsGroup, framework.VolumeTestCleanup(f, convertTestConfig(config))
resource: resource, cleanup()
fsType: pattern.FsType, }()
tests: []framework.VolumeTest{
tests := []framework.VolumeTest{
{ {
Volume: *volSource, Volume: *resource.volSource,
File: "index.html", File: "index.html",
// Must match content // Must match content
ExpectedContent: fmt.Sprintf("Hello from %s from namespace %s", ExpectedContent: fmt.Sprintf("Hello from %s from namespace %s",
dInfo.Name, f.Namespace.Name), dInfo.Name, f.Namespace.Name),
}, },
}, }
} config := convertTestConfig(config)
} framework.InjectHtml(f.ClientSet, config, tests[0].Volume, tests[0].ExpectedContent)
var fsGroup *int64
func (t *volumesTestSuite) execTest(driver TestDriver, pattern testpatterns.TestPattern) { if dInfo.Capabilities[CapFsGroup] {
Context(getTestNameStr(t, pattern), func() { fsGroupVal := int64(1234)
var ( fsGroup = &fsGroupVal
resource genericVolumeTestResource }
input volumesTestInput framework.TestVolumeClient(f.ClientSet, config, fsGroup, pattern.FsType, tests)
needsCleanup bool
)
BeforeEach(func() {
needsCleanup = false
// Skip unsupported tests to avoid unnecessary resource initialization
skipUnsupportedTest(t, driver, pattern)
needsCleanup = true
// Setup test resource for driver and testpattern
resource = genericVolumeTestResource{}
resource.setupResource(driver, pattern)
// Create test input
input = createVolumesTestInput(pattern, resource)
})
AfterEach(func() {
if needsCleanup {
resource.cleanupResource(driver, pattern)
}
})
testVolumes(&input)
}) })
}
type volumesTestInput struct {
f *framework.Framework
name string
config *TestConfig
fsGroup *int64
fsType string
tests []framework.VolumeTest
resource genericVolumeTestResource
}
func testVolumes(input *volumesTestInput) {
It("should be mountable", func() {
f := input.f
cs := f.ClientSet
defer framework.VolumeTestCleanup(f, convertTestConfig(input.config))
skipPersistenceTest(input.resource.driver)
volumeTest := input.tests
config := convertTestConfig(input.config)
framework.InjectHtml(cs, config, volumeTest[0].Volume, volumeTest[0].ExpectedContent)
framework.TestVolumeClient(cs, config, input.fsGroup, input.fsType, input.tests)
})
It("should allow exec of files on the volume", func() { It("should allow exec of files on the volume", func() {
f := input.f skipExecTest(driver)
skipExecTest(input.resource.driver) init()
defer cleanup()
testScriptInPod(f, input.resource.volType, input.resource.volSource, input.resource.driver.GetDriverInfo().Config.ClientNodeSelector) testScriptInPod(f, resource.volType, resource.volSource, config.ClientNodeSelector)
}) })
} }
......
...@@ -212,21 +212,22 @@ func testZonalDelayedBinding(c clientset.Interface, ns string, specifyAllowedTop ...@@ -212,21 +212,22 @@ func testZonalDelayedBinding(c clientset.Interface, ns string, specifyAllowedTop
action := "creating claims with class with waitForFirstConsumer" action := "creating claims with class with waitForFirstConsumer"
suffix := "delayed" suffix := "delayed"
var topoZone string var topoZone string
class := newStorageClass(test, ns, suffix) test.Client = c
test.Class = newStorageClass(test, ns, suffix)
if specifyAllowedTopology { if specifyAllowedTopology {
action += " and allowedTopologies" action += " and allowedTopologies"
suffix += "-topo" suffix += "-topo"
topoZone = getRandomClusterZone(c) topoZone = getRandomClusterZone(c)
addSingleZoneAllowedTopologyToStorageClass(c, class, topoZone) addSingleZoneAllowedTopologyToStorageClass(c, test.Class, topoZone)
} }
By(action) By(action)
var claims []*v1.PersistentVolumeClaim var claims []*v1.PersistentVolumeClaim
for i := 0; i < pvcCount; i++ { for i := 0; i < pvcCount; i++ {
claim := newClaim(test, ns, suffix) claim := newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name claim.Spec.StorageClassName = &test.Class.Name
claims = append(claims, claim) claims = append(claims, claim)
} }
pvs, node := testsuites.TestBindingWaitForFirstConsumerMultiPVC(test, c, claims, class, nil /* node selector */, false /* expect unschedulable */) pvs, node := test.TestBindingWaitForFirstConsumerMultiPVC(claims, nil /* node selector */, false /* expect unschedulable */)
if node == nil { if node == nil {
framework.Failf("unexpected nil node found") framework.Failf("unexpected nil node found")
} }
...@@ -440,10 +441,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -440,10 +441,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
By("Testing " + test.Name) By("Testing " + test.Name)
suffix := fmt.Sprintf("%d", i) suffix := fmt.Sprintf("%d", i)
class := newStorageClass(test, ns, suffix) test.Client = c
claim := newClaim(test, ns, suffix) test.Class = newStorageClass(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name test.Claim = newClaim(test, ns, suffix)
testsuites.TestDynamicProvisioning(test, c, claim, class) test.Claim.Spec.StorageClassName = &test.Class.Name
test.TestDynamicProvisioning()
} }
// Run the last test with storage.k8s.io/v1beta1 on pvc // Run the last test with storage.k8s.io/v1beta1 on pvc
...@@ -455,9 +457,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -455,9 +457,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
defer deleteStorageClass(c, class.Name) defer deleteStorageClass(c, class.Name)
claim := newClaim(*betaTest, ns, "beta") betaTest.Client = c
claim.Spec.StorageClassName = &(class.Name) betaTest.Class = nil
testsuites.TestDynamicProvisioning(*betaTest, c, claim, nil) betaTest.Claim = newClaim(*betaTest, ns, "beta")
betaTest.Claim.Spec.StorageClassName = &(class.Name)
(*betaTest).TestDynamicProvisioning()
} }
}) })
...@@ -465,6 +469,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -465,6 +469,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
framework.SkipUnlessProviderIs("gce", "gke") framework.SkipUnlessProviderIs("gce", "gke")
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "HDD PD on GCE/GKE", Name: "HDD PD on GCE/GKE",
CloudProviders: []string{"gce", "gke"}, CloudProviders: []string{"gce", "gke"},
Provisioner: "kubernetes.io/gce-pd", Provisioner: "kubernetes.io/gce-pd",
...@@ -479,12 +484,12 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -479,12 +484,12 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
testsuites.PVWriteReadSingleNodeCheck(c, claim, volume, testsuites.NodeSelection{}) testsuites.PVWriteReadSingleNodeCheck(c, claim, volume, testsuites.NodeSelection{})
}, },
} }
class := newStorageClass(test, ns, "reclaimpolicy") test.Class = newStorageClass(test, ns, "reclaimpolicy")
retain := v1.PersistentVolumeReclaimRetain retain := v1.PersistentVolumeReclaimRetain
class.ReclaimPolicy = &retain test.Class.ReclaimPolicy = &retain
claim := newClaim(test, ns, "reclaimpolicy") test.Claim = newClaim(test, ns, "reclaimpolicy")
claim.Spec.StorageClassName = &class.Name test.Claim.Spec.StorageClassName = &test.Class.Name
pv := testsuites.TestDynamicProvisioning(test, c, claim, class) pv := test.TestDynamicProvisioning()
By(fmt.Sprintf("waiting for the provisioned PV %q to enter phase %s", pv.Name, v1.VolumeReleased)) By(fmt.Sprintf("waiting for the provisioned PV %q to enter phase %s", pv.Name, v1.VolumeReleased))
framework.ExpectNoError(framework.WaitForPersistentVolumePhase(v1.VolumeReleased, c, pv.Name, 1*time.Second, 30*time.Second)) framework.ExpectNoError(framework.WaitForPersistentVolumePhase(v1.VolumeReleased, c, pv.Name, 1*time.Second, 30*time.Second))
...@@ -718,17 +723,18 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -718,17 +723,18 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
By("creating a StorageClass") By("creating a StorageClass")
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "external provisioner test", Name: "external provisioner test",
Provisioner: externalPluginName, Provisioner: externalPluginName,
ClaimSize: "1500Mi", ClaimSize: "1500Mi",
ExpectedSize: "1500Mi", ExpectedSize: "1500Mi",
} }
class := newStorageClass(test, ns, "external") test.Class = newStorageClass(test, ns, "external")
claim := newClaim(test, ns, "external") test.Claim = newClaim(test, ns, "external")
claim.Spec.StorageClassName = &(class.Name) test.Claim.Spec.StorageClassName = &test.Class.Name
By("creating a claim with a external provisioning annotation") By("creating a claim with a external provisioning annotation")
testsuites.TestDynamicProvisioning(test, c, claim, class) test.TestDynamicProvisioning()
}) })
}) })
...@@ -738,13 +744,14 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -738,13 +744,14 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
By("creating a claim with no annotation") By("creating a claim with no annotation")
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "default", Name: "default",
ClaimSize: "2Gi", ClaimSize: "2Gi",
ExpectedSize: "2Gi", ExpectedSize: "2Gi",
} }
claim := newClaim(test, ns, "default") test.Claim = newClaim(test, ns, "default")
testsuites.TestDynamicProvisioning(test, c, claim, nil) test.TestDynamicProvisioning()
}) })
// Modifying the default storage class can be disruptive to other tests that depend on it // Modifying the default storage class can be disruptive to other tests that depend on it
...@@ -817,6 +824,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -817,6 +824,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
serverUrl := "http://" + pod.Status.PodIP + ":8081" serverUrl := "http://" + pod.Status.PodIP + ":8081"
By("creating a StorageClass") By("creating a StorageClass")
test := testsuites.StorageClassTest{ test := testsuites.StorageClassTest{
Client: c,
Name: "Gluster Dynamic provisioner test", Name: "Gluster Dynamic provisioner test",
Provisioner: "kubernetes.io/glusterfs", Provisioner: "kubernetes.io/glusterfs",
ClaimSize: "2Gi", ClaimSize: "2Gi",
...@@ -824,13 +832,13 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -824,13 +832,13 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
Parameters: map[string]string{"resturl": serverUrl}, Parameters: map[string]string{"resturl": serverUrl},
} }
suffix := fmt.Sprintf("glusterdptest") suffix := fmt.Sprintf("glusterdptest")
class := newStorageClass(test, ns, suffix) test.Class = newStorageClass(test, ns, suffix)
By("creating a claim object with a suffix for gluster dynamic provisioner") By("creating a claim object with a suffix for gluster dynamic provisioner")
claim := newClaim(test, ns, suffix) test.Claim = newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name test.Claim.Spec.StorageClassName = &test.Class.Name
testsuites.TestDynamicProvisioning(test, c, claim, class) test.TestDynamicProvisioning()
}) })
}) })
...@@ -929,12 +937,13 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ...@@ -929,12 +937,13 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
} }
By("creating a claim with class with allowedTopologies set") By("creating a claim with class with allowedTopologies set")
suffix := "topology" suffix := "topology"
class := newStorageClass(test, ns, suffix) test.Client = c
test.Class = newStorageClass(test, ns, suffix)
zone := getRandomClusterZone(c) zone := getRandomClusterZone(c)
addSingleZoneAllowedTopologyToStorageClass(c, class, zone) addSingleZoneAllowedTopologyToStorageClass(c, test.Class, zone)
claim := newClaim(test, ns, suffix) test.Claim = newClaim(test, ns, suffix)
claim.Spec.StorageClassName = &class.Name test.Claim.Spec.StorageClassName = &test.Class.Name
pv := testsuites.TestDynamicProvisioning(test, c, claim, class) pv := test.TestDynamicProvisioning()
checkZoneFromLabelAndAffinity(pv, zone, true) checkZoneFromLabelAndAffinity(pv, zone, true)
} }
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment