diff --git a/cmd/csi-sanity/sanity_test.go b/cmd/csi-sanity/sanity_test.go index 30960b18..e4c35dc6 100644 --- a/cmd/csi-sanity/sanity_test.go +++ b/cmd/csi-sanity/sanity_test.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "testing" + "time" "github.com/kubernetes-csi/csi-test/v3/pkg/sanity" ) @@ -30,39 +31,63 @@ const ( var ( VERSION = "(dev)" - version bool - config sanity.Config + config = sanity.NewTestConfig() ) -func init() { - flag.StringVar(&config.Address, prefix+"endpoint", "", "CSI endpoint") - flag.StringVar(&config.ControllerAddress, prefix+"controllerendpoint", "", "CSI controller endpoint") - flag.BoolVar(&version, prefix+"version", false, "Version of this program") - flag.StringVar(&config.TargetPath, prefix+"mountdir", os.TempDir()+"/csi-mount", "Mount point for NodePublish") - flag.StringVar(&config.StagingPath, prefix+"stagingdir", os.TempDir()+"/csi-staging", "Mount point for NodeStage if staging is supported") - flag.StringVar(&config.CreateTargetPathCmd, prefix+"createmountpathcmd", "", "Command to run for target path creation") - flag.StringVar(&config.CreateStagingPathCmd, prefix+"createstagingpathcmd", "", "Command to run for staging path creation") - flag.IntVar(&config.CreatePathCmdTimeout, prefix+"createpathcmdtimeout", 10, "Timeout for the commands to create target and staging paths, in seconds") - flag.StringVar(&config.RemoveTargetPathCmd, prefix+"removemountpathcmd", "", "Command to run for target path removal") - flag.StringVar(&config.RemoveStagingPathCmd, prefix+"removestagingpathcmd", "", "Command to run for staging path removal") - flag.IntVar(&config.RemovePathCmdTimeout, prefix+"removepathcmdtimeout", 10, "Timeout for the commands to remove target and staging paths, in seconds") - flag.StringVar(&config.SecretsFile, prefix+"secrets", "", "CSI secrets file") - flag.Int64Var(&config.TestVolumeSize, prefix+"testvolumesize", sanity.DefTestVolumeSize, "Base volume size used for provisioned volumes") - flag.Int64Var(&config.TestVolumeExpandSize, prefix+"testvolumeexpandsize", 0, "Target size for expanded volumes") - flag.StringVar(&config.TestVolumeParametersFile, prefix+"testvolumeparameters", "", "YAML file of volume parameters for provisioned volumes") - flag.StringVar(&config.TestSnapshotParametersFile, prefix+"testsnapshotparameters", "", "YAML file of snapshot parameters for provisioned snapshots") - flag.BoolVar(&config.TestNodeVolumeAttachLimit, prefix+"testnodevolumeattachlimit", false, "Test node volume attach limit") - flag.StringVar(&config.JUnitFile, prefix+"junitfile", "", "JUnit XML output file where test results will be written") - flag.Parse() +func stringVar(p *string, name string, usage string) { + flag.StringVar(p, prefix+name, *p, usage) } -func TestSanity(t *testing.T) { - if version { +func boolVar(p *bool, name string, usage string) { + flag.BoolVar(p, prefix+name, *p, usage) +} + +func intVar(p *int, name string, usage string) { + flag.IntVar(p, prefix+name, *p, usage) +} + +func int64Var(p *int64, name string, usage string) { + flag.Int64Var(p, prefix+name, *p, usage) +} + +func durationVar(p *time.Duration, name string, usage string) { + flag.DurationVar(p, prefix+name, *p, usage) +} + +func TestMain(m *testing.M) { + version := flag.Bool("version", false, "print version of this program") + + // Support overriding the default configuration via flags. + stringVar(&config.Address, "endpoint", "CSI endpoint") + stringVar(&config.ControllerAddress, "controllerendpoint", "CSI controller endpoint") + stringVar(&config.TargetPath, "mountdir", "Mount point for NodePublish") + stringVar(&config.StagingPath, "stagingdir", "Mount point for NodeStage if staging is supported") + stringVar(&config.CreateTargetPathCmd, "createmountpathcmd", "Command to run for target path creation") + stringVar(&config.CreateStagingPathCmd, "createstagingpathcmd", "Command to run for staging path creation") + durationVar(&config.CreatePathCmdTimeout, "createpathcmdtimeout", "Timeout for the commands to create target and staging paths, in seconds") + stringVar(&config.RemoveTargetPathCmd, "removemountpathcmd", "Command to run for target path removal") + stringVar(&config.RemoveStagingPathCmd, "removestagingpathcmd", "Command to run for staging path removal") + durationVar(&config.RemovePathCmdTimeout, "removepathcmdtimeout", "Timeout for the commands to remove target and staging paths, in seconds") + stringVar(&config.SecretsFile, "secrets", "CSI secrets file") + int64Var(&config.TestVolumeSize, "testvolumesize", "Base volume size used for provisioned volumes") + int64Var(&config.TestVolumeExpandSize, "testvolumeexpandsize", "Target size for expanded volumes") + stringVar(&config.TestVolumeParametersFile, "testvolumeparameters", "YAML file of volume parameters for provisioned volumes") + stringVar(&config.TestSnapshotParametersFile, "testsnapshotparameters", "YAML file of snapshot parameters for provisioned snapshots") + boolVar(&config.TestNodeVolumeAttachLimit, "testnodevolumeattachlimit", "Test node volume attach limit") + stringVar(&config.JUnitFile, "junitfile", "JUnit XML output file where test results will be written") + + flag.Parse() + if *version { fmt.Printf("Version = %s\n", VERSION) - return + os.Exit(0) } - if len(config.Address) == 0 { - t.Fatalf("--%sendpoint must be provided with an CSI endpoint", prefix) + if config.Address == "" { + fmt.Printf("--%sendpoint must be provided with an CSI endpoint\n", prefix) + os.Exit(1) } - sanity.Test(t, &config) + os.Exit(m.Run()) +} + +func TestSanity(t *testing.T) { + sanity.Test(t, config) } diff --git a/hack/_apitest/api_test.go b/hack/_apitest/api_test.go index 6971a374..131c27e3 100644 --- a/hack/_apitest/api_test.go +++ b/hack/_apitest/api_test.go @@ -1,19 +1,15 @@ package apitest import ( - "os" "testing" "github.com/kubernetes-csi/csi-test/pkg/sanity" ) func TestMyDriver(t *testing.T) { - config := &sanity.Config{ - TargetPath: os.TempDir() + "/csi-target", - StagingPath: os.TempDir() + "/csi-staging", - Address: "/tmp/e2e-csi-sanity.sock", - TestNodeVolumeAttachLimit: true, - } + config := sanity.NewTestConfig() + config.Address = "/tmp/e2e-csi-sanity.sock" + config.TestNodeVolumeAttachLimit = true sanity.Test(t, config) } diff --git a/hack/_apitest2/api_test.go b/hack/_apitest2/api_test.go index 28da8560..a67c57e6 100644 --- a/hack/_apitest2/api_test.go +++ b/hack/_apitest2/api_test.go @@ -24,28 +24,27 @@ func TestMyDriverWithCustomTargetPaths(t *testing.T) { // are created. For k8s, it could be /var/lib/kubelet/pods under which the // mount directories could be created. tmpPath := path.Join(os.TempDir(), "csi") - config := &sanity.Config{ - TargetPath: "foo/target/mount", - StagingPath: "foo/staging/mount", - Address: "/tmp/e2e-csi-sanity.sock", - CreateTargetDir: func(targetPath string) (string, error) { - createTargetDirCalls++ - targetPath = path.Join(tmpPath, targetPath) - return targetPath, createTargetDir(targetPath) - }, - CreateStagingDir: func(targetPath string) (string, error) { - createStagingDirCalls++ - targetPath = path.Join(tmpPath, targetPath) - return targetPath, createTargetDir(targetPath) - }, - RemoveTargetPath: func(targetPath string) error { - removeTargetDirCalls++ - return os.RemoveAll(targetPath) - }, - RemoveStagingPath: func(targetPath string) error { - removeStagingDirCalls++ - return os.RemoveAll(targetPath) - }, + config := sanity.NewTestConfig() + config.TargetPath = "foo/target/mount" + config.StagingPath = "foo/staging/mount" + config.Address = "/tmp/e2e-csi-sanity.sock" + config.CreateTargetDir = func(targetPath string) (string, error) { + createTargetDirCalls++ + targetPath = path.Join(tmpPath, targetPath) + return targetPath, createTargetDir(targetPath) + } + config.CreateStagingDir = func(targetPath string) (string, error) { + createStagingDirCalls++ + targetPath = path.Join(tmpPath, targetPath) + return targetPath, createTargetDir(targetPath) + } + config.RemoveTargetPath = func(targetPath string) error { + removeTargetDirCalls++ + return os.RemoveAll(targetPath) + } + config.RemoveStagingPath = func(targetPath string) error { + removeStagingDirCalls++ + return os.RemoveAll(targetPath) } sanity.Test(t, config) diff --git a/hack/_embedded/embedded_test.go b/hack/_embedded/embedded_test.go index 26692bac..763aea72 100644 --- a/hack/_embedded/embedded_test.go +++ b/hack/_embedded/embedded_test.go @@ -1,7 +1,6 @@ package embedded import ( - "os" "testing" "github.com/kubernetes-csi/csi-test/pkg/sanity" @@ -9,6 +8,8 @@ import ( . "github.com/onsi/gomega" ) +var context *sanity.TestContext + func TestMyDriverGinkgo(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "CSI Sanity Test Suite") @@ -21,24 +22,24 @@ func TestMyDriverGinkgo(t *testing.T) { // in hack/e2e.sh if a PR adds back such functions in the sanity test // code. var _ = BeforeSuite(func() {}) -var _ = AfterSuite(func() {}) +var _ = AfterSuite(func() { + if context != nil { + context.Finalize() + } +}) var _ = Describe("MyCSIDriver", func() { Context("Config A", func() { - config := &sanity.Config{ - TargetPath: os.TempDir() + "/csi-target", - StagingPath: os.TempDir() + "/csi-staging", - Address: "/tmp/e2e-csi-sanity.sock", - TestNodeVolumeAttachLimit: true, - IDGen: &sanity.DefaultIDGenerator{}, - } + config := sanity.NewTestConfig() + config.Address = "/tmp/e2e-csi-sanity.sock" + config.TestNodeVolumeAttachLimit = true BeforeEach(func() {}) AfterEach(func() {}) Describe("CSI Driver Test Suite", func() { - sanity.GinkgoTest(config) + context = sanity.GinkgoTest(&config) }) }) }) diff --git a/pkg/sanity/cleanup.go b/pkg/sanity/cleanup.go index d1d717a4..0322233e 100644 --- a/pkg/sanity/cleanup.go +++ b/pkg/sanity/cleanup.go @@ -39,7 +39,7 @@ type VolumeInfo struct { // Cleanup keeps track of resources, in particular volumes, which need // to be freed when testing is done. All methods can be called concurrently. type Cleanup struct { - Context *SanityContext + Context *TestContext ControllerClient csi.ControllerClient NodeClient csi.NodeClient ControllerPublishSupported bool diff --git a/pkg/sanity/controller.go b/pkg/sanity/controller.go index 01d8603d..c404290c 100644 --- a/pkg/sanity/controller.go +++ b/pkg/sanity/controller.go @@ -31,11 +31,6 @@ import ( ) const ( - // DefTestVolumeSize defines the base size of dynamically - // provisioned volumes. 10GB by default, can be overridden by - // setting Config.TestVolumeSize. - DefTestVolumeSize int64 = 10 * 1024 * 1024 * 1024 - // DefTestVolumeExpand defines the size increment for volume // expansion. It can be overriden by setting an // Config.TestVolumeExpandSize, which will be taken as absolute @@ -45,14 +40,11 @@ const ( MaxNameLength int = 128 ) -func TestVolumeSize(sc *SanityContext) int64 { - if sc.Config.TestVolumeSize > 0 { - return sc.Config.TestVolumeSize - } - return DefTestVolumeSize +func TestVolumeSize(sc *TestContext) int64 { + return sc.Config.TestVolumeSize } -func TestVolumeExpandSize(sc *SanityContext) int64 { +func TestVolumeExpandSize(sc *TestContext) int64 { if sc.Config.TestVolumeExpandSize > 0 { return sc.Config.TestVolumeExpandSize } @@ -92,7 +84,7 @@ func isControllerCapabilitySupported( return false } -var _ = DescribeSanity("Controller Service [Controller Server]", func(sc *SanityContext) { +var _ = DescribeSanity("Controller Service [Controller Server]", func(sc *TestContext) { var ( c csi.ControllerClient n csi.NodeClient @@ -1617,7 +1609,7 @@ var _ = DescribeSanity("Controller Service [Controller Server]", func(sc *Sanity }) }) -var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityContext) { +var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *TestContext) { var ( c csi.ControllerClient ) @@ -1870,7 +1862,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte }) -var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityContext) { +var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *TestContext) { var ( c csi.ControllerClient ) @@ -1933,7 +1925,7 @@ var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityCont }) }) -var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityContext) { +var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *TestContext) { var ( c csi.ControllerClient ) @@ -2082,7 +2074,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont }) }) -var _ = DescribeSanity("ExpandVolume [Controller Server]", func(sc *SanityContext) { +var _ = DescribeSanity("ExpandVolume [Controller Server]", func(sc *TestContext) { var ( c csi.ControllerClient cl *Cleanup @@ -2188,7 +2180,7 @@ var _ = DescribeSanity("ExpandVolume [Controller Server]", func(sc *SanityContex }) }) -func MakeCreateVolumeReq(sc *SanityContext, name string) *csi.CreateVolumeRequest { +func MakeCreateVolumeReq(sc *TestContext, name string) *csi.CreateVolumeRequest { size1 := TestVolumeSize(sc) req := &csi.CreateVolumeRequest{ @@ -2217,7 +2209,7 @@ func MakeCreateVolumeReq(sc *SanityContext, name string) *csi.CreateVolumeReques return req } -func MakeCreateSnapshotReq(sc *SanityContext, name, sourceVolumeId string) *csi.CreateSnapshotRequest { +func MakeCreateSnapshotReq(sc *TestContext, name, sourceVolumeId string) *csi.CreateSnapshotRequest { req := &csi.CreateSnapshotRequest{ Name: name, SourceVolumeId: sourceVolumeId, @@ -2231,7 +2223,7 @@ func MakeCreateSnapshotReq(sc *SanityContext, name, sourceVolumeId string) *csi. return req } -func MakeDeleteSnapshotReq(sc *SanityContext, id string) *csi.DeleteSnapshotRequest { +func MakeDeleteSnapshotReq(sc *TestContext, id string) *csi.DeleteSnapshotRequest { delSnapReq := &csi.DeleteSnapshotRequest{ SnapshotId: id, } @@ -2243,7 +2235,7 @@ func MakeDeleteSnapshotReq(sc *SanityContext, id string) *csi.DeleteSnapshotRequ return delSnapReq } -func MakeDeleteVolumeReq(sc *SanityContext, id string) *csi.DeleteVolumeRequest { +func MakeDeleteVolumeReq(sc *TestContext, id string) *csi.DeleteVolumeRequest { delVolReq := &csi.DeleteVolumeRequest{ VolumeId: id, } @@ -2256,7 +2248,7 @@ func MakeDeleteVolumeReq(sc *SanityContext, id string) *csi.DeleteVolumeRequest } // MakeControllerPublishVolumeReq creates and returns a ControllerPublishVolumeRequest. -func MakeControllerPublishVolumeReq(sc *SanityContext, volID, nodeID string) *csi.ControllerPublishVolumeRequest { +func MakeControllerPublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerPublishVolumeRequest { return &csi.ControllerPublishVolumeRequest{ VolumeId: volID, NodeId: nodeID, @@ -2274,7 +2266,7 @@ func MakeControllerPublishVolumeReq(sc *SanityContext, volID, nodeID string) *cs } // MakeControllerUnpublishVolumeReq creates and returns a ControllerUnpublishVolumeRequest. -func MakeControllerUnpublishVolumeReq(sc *SanityContext, volID, nodeID string) *csi.ControllerUnpublishVolumeRequest { +func MakeControllerUnpublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerUnpublishVolumeRequest { return &csi.ControllerUnpublishVolumeRequest{ VolumeId: volID, NodeId: nodeID, @@ -2283,7 +2275,7 @@ func MakeControllerUnpublishVolumeReq(sc *SanityContext, volID, nodeID string) * } // CreateAndControllerPublishVolume creates and controller publishes a volume given a volume name and node ID. -func CreateAndControllerPublishVolume(sc *SanityContext, c csi.ControllerClient, volName, nodeID string) (volID string, err error) { +func CreateAndControllerPublishVolume(sc *TestContext, c csi.ControllerClient, volName, nodeID string) (volID string, err error) { vol, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, volName)) Expect(err).NotTo(HaveOccurred()) Expect(vol).NotTo(BeNil()) @@ -2298,7 +2290,7 @@ func CreateAndControllerPublishVolume(sc *SanityContext, c csi.ControllerClient, } // ControllerUnpublishAndDeleteVolume controller unpublishes and deletes a volume, given volume ID and node ID. -func ControllerUnpublishAndDeleteVolume(sc *SanityContext, c csi.ControllerClient, volID, nodeID string) error { +func ControllerUnpublishAndDeleteVolume(sc *TestContext, c csi.ControllerClient, volID, nodeID string) error { _, err := c.ControllerUnpublishVolume( context.Background(), MakeControllerUnpublishVolumeReq(sc, volID, nodeID), diff --git a/pkg/sanity/identity.go b/pkg/sanity/identity.go index d2161e7c..28b940ed 100644 --- a/pkg/sanity/identity.go +++ b/pkg/sanity/identity.go @@ -30,7 +30,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = DescribeSanity("Identity Service", func(sc *SanityContext) { +var _ = DescribeSanity("Identity Service", func(sc *TestContext) { var ( c csi.IdentityClient ) diff --git a/pkg/sanity/node.go b/pkg/sanity/node.go index 52f35d3c..5f36d862 100644 --- a/pkg/sanity/node.go +++ b/pkg/sanity/node.go @@ -66,7 +66,7 @@ func isPluginCapabilitySupported(c csi.IdentityClient, return false } -var _ = DescribeSanity("Node Service", func(sc *SanityContext) { +var _ = DescribeSanity("Node Service", func(sc *TestContext) { var ( cl *Cleanup c csi.NodeClient diff --git a/pkg/sanity/sanity.go b/pkg/sanity/sanity.go index 060e2891..86be7caa 100644 --- a/pkg/sanity/sanity.go +++ b/pkg/sanity/sanity.go @@ -51,9 +51,13 @@ type CSISecrets struct { ControllerExpandVolumeSecret map[string]string `yaml:"ControllerExpandVolumeSecret"` } -// Config provides the configuration for the sanity tests. It -// needs to be initialized by the user of the sanity package. -type Config struct { +// TestConfig provides the configuration for the sanity tests. It must be +// constructed with NewTestConfig to initialize it with sane defaults. The +// user of the sanity package can then override values before passing +// the instance to [Ginkgo]Test and/or (when using GinkgoTest) in a +// BeforeEach. For example, the BeforeEach could set up the CSI driver +// and then set the Address field differently for each test. +type TestConfig struct { // TargetPath is the *parent* directory for NodePublishVolumeRequest.target_path. // It gets created and removed by csi-sanity. TargetPath string @@ -62,9 +66,19 @@ type Config struct { // It gets created and removed by csi-sanity. StagingPath string - Address string + // Address is the gRPC endpoint (e.g. unix:/tmp/csi.sock or + // dns:///my-machine:9000) of the CSI driver. If ControllerAddress + // is empty, it must provide both the controller and node service. + Address string + + // ControllerAddress optionally provides the gRPC endpoint of + // the controller service. ControllerAddress string - SecretsFile string + + // SecretsFile is the filename of a .yaml file which is used + // to populate CSISecrets which are then used for calls to the + // CSI driver. + SecretsFile string TestVolumeSize int64 @@ -74,6 +88,9 @@ type Config struct { TestVolumeParameters map[string]string TestNodeVolumeAttachLimit bool + // JUnitFile is used by Test to store test results in JUnit + // format. When using GinkgoTest, the caller is responsible + // for configuring the Ginkgo runner. JUnitFile string // TestSnapshotParametersFile for setting CreateVolumeRequest.Parameters. @@ -117,26 +134,25 @@ type Config struct { CreateTargetPathCmd string CreateStagingPathCmd string // Timeout for the executed commands for path creation. - CreatePathCmdTimeout int + CreatePathCmdTimeout time.Duration // Commands to be executed for customized removal of the target and staging // paths. Thie command must be available on the host where sanity runs. RemoveTargetPathCmd string RemoveStagingPathCmd string // Timeout for the executed commands for path removal. - RemovePathCmdTimeout int + RemovePathCmdTimeout time.Duration - // IDGen is an optional interface for callers to provide a - // generator for valid Volume and Node IDs. If unset, - // it will be set to a DefaultIDGenerator instance when - // passing the config to Test or GinkgoTest. + // IDGen is an interface for callers to provide a + // generator for valid Volume and Node IDs. Defaults to + // DefaultIDGenerator. IDGen IDGenerator } -// SanityContext holds the variables that each test can depend on. It -// gets initialized before each test block runs. -type SanityContext struct { - Config *Config +// TestContext gets initialized by the sanity package before each test +// runs. It holds the variables that each test can depend on. +type TestContext struct { + Config *TestConfig Conn *grpc.ClientConn ControllerConn *grpc.ClientConn Secrets *CSISecrets @@ -149,55 +165,66 @@ type SanityContext struct { StagingPath string } +// NewTestConfig returns a config instance with all values set to +// their defaults. +func NewTestConfig() TestConfig { + return TestConfig{ + TargetPath: os.TempDir() + "/csi-mount", + StagingPath: os.TempDir() + "/csi-staging", + CreatePathCmdTimeout: 10 * time.Second, + RemovePathCmdTimeout: 10 * time.Second, + TestVolumeSize: 10 * 1024 * 1024 * 1024, // 10 GiB + IDGen: &DefaultIDGenerator{}, + } +} + // newContext sets up sanity testing with a config supplied by the // user of the sanity package. Ownership of that config is shared // between the sanity package and the caller. -func newContext(reqConfig *Config) *SanityContext { - // To avoid runtime if checks when using IDGen, a default - // is set here. - if reqConfig.IDGen == nil { - reqConfig.IDGen = &DefaultIDGenerator{} - } - - return &SanityContext{ - Config: reqConfig, +func newTestContext(config *TestConfig) *TestContext { + return &TestContext{ + Config: config, } } // Test will test the CSI driver at the specified address by // setting up a Ginkgo suite and running it. -func Test(t *testing.T, reqConfig *Config) { - // Get StorageClass parameters from TestVolumeParametersFile - loadFromFile(reqConfig.TestVolumeParametersFile, &reqConfig.TestVolumeParameters) - // Get VolumeSnapshotClass parameters from TestSnapshotParametersFile - loadFromFile(reqConfig.TestSnapshotParametersFile, &reqConfig.TestSnapshotParameters) - - sc := newContext(reqConfig) - registerTestsInGinkgo(sc) +func Test(t *testing.T, config TestConfig) { + sc := GinkgoTest(&config) RegisterFailHandler(Fail) var specReporters []Reporter - if reqConfig.JUnitFile != "" { - junitReporter := reporters.NewJUnitReporter(reqConfig.JUnitFile) + if config.JUnitFile != "" { + junitReporter := reporters.NewJUnitReporter(config.JUnitFile) specReporters = append(specReporters, junitReporter) } RunSpecsWithDefaultAndCustomReporters(t, "CSI Driver Test Suite", specReporters) - if sc.Conn != nil { - sc.Conn.Close() - } + sc.Finalize() } -// GinkoTest is another entry point for sanity testing: instead of directly -// running tests like Test does, it merely registers the tests. This can -// be used to embed sanity testing in a custom Ginkgo test suite. -func GinkgoTest(reqConfig *Config) { - sc := newContext(reqConfig) +// GinkoTest is another entry point for sanity testing: instead of +// directly running tests like Test does, it merely registers the +// tests. This can be used to embed sanity testing in a custom Ginkgo +// test suite. The pointer to the configuration is merely stored by +// GinkgoTest for use when the tests run. Therefore its content can +// still be modified in a BeforeEach. The sanity package itself treats +// it as read-only. +func GinkgoTest(config *TestConfig) *TestContext { + sc := newTestContext(config) registerTestsInGinkgo(sc) + return sc } -func (sc *SanityContext) Setup() { +// Setup must be invoked before each test. It initialize per-test +// variables in the context. +func (sc *TestContext) Setup() { var err error + // Get StorageClass parameters from TestVolumeParametersFile + loadFromFile(sc.Config.TestVolumeParametersFile, &sc.Config.TestVolumeParameters) + // Get VolumeSnapshotClass parameters from TestSnapshotParametersFile + loadFromFile(sc.Config.TestSnapshotParametersFile, &sc.Config.TestSnapshotParameters) + if len(sc.Config.SecretsFile) > 0 { sc.Secrets, err = loadSecrets(sc.Config.SecretsFile) Expect(err).NotTo(HaveOccurred()) @@ -247,7 +274,9 @@ func (sc *SanityContext) Setup() { sc.StagingPath = stagingPath } -func (sc *SanityContext) Teardown() { +// Teardown must be called after each test. It frees resources +// allocated by Setup. +func (sc *TestContext) Teardown() { // Delete the created paths if any. removeMountTargetLocation(sc.TargetPath, sc.Config.RemoveTargetPathCmd, sc.Config.RemoveTargetPath, sc.Config.RemovePathCmdTimeout) removeMountTargetLocation(sc.StagingPath, sc.Config.RemoveStagingPathCmd, sc.Config.RemoveStagingPath, sc.Config.RemovePathCmdTimeout) @@ -264,10 +293,21 @@ func (sc *SanityContext) Teardown() { // (https://github.com/kubernetes-csi/csi-test/pull/98). } +// Finalize frees any resources that might be still cached in the context. +// It should be called after running all tests. +func (sc *TestContext) Finalize() { + if sc.Conn != nil { + sc.Conn.Close() + } + if sc.ControllerConn != nil { + sc.ControllerConn.Close() + } +} + // createMountTargetLocation takes a target path parameter and creates the // target path using a custom command, custom function or falls back to the // default using mkdir and returns the new target path. -func createMountTargetLocation(targetPath string, createPathCmd string, customCreateDir func(string) (string, error), timeout int) (string, error) { +func createMountTargetLocation(targetPath string, createPathCmd string, customCreateDir func(string) (string, error), timeout time.Duration) (string, error) { // Return the target path if empty. if targetPath == "" { @@ -278,7 +318,7 @@ func createMountTargetLocation(targetPath string, createPathCmd string, customCr if createPathCmd != "" { // Create the target path using the create path command. - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() cmd := exec.CommandContext(ctx, createPathCmd, targetPath) @@ -312,13 +352,13 @@ func createMountTargetLocation(targetPath string, createPathCmd string, customCr // removeMountTargetLocation takes a target path parameter and removes the path // using a custom command, custom function or falls back to the default removal // by deleting the path on the host. -func removeMountTargetLocation(targetPath string, removePathCmd string, customRemovePath func(string) error, timeout int) error { +func removeMountTargetLocation(targetPath string, removePathCmd string, customRemovePath func(string) error, timeout time.Duration) error { if targetPath == "" { return nil } if removePathCmd != "" { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() cmd := exec.CommandContext(ctx, removePathCmd, targetPath) diff --git a/pkg/sanity/tests.go b/pkg/sanity/tests.go index 5ddc061c..92f2fe57 100644 --- a/pkg/sanity/tests.go +++ b/pkg/sanity/tests.go @@ -22,7 +22,7 @@ import ( type test struct { text string - body func(*SanityContext) + body func(*TestContext) } var tests []test @@ -32,14 +32,14 @@ var tests []test // will be called multiple times with the right context (when // setting up a Ginkgo suite or a testing.T test, with the right // configuration). -func DescribeSanity(text string, body func(*SanityContext)) bool { +func DescribeSanity(text string, body func(*TestContext)) bool { tests = append(tests, test{text, body}) return true } // registerTestsInGinkgo invokes the actual Gingko Describe // for the tests registered earlier with DescribeSanity. -func registerTestsInGinkgo(sc *SanityContext) { +func registerTestsInGinkgo(sc *TestContext) { for _, test := range tests { Describe(test.text, func() { BeforeEach(func() {