Skip to content

Commit 6ec1572

Browse files
committed
Migrate operator upgrade tests to Godog/cucumber
1 parent 32761fc commit 6ec1572

File tree

9 files changed

+451
-446
lines changed

9 files changed

+451
-446
lines changed

Makefile

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,17 @@ verify-crd-compatibility: $(CRD_DIFF) manifests
238238

239239
#SECTION Test
240240

241+
define install-sh
242+
.PHONY: $(1)/install.sh
243+
$(1)/install.sh: manifests
244+
@echo -e "\n\U1F4D8 Using $(1).yaml as source manifest\n"
245+
sed "s/cert-git-version/cert-$$(VERSION)/g" manifests/$(1).yaml > $(2)
246+
MANIFEST=$(2) INSTALL_DEFAULT_CATALOGS=false DEFAULT_CATALOG=$$(RELEASE_CATALOGS) envsubst '$$$$DEFAULT_CATALOG,$$$$CERT_MGR_VERSION,$$$$INSTALL_DEFAULT_CATALOGS,$$$$MANIFEST' < scripts/install.tpl.sh > $(1)-install.sh
247+
endef
248+
249+
$(eval $(call install-sh,experimental,operator-controller-experimental.yaml))
250+
$(eval $(call install-sh,standard,operator-controller-standard.yaml))
251+
241252
.PHONY: test
242253
test: manifests generate fmt lint test-unit test-e2e test-regression #HELP Run all tests.
243254

@@ -339,48 +350,43 @@ run-latest-release:
339350
pre-upgrade-setup:
340351
./hack/test/pre-upgrade-setup.sh $(CATALOG_IMG) $(TEST_CLUSTER_CATALOG_NAME) $(TEST_CLUSTER_EXTENSION_NAME)
341352

342-
.PHONY: post-upgrade-checks
343-
post-upgrade-checks:
344-
go test -count=1 -v ./test/upgrade-e2e/...
353+
.PHONY: test-upgrade-e2e
354+
test-upgrade-e2e:
355+
RELEASE_INSTALL=$(RELEASE_INSTALL) \
356+
RELEASE_UPGRADE=$(RELEASE_UPGRADE) \
357+
KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) \
358+
ROOT_DIR=$(ROOT_DIR) \
359+
go test -count=1 -v ./test/upgrade-e2e/upgrade_test.go
345360

346361

347-
TEST_UPGRADE_E2E_TASKS := kind-cluster run-latest-release image-registry pre-upgrade-setup docker-build kind-load kind-deploy post-upgrade-checks kind-clean
362+
TEST_UPGRADE_E2E_TASKS := kind-cluster docker-build kind-load test-upgrade-e2e kind-clean
348363

349364
.PHONY: test-upgrade-st2st-e2e
350-
test-upgrade-st2st-e2e: SOURCE_MANIFEST := $(STANDARD_MANIFEST)
351-
test-upgrade-st2st-e2e: RELEASE_INSTALL := $(STANDARD_RELEASE_INSTALL)
365+
test-upgrade-st2st-e2e: RELEASE_INSTALL := https://github.com/operator-framework/operator-controller/releases/latest/download/install.sh
366+
test-upgrade-st2st-e2e: RELEASE_UPGRADE := $(ROOT_DIR)/standard-install.sh
352367
test-upgrade-st2st-e2e: KIND_CLUSTER_NAME := operator-controller-upgrade-st2st-e2e
353-
test-upgrade-st2st-e2e: export MANIFEST := $(STANDARD_RELEASE_MANIFEST)
354-
test-upgrade-st2st-e2e: export TEST_CLUSTER_CATALOG_NAME := test-catalog
355-
test-upgrade-st2st-e2e: export TEST_CLUSTER_EXTENSION_NAME := test-package
356-
test-upgrade-st2st-e2e: $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (standard -> standard) e2e tests on a local kind cluster
368+
test-upgrade-st2st-e2e: standard/install.sh $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (standard -> standard) e2e tests on a local kind cluster
357369

