Files
external-snapshotter/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go
2018-11-14 16:54:21 -08:00

195 lines
5.5 KiB
Go

/*
Copyright 2017 Luis Pabón luis@portworx.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package sanity
import (
"crypto/rand"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/kubernetes-csi/csi-test/utils"
yaml "gopkg.in/yaml.v2"
"google.golang.org/grpc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
// CSISecrets consists of secrets used in CSI credentials.
type CSISecrets struct {
CreateVolumeSecret map[string]string `yaml:"CreateVolumeSecret"`
DeleteVolumeSecret map[string]string `yaml:"DeleteVolumeSecret"`
ControllerPublishVolumeSecret map[string]string `yaml:"ControllerPublishVolumeSecret"`
ControllerUnpublishVolumeSecret map[string]string `yaml:"ControllerUnpublishVolumeSecret"`
NodeStageVolumeSecret map[string]string `yaml:"NodeStageVolumeSecret"`
NodePublishVolumeSecret map[string]string `yaml:"NodePublishVolumeSecret"`
CreateSnapshotSecret map[string]string `yaml:"CreateSnapshotSecret"`
DeleteSnapshotSecret map[string]string `yaml:"DeleteSnapshotSecret"`
}
// Config provides the configuration for the sanity tests. It
// needs to be initialized by the user of the sanity package.
type Config struct {
TargetPath string
StagingPath string
Address string
SecretsFile string
TestVolumeSize int64
TestVolumeParametersFile string
TestVolumeParameters map[string]string
}
// SanityContext holds the variables that each test can depend on. It
// gets initialized before each test block runs.
type SanityContext struct {
Config *Config
Conn *grpc.ClientConn
Secrets *CSISecrets
connAddress string
}
// 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) {
path := reqConfig.TestVolumeParametersFile
if len(path) != 0 {
yamlFile, err := ioutil.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("failed to read file %q: %v", path, err))
}
err = yaml.Unmarshal(yamlFile, &reqConfig.TestVolumeParameters)
if err != nil {
panic(fmt.Sprintf("error unmarshaling yaml: %v", err))
}
}
sc := &SanityContext{
Config: reqConfig,
}
registerTestsInGinkgo(sc)
RegisterFailHandler(Fail)
RunSpecs(t, "CSI Driver Test Suite")
}
func GinkgoTest(reqConfig *Config) {
sc := &SanityContext{
Config: reqConfig,
}
registerTestsInGinkgo(sc)
}
func (sc *SanityContext) setup() {
var err error
if len(sc.Config.SecretsFile) > 0 {
sc.Secrets, err = loadSecrets(sc.Config.SecretsFile)
Expect(err).NotTo(HaveOccurred())
} else {
sc.Secrets = &CSISecrets{}
}
// It is possible that a test sets sc.Config.Address
// dynamically (and differently!) in a BeforeEach, so only
// reuse the connection if the address is still the same.
if sc.Conn == nil || sc.connAddress != sc.Config.Address {
By("connecting to CSI driver")
sc.Conn, err = utils.Connect(sc.Config.Address)
Expect(err).NotTo(HaveOccurred())
sc.connAddress = sc.Config.Address
} else {
By(fmt.Sprintf("reusing connection to CSI driver at %s", sc.connAddress))
}
By("creating mount and staging directories")
err = createMountTargetLocation(sc.Config.TargetPath)
Expect(err).NotTo(HaveOccurred())
if len(sc.Config.StagingPath) > 0 {
err = createMountTargetLocation(sc.Config.StagingPath)
Expect(err).NotTo(HaveOccurred())
}
}
func (sc *SanityContext) teardown() {
// We intentionally do not close the connection to the CSI
// driver here because the large amount of connection attempts
// caused test failures
// (https://github.com/kubernetes-csi/csi-test/issues/101). We
// could fix this with retries
// (https://github.com/kubernetes-csi/csi-test/pull/97) but
// that requires more discussion, so instead we just connect
// once per process instead of once per test case. This was
// also said to be faster
// (https://github.com/kubernetes-csi/csi-test/pull/98).
}
func createMountTargetLocation(targetPath string) error {
fileInfo, err := os.Stat(targetPath)
if err != nil && os.IsNotExist(err) {
return os.MkdirAll(targetPath, 0755)
} else if err != nil {
return err
}
if !fileInfo.IsDir() {
return fmt.Errorf("Target location %s is not a directory", targetPath)
}
return nil
}
func loadSecrets(path string) (*CSISecrets, error) {
var creds CSISecrets
yamlFile, err := ioutil.ReadFile(path)
if err != nil {
return &creds, fmt.Errorf("failed to read file %q: #%v", path, err)
}
err = yaml.Unmarshal(yamlFile, &creds)
if err != nil {
return &creds, fmt.Errorf("error unmarshaling yaml: #%v", err)
}
return &creds, nil
}
var uniqueSuffix = "-" + pseudoUUID()
// pseudoUUID returns a unique string generated from random
// bytes, empty string in case of error.
func pseudoUUID() string {
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
// Shouldn't happen?!
return ""
}
return fmt.Sprintf("%08X-%08X", b[0:4], b[4:8])
}
// uniqueString returns a unique string by appending a random
// number. In case of an error, just the prefix is returned, so it
// alone should already be fairly unique.
func uniqueString(prefix string) string {
return prefix + uniqueSuffix
}