diff --git a/pkg/apis/testharness/v1beta1/test_types.go b/pkg/apis/testharness/v1beta1/test_types.go index 7907eaf7..4330fff3 100644 --- a/pkg/apis/testharness/v1beta1/test_types.go +++ b/pkg/apis/testharness/v1beta1/test_types.go @@ -65,6 +65,8 @@ type TestSuite struct { // Any other value is the name of the namespace to use. This namespace will be created if it does not exist and will // be removed it was created (unless --skipDelete is used). Namespace string `json:"namespace"` + // BlockOnNamespaceDelete determines if the test suite should wait until a namespace is deleted before it finishes + BlockOnNamespaceDelete bool `json:"blockOnNamespaceDelete"` // Suppress is used to suppress logs Suppress []string `json:"suppress"` } diff --git a/pkg/kuttlctl/cmd/test.go b/pkg/kuttlctl/cmd/test.go index a97b949a..788f4262 100644 --- a/pkg/kuttlctl/cmd/test.go +++ b/pkg/kuttlctl/cmd/test.go @@ -51,6 +51,7 @@ func newTestCmd() *cobra.Command { startKIND := false kindConfig := "" kindContext := "" + blockOnNamespaceDelete := false skipDelete := false skipClusterDelete := false parallel := 0 @@ -182,6 +183,10 @@ For more detailed documentation, visit: https://kuttl.dev`, options.Namespace = namespace } + if isSet(flags, "block-on-namespace-delete") { + options.BlockOnNamespaceDelete = blockOnNamespaceDelete + } + if isSet(flags, "suppress-log") { suppressSet := make(map[string]struct{}) for _, s := range append(options.Suppress, suppress...) { @@ -251,6 +256,7 @@ For more detailed documentation, visit: https://kuttl.dev`, testCmd.Flags().IntVar(&timeout, "timeout", 30, "The timeout to use as default for TestSuite configuration.") testCmd.Flags().StringVar(&reportFormat, "report", "", "Specify JSON|XML for report. Report location determined by --artifacts-dir.") testCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to use for tests. Provided namespaces must exist prior to running tests.") + testCmd.Flags().BoolVar(&blockOnNamespaceDelete, "block-on-namespace-delete", false, "Block the test harness until the namespace is deleted") testCmd.Flags().StringSliceVar(&suppress, "suppress-log", []string{}, "Suppress logging for these kinds of logs (events).") // This cannot be a global flag because pkg/test/utils.RunTests calls flag.Parse which barfs on unknown top-level flags. // Putting it here at least does not advertise it on a level where using it is impossible. diff --git a/pkg/test/case.go b/pkg/test/case.go index 496a62a2..76368e10 100644 --- a/pkg/test/case.go +++ b/pkg/test/case.go @@ -34,12 +34,13 @@ var testStepRegex = regexp.MustCompile(`^(\d+)-(?:[^\.]+)(?:\.yaml)?$`) // Case contains all of the test steps and the Kubernetes client and other global configuration // for a test. type Case struct { - Steps []*Step - Name string - Dir string - SkipDelete bool - Timeout int - PreferredNamespace string + Steps []*Step + Name string + Dir string + SkipDelete bool + Timeout int + PreferredNamespace string + BlockOnNamespaceDelete bool Client func(forceNew bool) (client.Client, error) DiscoveryClient func() (discovery.DiscoveryInterface, error) @@ -84,13 +85,18 @@ func (t *Case) DeleteNamespace(cl client.Client, ns *namespace) error { return err } - return wait.PollImmediateUntil(100*time.Millisecond, func() (done bool, err error) { - err = cl.Get(ctx, client.ObjectKeyFromObject(nsobj), &corev1.Namespace{}) - if err == nil || !errors.IsNotFound(err) { - return false, err - } - return true, nil - }, ctx.Done()) + if t.BlockOnNamespaceDelete { + t.Logger.Log("Blocking until namespace is deleted:", ns.Name) + return wait.PollImmediateUntil(100*time.Millisecond, func() (done bool, err error) { + err = cl.Get(ctx, client.ObjectKeyFromObject(nsobj), &corev1.Namespace{}) + if err == nil || !errors.IsNotFound(err) { + return false, err + } + return true, nil + }, ctx.Done()) + } + + return nil } // CreateNamespace creates a namespace in Kubernetes to use for a test. diff --git a/pkg/test/harness.go b/pkg/test/harness.go index 1e972295..b2a79a8e 100644 --- a/pkg/test/harness.go +++ b/pkg/test/harness.go @@ -79,13 +79,14 @@ func (h *Harness) LoadTests(dir string) ([]*Case, error) { } tests = append(tests, &Case{ - Timeout: timeout, - Steps: []*Step{}, - Name: file.Name(), - PreferredNamespace: h.TestSuite.Namespace, - Dir: filepath.Join(dir, file.Name()), - SkipDelete: h.TestSuite.SkipDelete, - Suppress: h.TestSuite.Suppress, + Timeout: timeout, + Steps: []*Step{}, + Name: file.Name(), + PreferredNamespace: h.TestSuite.Namespace, + Dir: filepath.Join(dir, file.Name()), + BlockOnNamespaceDelete: h.TestSuite.BlockOnNamespaceDelete, + SkipDelete: h.TestSuite.SkipDelete, + Suppress: h.TestSuite.Suppress, }) }