358370
.PHONY: test-upgrade-ex2ex-e2e
359-
test-upgrade-ex2ex-e2e: SOURCE_MANIFEST := $(EXPERIMENTAL_MANIFEST)
360-
test-upgrade-ex2ex-e2e: RELEASE_INSTALL := $(EXPERIMENTAL_RELEASE_INSTALL)
371+
test-upgrade-ex2ex-e2e: RELEASE_INSTALL := https://github.com/operator-framework/operator-controller/releases/latest/download/install-experimental.sh
361372
test-upgrade-ex2ex-e2e: KIND_CLUSTER_NAME := operator-controller-upgrade-ex2ex-e2e
362-
test-upgrade-ex2ex-e2e: export MANIFEST := $(EXPERIMENTAL_RELEASE_MANIFEST)
363-
test-upgrade-ex2ex-e2e: export TEST_CLUSTER_CATALOG_NAME := test-catalog
364-
test-upgrade-ex2ex-e2e: export TEST_CLUSTER_EXTENSION_NAME := test-package
365-
test-upgrade-ex2ex-e2e: $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (experimental -> experimental) e2e tests on a local kind cluster
373+
test-upgrade-ex2ex-e2e: RELEASE_UPGRADE := $(ROOT_DIR)/experimental-install.sh
374+
test-upgrade-ex2ex-e2e: experimental/install.sh $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (experimental -> experimental) e2e tests on a local kind cluster
366375

367376
.PHONY: test-upgrade-st2ex-e2e
368-
test-upgrade-st2ex-e2e: SOURCE_MANIFEST := $(EXPERIMENTAL_MANIFEST)
369-
test-upgrade-st2ex-e2e: RELEASE_INSTALL := $(STANDARD_RELEASE_INSTALL)
377+
test-upgrade-st2ex-e2e: RELEASE_INSTALL := https://github.com/operator-framework/operator-controller/releases/latest/download/install.sh
378+
test-upgrade-st2ex-e2e: RELEASE_UPGRADE := $(ROOT_DIR)/experimental-install.sh
370379
test-upgrade-st2ex-e2e: KIND_CLUSTER_NAME := operator-controller-upgrade-st2ex-e2e
371-
test-upgrade-st2ex-e2e: export MANIFEST := $(EXPERIMENTAL_RELEASE_MANIFEST)
372-
test-upgrade-st2ex-e2e: export TEST_CLUSTER_CATALOG_NAME := test-catalog
373-
test-upgrade-st2ex-e2e: export TEST_CLUSTER_EXTENSION_NAME := test-package
374-
test-upgrade-st2ex-e2e: $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (standard -> experimental) e2e tests on a local kind cluster
380+
test-upgrade-st2ex-e2e: experimental/install.sh $(TEST_UPGRADE_E2E_TASKS) #HELP Run upgrade (standard -> experimental) e2e tests on a local kind cluster
375381

376382
.PHONY: test-st2ex-e2e
377-
test-st2ex-e2e: SOURCE_MANIFEST := $(STANDARD_MANIFEST)
378-
test-st2ex-e2e: RELEASE_INSTALL := $(STANDARD_RELEASE_INSTALL)
383+
test-st2ex-e2e: RELEASE_INSTALL := $(ROOT_DIR)/standard-install.sh
384+
test-st2ex-e2e: RELEASE_UPGRADE := $(ROOT_DIR)/experimental-install.sh
379385
test-st2ex-e2e: KIND_CLUSTER_NAME := operator-controller-st2ex-e2e
380386
test-st2ex-e2e: export MANIFEST := $(STANDARD_RELEASE_MANIFEST)
381387
test-st2ex-e2e: export TEST_CLUSTER_CATALOG_NAME := test-catalog
382388
test-st2ex-e2e: export TEST_CLUSTER_EXTENSION_NAME := test-package
383-
test-st2ex-e2e: run-internal image-registry pre-upgrade-setup kind-deploy-experimental post-upgrade-checks kind-clean #HELP Run swichover (standard -> experimental) e2e tests on a local kind cluster
389+
test-st2ex-e2e: experimental/install.sh standard/install.sh $(TEST_UPGRADE_E2E_TASKS) #HELP Run swichover (standard -> experimental) e2e tests on a local kind cluster
384390

