From 7081aeef1f3e95d1cd7eb5ae14d28a0969665e04 Mon Sep 17 00:00:00 2001 From: Ravi Shankar Date: Thu, 19 Sep 2024 14:43:25 -0700 Subject: [PATCH] test(GcpNfsBackupSchedule): e2e tests --- features/000-module.feature | 2 + features/200-gcpnfs-backup-schedule.feature | 39 +++++++++ internal/register.go | 6 ++ internal/valueAssert.go | 90 +++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 features/200-gcpnfs-backup-schedule.feature diff --git a/features/000-module.feature b/features/000-module.feature index a21be1b..2a8cd71 100644 --- a/features/000-module.feature +++ b/features/000-module.feature @@ -23,6 +23,7 @@ Feature: Module enable feature | GcpNfsVolume | | GcpNfsVolumeBackup | | GcpNfsVolumeRestore | + | GcpNfsBackupSchedule| | GcpRedisInstance | | GcpVpcPeering | | AzureVpcPeering | @@ -36,6 +37,7 @@ Feature: Module enable feature | GcpNfsVolume | | GcpNfsVolumeBackup | | GcpNfsVolumeRestore | + | GcpNfsBackupSchedule| | GcpRedisInstance | | GcpVpcPeering | And CRDs do not exist: diff --git a/features/200-gcpnfs-backup-schedule.feature b/features/200-gcpnfs-backup-schedule.feature new file mode 100644 index 0000000..4728d45 --- /dev/null +++ b/features/200-gcpnfs-backup-schedule.feature @@ -0,0 +1,39 @@ +Feature: GcpNfsBackupSchedule feature + + @gcp @allShoots @allEnvs + Scenario: GcpNfsVolume scenario + Given resource declaration: + | vol | GcpNfsVolume | "vol-"+rndStr(8) | namespace | + | schedule | GcpNfsBackupSchedule | "test-schedule-"+rndStr(3) | namespace | + | backup | GcpNfsVolumeBackup | schedule.status.lastCreatedBackup.name | namespace | + + When resource vol is applied: + """ + apiVersion: cloud-resources.kyma-project.io/v1beta1 + kind: GcpNfsVolume + spec: + capacityGb: 1024 + """ + Then eventually value load("vol").status.state equals "Ready" with timeout2X + + When resource schedule is applied: + """ + apiVersion: cloud-resources.kyma-project.io/v1beta1 + kind: GcpNfsBackupSchedule + spec: + nfsVolumeRef: + name: <(vol.metadata.name)> + schedule: "*/5 * * * *" + prefix: five-minutes-backup + deleteCascade: true + """ + Then eventually value load("schedule").status.state equals "Active" + And eventually value load("schedule").status.lastCreatedBackup.name is not zero + And eventually value load("backup").status.state equals "Ready" + + When resource schedule is deleted + Then eventually resource backup does not exist + And eventually resource schedule does not exist + + When resource vol is deleted + And eventually resource vol does not exist diff --git a/internal/register.go b/internal/register.go index 4f498e7..6e03f98 100644 --- a/internal/register.go +++ b/internal/register.go @@ -49,6 +49,12 @@ func Register(ctx *godog.ScenarioContext) { ctx.Step("^value (.*) equals (.*)$", valueAssertEquals) ctx.Step("^eventually value (.*) equals (.*) with (.*)$", eventuallyValueAssertEqualsWithOptions) ctx.Step("^eventually value (.*) equals (.*)$", eventuallyValueAssertEqualsNoOptions) + ctx.Step("^value (.*) is zero$", valueAssertIsZero) + ctx.Step("^eventually value (.*) is zero with (.*)$", eventuallyValueAssertIsZeroWithOptions) + ctx.Step("^eventually value (.*) is zero$", eventuallyValueAssertIsZeroNoOptions) + ctx.Step("^value (.*) is not zero$", valueAssertIsNotZero) + ctx.Step("^eventually value (.*) is not zero with (.*)$", eventuallyValueAssertIsNotZeroWithOptions) + ctx.Step("^eventually value (.*) is not zero$", eventuallyValueAssertIsNotZeroNoOptions) ctx.Step(`^resource (.*) is deleted`, resourceDeleted) ctx.Step(`^cleanup (.*)$`, cleanup) ctx.Step(`^resource (.*) does not exist$`, resourceDoesNotExist) diff --git a/internal/valueAssert.go b/internal/valueAssert.go index c0d14cb..e6a1952 100644 --- a/internal/valueAssert.go +++ b/internal/valueAssert.go @@ -71,3 +71,93 @@ func valueAssertEquals(ctx context.Context, a string, b string) error { return nil } + +func eventuallyValueAssertIsZeroNoOptions(ctx context.Context, a string) error { + return eventuallyValueAssertZeroWithOptions(ctx, a, true, "") +} + +func eventuallyValueAssertIsZeroWithOptions(ctx context.Context, a string, withOpts string) error { + return eventuallyValueAssertZeroWithOptions(ctx, a, true, withOpts) +} + +func eventuallyValueAssertIsNotZeroNoOptions(ctx context.Context, a string) error { + return eventuallyValueAssertZeroWithOptions(ctx, a, false, "") +} + +func eventuallyValueAssertIsNotZeroWithOptions(ctx context.Context, a string, withOpts string) error { + return eventuallyValueAssertZeroWithOptions(ctx, a, false, withOpts) +} + +func eventuallyValueAssertZeroWithOptions(ctx context.Context, a string, isZero bool, withOpts string) error { + timeout := DefaultEventuallyTimeout + + withOpts = strings.TrimSpace(withOpts) + if len(withOpts) > 0 { + opts := strings.Split(withOpts, ",") + for _, opt := range opts { + opt = strings.TrimSpace(opt) + if opt == "" { + continue + } + // ugly, but for now with just few timeout1-5X works, if you add more, try to find a better implementation. + switch opt { + case "timeout2X": + timeout = 2 * timeout + case "timeout3X": + timeout = 3 * timeout + case "timeout4X": + timeout = 4 * timeout + case "timeout5X": + timeout = 5 * timeout + default: + return fmt.Errorf("unknown option: %s", opt) + } + } + } + + var errMsg string + gm := gomega.NewGomega(func(message string, callerSkip ...int) { + errMsg = message + }) + ok := gm.Eventually(func(ctx context.Context, a string) error { + if isZero { + return valueAssertIsZero(ctx, a) + } else { + return valueAssertIsNotZero(ctx, a) + } + }, timeout). + WithArguments(ctx, a). + Should(gomega.Succeed()) + if !ok || len(errMsg) > 0 { + return fmt.Errorf("failed: %s", errMsg) + } + return nil +} + +func valueAssertIsZero(ctx context.Context, a string) error { + kfrCtx := KfrFromContext(ctx) + aa, err := kfrCtx.Eval(ctx, a) + if err != nil { + return fmt.Errorf("error evaluating value %s: %w", a, err) + } + + value := reflect.ValueOf(aa) + if value.IsValid() && !value.IsZero() { + return fmt.Errorf("value %s (%v) is not zero", a, aa) + } + return nil +} + +func valueAssertIsNotZero(ctx context.Context, a string) error { + kfrCtx := KfrFromContext(ctx) + aa, err := kfrCtx.Eval(ctx, a) + if err != nil { + return fmt.Errorf("error evaluating value %s: %w", a, err) + } + + value := reflect.ValueOf(aa) + if !value.IsValid() || value.IsZero() { + return fmt.Errorf("value %s (%v) is not valid or zero", a, aa) + } + return nil +}