From 65ccfa10d521af60bd2ffe2ecf6322a1c4d254e6 Mon Sep 17 00:00:00 2001 From: Yaroslav Borbat Date: Fri, 29 May 2026 17:17:00 +0300 Subject: [PATCH] test: add postcleanup mode Signed-off-by: Yaroslav Borbat --- test/e2e/README.md | 15 +++++----- test/e2e/default_config.yaml | 6 ++-- test/e2e/internal/config/cleanup.go | 13 ++++++++- test/e2e/internal/config/config.go | 35 ++++++++++++++++++----- test/e2e/internal/framework/framework.go | 2 +- test/e2e/internal/precheck/postcleanup.go | 11 +++++-- test/e2e/legacy/image_hotplug.go | 2 +- test/e2e/legacy/legacy.go | 2 +- 8 files changed, 63 insertions(+), 23 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index 75e53f4653..71c485ae69 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -90,13 +90,13 @@ task runp ### Debugging options - Use the FOCUS environment variable to run a specific test. -- Set POST_CLEANUP=no to disable cleanup after tests (takes precedence over isCleanupNeeded in config). +- Set `POST_CLEANUP=never` to disable cleanup after tests (takes precedence over `postCleanupMode` in config). - Set LABELS to run tests with specific label(https://onsi.github.io/ginkgo/#spec-labels). - Manage timeouts for new e2e tests (not for legacy tests) using env variables `E2E_SHORT_TIMEOUT`, `E2E_MIDDLE_TIMEOUT`, `E2E_LONG_TIMEOUT` and `E2E_MAX_TIMEOUT`. For example, to run only one test and leave all created resources in the cluster, use the following command: ```bash -FOCUS="VirtualMachineConnectivity" POST_CLEANUP=no task run +FOCUS="VirtualMachineConnectivity" POST_CLEANUP=never task run ``` ### PostCleanUp option @@ -104,19 +104,20 @@ FOCUS="VirtualMachineConnectivity" POST_CLEANUP=no task run `POST_CLEANUP` defines an environment variable used to explicitly request the deletion of created/used resources. Valid values: -- `yes` or "" (empty) - perform cleanup after tests (default) -- `no` - skip cleanup after tests +- `always` or "" (empty) - perform cleanup after tests (default) +- `never` - skip cleanup after tests +- `no-failure` - perform cleanup only when the spec passes (skip cleanup on failure, preserving resources for investigation) -You can also control cleanup behavior via the `isCleanupNeeded` field in `default_config.yaml`: +You can also control cleanup behavior via the `postCleanupMode` field in `default_config.yaml`: ```yaml -isCleanupNeeded: true # default: cleanup enabled +postCleanupMode: always # default: cleanup enabled ``` The `POST_CLEANUP` environment variable takes precedence over the YAML config. For example, run a test in no-cleanup mode: ```bash -POST_CLEANUP=no task run +POST_CLEANUP=never task run ``` ### Working with `Virtualization-controller` errors diff --git a/test/e2e/default_config.yaml b/test/e2e/default_config.yaml index 78b93d7e75..52c01a46d2 100644 --- a/test/e2e/default_config.yaml +++ b/test/e2e/default_config.yaml @@ -1,8 +1,8 @@ namespaceSuffix: "e2e" -# isCleanupNeeded controls cleanup of resources created during test execution (VMs, VDs, namespaces, etc.) -# Enabled by default. Set to false to skip cleanup for debugging. -isCleanupNeeded: true +# postCleanupMode controls cleanup of resources created during test execution (VMs, VDs, namespaces, etc.) +# Enabled by default. Set to never or no-failure to skip cleanup for debugging. +postCleanupMode: always # isPrecreatedCVICleanupNeeded controls cleanup of precreated ClusterVirtualImages shared across test runs # Disabled by default: CVIs persist between runs for faster execution. # Set to true to delete them after the suite. diff --git a/test/e2e/internal/config/cleanup.go b/test/e2e/internal/config/cleanup.go index 5e3478b1cb..948fe0919f 100644 --- a/test/e2e/internal/config/cleanup.go +++ b/test/e2e/internal/config/cleanup.go @@ -16,6 +16,10 @@ limitations under the License. package config +import ( + "os" +) + // PrecreatedCVICleanupEnv defines an environment variable to explicitly enable deletion of precreated CVIs after the suite. // // By default, precreated CVIs are not deleted: they are shared across runs and may be reused. @@ -23,5 +27,12 @@ package config const PrecreatedCVICleanupEnv = "PRECREATED_CVI_CLEANUP" // PostCleanupEnv defines an environment variable used to explicitly request the deletion of created/used resources. -// Valid values: "yes", "no", or "" (default = yes). +// Valid values: "always", "never", "no-failure", or "" (default = always). const PostCleanupEnv = "POST_CLEANUP" + +func LoadPostCleanupMode() PostCleanupMode { + if e, ok := os.LookupEnv(PostCleanupEnv); ok { + return PostCleanupMode(e) + } + return PostCleanupAlways +} diff --git a/test/e2e/internal/config/config.go b/test/e2e/internal/config/config.go index feb5141fd0..5e94846bb2 100644 --- a/test/e2e/internal/config/config.go +++ b/test/e2e/internal/config/config.go @@ -26,6 +26,7 @@ import ( "slices" "strconv" + "github.com/onsi/ginkgo/v2" yamlv3 "gopkg.in/yaml.v3" storagev1 "k8s.io/api/storage/v1" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -76,9 +77,9 @@ type Config struct { LogFilter []string `yaml:"logFilter"` CleanupResources []string `yaml:"cleanupResources"` RegexpLogFilter []regexp.Regexp `yaml:"regexpLogFilter"` - // IsCleanupNeeded controls cleanup of resources created during test execution (VMs, VDs, namespaces, etc.). - // Enabled by default (POST_CLEANUP=yes or unset). Set to false to skip cleanup for debugging. - IsCleanupNeeded bool `yaml:"isCleanupNeeded"` + // PostCleanupMode controls cleanup of resources created during test execution (VMs, VDs, namespaces, etc.). + // Enabled by default (POST_CLEANUP=always or unset). Set to never or no-failure to skip cleanup for debugging. + PostCleanupMode PostCleanupMode `yaml:"postCleanupMode"` // IsPrecreatedCVICleanupNeeded controls cleanup of precreated ClusterVirtualImages that are shared across test runs. // Disabled by default (PRECREATED_CVI_CLEANUP=no): CVIs persist between runs for faster execution. // Set to true to delete them after the suite. @@ -87,6 +88,28 @@ type Config struct { StorageClass StorageClass } +func (c *Config) IsCleanupNeeded() bool { + switch c.PostCleanupMode { + case PostCleanupAlways: + return true + case PostCleanupNever: + return false + case PostCleanupNoFailure: + return !ginkgo.CurrentSpecReport().Failed() + default: + ginkgo.GinkgoWriter.Printf("Unknown PostCleanupMode: %s, defaulting to always\n", c.PostCleanupMode) + return true + } +} + +type PostCleanupMode string + +const ( + PostCleanupAlways PostCleanupMode = "always" + PostCleanupNever PostCleanupMode = "never" + PostCleanupNoFailure PostCleanupMode = "no-failure" +) + type TestData struct { ImageHotplug string `yaml:"imageHotplug"` VMMigration string `yaml:"vmMigration"` @@ -133,10 +156,8 @@ type HelperImages struct { } func (c *Config) setEnvs() error { - // isCleanupNeeded: env var has priority over yaml config - if e, ok := os.LookupEnv(PostCleanupEnv); ok { - c.IsCleanupNeeded = e != "no" - } + c.PostCleanupMode = LoadPostCleanupMode() + // isPrecreatedCVICleanupNeeded: env var has priority over yaml config if e, ok := os.LookupEnv("PRECREATED_CVI_CLEANUP"); ok { c.IsPrecreatedCVICleanupNeeded = e == "yes" diff --git a/test/e2e/internal/framework/framework.go b/test/e2e/internal/framework/framework.go index 14b7596b68..e7092f8f7d 100644 --- a/test/e2e/internal/framework/framework.go +++ b/test/e2e/internal/framework/framework.go @@ -72,7 +72,7 @@ func (f *Framework) Before() { func (f *Framework) After() { GinkgoHelper() - if GetConfig().IsCleanupNeeded { + if GetConfig().IsCleanupNeeded() { defer func() { if f.namespace != nil { By("Cleanup: delete namespace") diff --git a/test/e2e/internal/precheck/postcleanup.go b/test/e2e/internal/precheck/postcleanup.go index d39cba727d..309e2b4cef 100644 --- a/test/e2e/internal/precheck/postcleanup.go +++ b/test/e2e/internal/precheck/postcleanup.go @@ -51,10 +51,17 @@ func (c *postcleanupPrecheck) Run(ctx context.Context, f *framework.Framework) e // Validate POST_CLEANUP env var (controls cleanup behavior) env := os.Getenv(config.PostCleanupEnv) switch env { - case "yes", "no", "": + case string(config.PostCleanupAlways), string(config.PostCleanupNever), string(config.PostCleanupNoFailure), "": // valid values default: - return fmt.Errorf("invalid value for the %s env: %q (allowed: \"\", \"yes\", \"no\")", config.PostCleanupEnv, env) + return fmt.Errorf( + "invalid value for the %s env: %q (allowed: \"\", %q, %q, %q)", + config.PostCleanupEnv, + env, + config.PostCleanupAlways, + config.PostCleanupNever, + config.PostCleanupNoFailure, + ) } return nil diff --git a/test/e2e/legacy/image_hotplug.go b/test/e2e/legacy/image_hotplug.go index eeccb42e4e..ce3a5d2494 100644 --- a/test/e2e/legacy/image_hotplug.go +++ b/test/e2e/legacy/image_hotplug.go @@ -82,7 +82,7 @@ var _ = Describe("ImageHotplug", Ordered, label.Legacy(), Label(precheck.NoPrech }) AfterAll(func() { - if conf.IsCleanupNeeded { + if conf.IsCleanupNeeded() { DeleteTestCaseResources(ns, ResourcesToDelete{ KustomizationDir: conf.TestData.ImageHotplug, }) diff --git a/test/e2e/legacy/legacy.go b/test/e2e/legacy/legacy.go index c71e7f4e34..0472c21ace 100644 --- a/test/e2e/legacy/legacy.go +++ b/test/e2e/legacy/legacy.go @@ -150,7 +150,7 @@ func NewBeforeProcess1Body() { } func NewAfterAllProcessBody() { - if conf.IsCleanupNeeded { + if conf.IsCleanupNeeded() { Expect(Cleanup()).To(Succeed()) } }