385391
.PHONY: e2e-coverage
386392
e2e-coverage:

test/e2e/steps/hooks.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ type scenarioContext struct {
3030
id string
3131
namespace string
3232
clusterExtensionName string
33+
clusterCatalogName string
3334
removedResources []unstructured.Unstructured
3435
backGroundCmds []*exec.Cmd
3536
metricsResponse map[string]string
37+
leaderPods map[string]string // component name -> leader pod name
3638

3739
extensionObjects []client.Object
3840
}
@@ -87,30 +89,37 @@ func RegisterHooks(sc *godog.ScenarioContext) {
8789
sc.After(ScenarioCleanup)
8890
}
8991

90-
func BeforeSuite() {
91-
if devMode {
92-
logger = textlogger.NewLogger(textlogger.NewConfig(textlogger.Verbosity(1)))
93-
} else {
94-
logger = textlogger.NewLogger(textlogger.NewConfig())
95-
}
96-
92+
func detectOLMDeployment() (*appsv1.Deployment, error) {
9793
raw, err := k8sClient("get", "deployments", "-A", "-l", "app.kubernetes.io/part-of=olm", "-o", "jsonpath={.items}")
9894
if err != nil {
99-
panic(fmt.Errorf("failed to get OLM deployments: %v", err))
95+
return nil, err
10096
}
10197
dl := []appsv1.Deployment{}
10298
if err := json.Unmarshal([]byte(raw), &dl); err != nil {
10399
panic(fmt.Errorf("failed to unmarshal OLM deployments: %v", err))
104100
}
105-
var olm *appsv1.Deployment
106101

107102
for _, d := range dl {
108103
if d.Name == olmDeploymentName {
109-
olm = &d
110-
olmNamespace = d.Namespace
111-
break
104+
return &d, nil
112105
}
113106
}
107+
return nil, fmt.Errorf("failed to detect OLM Deployment")
108+
}
109+
110+
func BeforeSuite() {
111+
if devMode {
112+
logger = textlogger.NewLogger(textlogger.NewConfig(textlogger.Verbosity(1)))
113+
} else {
114+
logger = textlogger.NewLogger(textlogger.NewConfig())
115+
}
116+
117+
olm, err := detectOLMDeployment()
118+
if err != nil {
119+
logger.Info("OLM deployments not found; skipping feature gate detection (upgrade scenarios will install OLM in Background)")
120+
return
121+
}
122+
olmNamespace = olm.Namespace
114123

115124
featureGatePattern := regexp.MustCompile(`--feature-gates=([[:alnum:]]+)=(true|false)`)
116125
for _, c := range olm.Spec.Template.Spec.Containers {
@@ -144,6 +153,7 @@ func CreateScenarioContext(ctx context.Context, sc *godog.Scenario) (context.Con
144153
id: sc.Id,
145154
namespace: fmt.Sprintf("ns-%s", sc.Id),
146155
clusterExtensionName: fmt.Sprintf("ce-%s", sc.Id),
156+
leaderPods: make(map[string]string),
147157
}
148158
return context.WithValue(ctx, scenarioContextKey, scCtx), nil
149159
}

test/e2e/steps/steps.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
"os/exec"
1515
"path/filepath"
1616
"reflect"
17+
"runtime"
1718
"strings"
19+
"sync"
1820
"time"
1921

2022
"github.com/cucumber/godog"
@@ -47,9 +49,24 @@ const (
4749
)
4850

4951
var (
50-
olmNamespace = "olmv1-system"
51-
kubeconfigPath string
52-
k8sCli string
52+
olmNamespace = "olmv1-system"
53+
kubeconfigPath string
54+
k8sCli string
55+
deployImageRegistry = sync.OnceValue(func() error {
56+
if os.Getenv("KIND_CLUSTER_NAME") == "" {
57+
return nil
58+
}
59+
cmd := exec.Command("bash", "-c", "make image-registry")
60+
dir, _ := os.LookupEnv("ROOT_DIR")
61+
if dir == "" {
62+
return fmt.Errorf("ROOT_DIR environment variable not set")
63+
}
64+
cmd.Dir = dir
65+
cmd.Env = append(os.Environ(), fmt.Sprintf("KUBECONFIG=%s", kubeconfigPath))
66+
cmd.Stdout = os.Stdout
67+
cmd.Stderr = os.Stderr
68+
return cmd.Run()
69+
})
5370
)
5471

5572
func RegisterSteps(sc *godog.ScenarioContext) {
@@ -89,6 +106,7 @@ func RegisterSteps(sc *godog.ScenarioContext) {
89106
sc.Step(`^(?i)resource "([^"]+)" is eventually restored$`, ResourceRestored)
90107
sc.Step(`^(?i)resource "([^"]+)" matches$`, ResourceMatches)
91108

109+
sc.Step(`^(?i)ServiceAccount "([^"]*)" with needed permissions is available in "([^"]*)" namespace$`, ServiceAccountWithNeededPermissionsIsAvailableInGivenNamespace)
92110
sc.Step(`^(?i)ServiceAccount "([^"]*)" with needed permissions is available in test namespace$`, ServiceAccountWithNeededPermissionsIsAvailableInNamespace)
93111
sc.Step(`^(?i)ServiceAccount "([^"]*)" with needed permissions is available in \${TEST_NAMESPACE}$`, ServiceAccountWithNeededPermissionsIsAvailableInNamespace)
94112
sc.Step(`^(?i)ServiceAccount "([^"]*)" is available in \${TEST_NAMESPACE}$`, ServiceAccountIsAvailableInNamespace)
@@ -108,6 +126,14 @@ func RegisterSteps(sc *godog.ScenarioContext) {
108126
sc.Step(`^(?i)Prometheus metrics are returned in the response$`, PrometheusMetricsAreReturned)
109127

110128
sc.Step(`^(?i)min value for (ClusterExtension|ClusterExtensionRevision) ((?:\.[a-zA-Z]+)+) is set to (\d+)$`, SetCRDFieldMinValue)
129+
130+
// Upgrade-specific steps
131+
sc.Step(`^(?i)the latest stable OLM release is installed$`, LatestStableOLMReleaseIsInstalled)
132+
sc.Step(`^(?i)OLM is upgraded$`, OLMIsUpgraded)
133+
sc.Step(`^(?i)(catalogd|operator-controller) is ready to reconcile resources$`, ComponentIsReadyToReconcile)
134+
sc.Step(`^(?i)all (ClusterCatalog|ClusterExtension) resources are reconciled$`, AllResourcesAreReconciled)
135+
sc.Step(`^(?i)(ClusterCatalog|ClusterExtension) is reconciled$`, ResourceTypeIsReconciled)
136+
sc.Step(`^(?i)ClusterCatalog reports ([[:alnum:]]+) as ([[:alnum:]]+) with Reason ([[:alnum:]]+)$`, ClusterCatalogReportsCondition)
111137
}
112138

113139
func init() {
@@ -768,7 +794,8 @@ func applyServiceAccount(ctx context.Context, serviceAccount string) error {
768794
"SERVICEACCOUNT_NAME": serviceAccount,
769795
})
770796

771-
yaml, err := templateYaml(filepath.Join("steps", "testdata", "serviceaccount-template.yaml"), vars)
797+
_, thisFile, _, _ := runtime.Caller(0)
798+
yaml, err := templateYaml(filepath.Join(filepath.Dir(thisFile), "testdata", "serviceaccount-template.yaml"), vars)
772799
if err != nil {
773800
return fmt.Errorf("failed to template ServiceAccount yaml: %v", err)
774801
}
@@ -795,7 +822,8 @@ func applyPermissionsToServiceAccount(ctx context.Context, serviceAccount, rbacT
795822
"CLUSTEREXTENSION_NAME": sc.clusterExtensionName,
796823
}, keyValue...)
797824

798-
yaml, err := templateYaml(filepath.Join("steps", "testdata", rbacTemplate), vars)
825+
_, thisFile, _, _ := runtime.Caller(0)
826+
yaml, err := templateYaml(filepath.Join(filepath.Dir(thisFile), "testdata", rbacTemplate), vars)
799827
if err != nil {
800828
return fmt.Errorf("failed to template RBAC yaml: %v", err)
801829
}
@@ -814,6 +842,13 @@ func ServiceAccountIsAvailableInNamespace(ctx context.Context, serviceAccount st
814842
return applyServiceAccount(ctx, serviceAccount)
815843
}
816844

845+
// ServiceAccountWithNeededPermissionsIsAvailableInNamespace creates a ServiceAccount and applies standard RBAC permissions.
846+
func ServiceAccountWithNeededPermissionsIsAvailableInGivenNamespace(ctx context.Context, serviceAccount string, ns string) error {
847+
sc := scenarioCtx(ctx)
848+
sc.namespace = ns
849+
return applyPermissionsToServiceAccount(ctx, serviceAccount, "rbac-template.yaml")
850+
}
851+
817852
// ServiceAccountWithNeededPermissionsIsAvailableInNamespace creates a ServiceAccount and applies standard RBAC permissions.
818853
func ServiceAccountWithNeededPermissionsIsAvailableInNamespace(ctx context.Context, serviceAccount string) error {
819854
return applyPermissionsToServiceAccount(ctx, serviceAccount, "rbac-template.yaml")
@@ -972,12 +1007,19 @@ func CatalogIsUpdatedToVersion(name, version string) error {
9721007

9731008
// CatalogServesBundles applies the ClusterCatalog YAML template to create a catalog that serves bundles.
9741009
func CatalogServesBundles(ctx context.Context, catalogName string) error {
975-
yamlContent, err := os.ReadFile(filepath.Join("steps", "testdata", fmt.Sprintf("%s-catalog-template.yaml", catalogName)))
1010+
if err := deployImageRegistry(); err != nil {
1011+
return err
1012+
}
1013+
sc := scenarioCtx(ctx)
1014+
sc.clusterCatalogName = fmt.Sprintf("%s-catalog", catalogName)
1015+
1016+
_, thisFile, _, _ := runtime.Caller(0)
1017+
yamlContent, err := os.ReadFile(filepath.Join(filepath.Dir(thisFile), "testdata", fmt.Sprintf("%s-catalog-template.yaml", catalogName)))
9761018
if err != nil {
9771019
return fmt.Errorf("failed to read catalog yaml: %v", err)
9781020
}
9791021

980-
_, err = k8scliWithInput(substituteScenarioVars(string(yamlContent), scenarioCtx(ctx)), "apply", "-f", "-")
1022+
_, err = k8scliWithInput(substituteScenarioVars(string(yamlContent), sc), "apply", "-f", "-")
9811023
if err != nil {
9821024
return fmt.Errorf("failed to apply catalog: %v", err)
9831025
}

test/e2e/steps/testdata/rbac-template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ metadata:
1111
rules:
1212
- apiGroups: [olm.operatorframework.io]
1313
resources: [clusterextensions, clusterextensions/finalizers]
14-
resourceNames: ["${CLUSTEREXTENSION_NAME}"]
14+
resourceNames: ["${CLUSTEREXTENSION_NAME}", "upgrade-ce"]
1515
verbs: [update]
1616
# Allow ClusterExtensionRevisions to set blockOwnerDeletion ownerReferences
1717
- apiGroups: [olm.operatorframework.io]

0 commit comments

Comments
 (0)