diff --git a/go.mod b/go.mod index 62180a3f1..7940e1a5c 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( cloud.google.com/go v0.61.0 // indirect + github.com/Masterminds/semver v1.5.0 github.com/aws/aws-sdk-go v1.33.9 // indirect github.com/ghodss/yaml v1.0.0 github.com/go-errors/errors v1.1.1 // indirect diff --git a/go.sum b/go.sum index 474aed86e..9e736eae3 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -720,6 +722,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/test/minikube/minikube_long_restore_test.go b/test/minikube/minikube_long_restore_test.go index 7669a7147..cb73a18e4 100644 --- a/test/minikube/minikube_long_restore_test.go +++ b/test/minikube/minikube_long_restore_test.go @@ -146,6 +146,7 @@ func TestKubernetesRestoreWithStorageGroups(t *testing.T) { if os.Getenv("NUODB_LICENSE") != "ENTERPRISE" && os.Getenv("NUODB_LICENSE_CONTENT") == "" { t.Skip("Cannot test multiple SMs without the Enterprise Edition") } + testlib.SkipTestOnNuoDBVersionCondition(t, "< 4.2") testlib.AwaitTillerUp(t) defer testlib.VerifyTeardown(t) defer testlib.Teardown(testlib.TEARDOWN_ADMIN) @@ -186,6 +187,7 @@ func TestKubernetesRestoreWithStorageGroups(t *testing.T) { smPodNameTemplate := fmt.Sprintf("sm-%s-nuodb-%s-%s", databaseChartName, opt.ClusterName, opt.DbName) hcSmPodNameTemplate := fmt.Sprintf("%s-hotcopy", smPodNameTemplate) hcSmPodName0 := fmt.Sprintf("%s-0", hcSmPodNameTemplate) + hcSmPodName1 := fmt.Sprintf("%s-1", hcSmPodNameTemplate) // Create 2 storage groups, each served by only one archive k8s.RunKubectl(t, kubectlOptions, "exec", admin0, "--", @@ -220,13 +222,21 @@ func TestKubernetesRestoreWithStorageGroups(t *testing.T) { tePodName := testlib.GetPodName(t, namespaceName, tePodNameTemplate) go testlib.GetAppLog(t, namespaceName, tePodName, "_pre-restart", &corev1.PodLogOptions{Follow: true}) go testlib.GetAppLog(t, namespaceName, hcSmPodName0, "_pre-restart", &corev1.PodLogOptions{Follow: true}) + go testlib.GetAppLog(t, namespaceName, hcSmPodName1, "_pre-restart", &corev1.PodLogOptions{Follow: true}) defer testlib.Teardown(testlib.TEARDOWN_RESTORE) + // Get SM pod logs if the test fails + testlib.AddDiagnosticTeardown(testlib.TEARDOWN_DATABASE, t, func() { + testlib.GetAppLog(t, namespaceName, hcSmPodName0, "_post-restore", &corev1.PodLogOptions{}) + testlib.GetAppLog(t, namespaceName, hcSmPodName1, "_post-restore", &corev1.PodLogOptions{}) + }) + // restore database databaseOptions.SetValues["restore.source"] = backupset testlib.RestoreDatabase(t, namespaceName, admin0, &databaseOptions) testlib.AwaitPodLog(t, namespaceName, hcSmPodName0, "_post-restart") + testlib.AwaitPodLog(t, namespaceName, hcSmPodName1, "_post-restart") // verify that the database does NOT contain the data from AFTER the backup diff --git a/test/testlib/nuodb_database_utilities.go b/test/testlib/nuodb_database_utilities.go index 5f5ec3ae3..93999749e 100644 --- a/test/testlib/nuodb_database_utilities.go +++ b/test/testlib/nuodb_database_utilities.go @@ -6,6 +6,7 @@ import ( "os" "path" "path/filepath" + "regexp" "strconv" "strings" "testing" @@ -14,6 +15,7 @@ import ( corev1 "k8s.io/api/core/v1" v12 "k8s.io/api/core/v1" + "github.com/Masterminds/semver" "github.com/gruntwork-io/terratest/modules/helm" "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/random" @@ -355,3 +357,58 @@ func ServePodFileViaHTTP(t *testing.T, namespaceName string, srcPodName string, k8s.RunKubectl(t, kubectlOptions, "cp", localFilePath, nginxPod+":/usr/share/nginx/html/"+fileName) return fmt.Sprintf("http://nginx.%s.svc.cluster.local/%s", namespaceName, fileName) } + +func GetNuoDBVersion(t *testing.T, namespaceName string, options *helm.Options) string { + kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName) + podName := "nuodb-version" + InferVersionFromTemplate(t, options) + InjectTestValues(t, options) + defer func() { + // Delete the pod just in case "--rm" doesn't do it + k8s.RunKubectlE(t, kubectlOptions, "delete", "pod", podName) + }() + nuodbImage := fmt.Sprintf( + "%s/%s:%s", + options.SetValues["nuodb.image.registry"], + options.SetValues["nuodb.image.repository"], + options.SetValues["nuodb.image.tag"]) + output, err := k8s.RunKubectlAndGetOutputE( + t, kubectlOptions, "run", podName, + "--image", nuodbImage, "--restart=Never", "--rm", "--attach", "--command", "--", + "nuodb", "--version") + require.NoError(t, err, "Unable to check NuoDB version in helper pod") + match := regexp.MustCompile("NuoDB Server build (.*)").FindStringSubmatch(output) + require.NotNil(t, match, "Unable to match NuoDB version from output") + return match[1] +} + +func SkipTestOnNuoDBVersion(t *testing.T, versionCheckFunc func(*semver.Version) bool) { + randomSuffix := strings.ToLower(random.UniqueId()) + defer Teardown(TEARDOWN_ADMIN) + namespaceName := fmt.Sprintf("nuodbversioncheck-%s", randomSuffix) + CreateNamespace(t, namespaceName) + versionString := GetNuoDBVersion(t, namespaceName, &helm.Options{}) + // Select only the main NuoDB version (i.e 4.2.1) from the full version string + versionString = regexp.MustCompile(`^([0-9]+\.[0-9]+(?:\.[0-9]+)?).*$`). + ReplaceAllString(versionString, "${1}") + version, err := semver.NewVersion(versionString) + require.NoError(t, err, "Unable to parse NuoDB version", versionString) + if versionCheckFunc(version) { + t.Skip("Skipping test when using NuoDB version", version) + } +} + +/** + * Skip test if NuoDB version matches the provided condition. + * + * For more information about supported condition strings, please + * check https://github.com/Masterminds/semver. + * + */ +func SkipTestOnNuoDBVersionCondition(t *testing.T, condition string) { + SkipTestOnNuoDBVersion(t, func(version *semver.Version) bool { + c, err := semver.NewConstraint(condition) + require.NoError(t, err) + return c.Check(version) + }) +}