Skip to content

Commit 69f5e82

Browse files
test: add e2e tests for workload resilience when catalog is deleted
Assisted-by: Cursor
1 parent b08a054 commit 69f5e82

2 files changed

Lines changed: 233 additions & 4 deletions

File tree

test/e2e/features/recover.feature

Lines changed: 221 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ Feature: Recover cluster extension from errors that might occur during its lifet
33
Background:
44
Given OLM is available
55
And ClusterCatalog "test" serves bundles
6+
And ServiceAccount "olm-sa" with needed permissions is available in ${TEST_NAMESPACE}
67

78

89
Scenario: Restore removed resource
9-
Given ServiceAccount "olm-sa" with needed permissions is available in ${TEST_NAMESPACE}
10-
And ClusterExtension is applied
10+
Given ClusterExtension is applied
1111
"""
1212
apiVersion: olm.operatorframework.io/v1
1313
kind: ClusterExtension
@@ -55,8 +55,7 @@ Feature: Recover cluster extension from errors that might occur during its lifet
5555
And ClusterExtension reports Progressing as True with Reason Succeeded
5656

5757
Scenario: Install ClusterExtension after conflicting resource is removed
58-
Given ServiceAccount "olm-sa" with needed permissions is available in ${TEST_NAMESPACE}
59-
And resource is applied
58+
Given resource is applied
6059
"""
6160
apiVersion: apps/v1
6261
kind: Deployment
@@ -115,3 +114,221 @@ Feature: Recover cluster extension from errors that might occur during its lifet
115114
Then ClusterExtension is available
116115
And ClusterExtension reports Progressing as True with Reason Succeeded
117116
And ClusterExtension reports Installed as True
117+
118+
# CATALOG DELETION RESILIENCE SCENARIOS
119+
120+
Scenario: Extension continues running after catalog deletion
121+
Given ClusterExtension is applied
122+
"""
123+
apiVersion: olm.operatorframework.io/v1
124+
kind: ClusterExtension
125+
metadata:
126+
name: ${NAME}
127+
spec:
128+
namespace: ${TEST_NAMESPACE}
129+
serviceAccount:
130+
name: olm-sa
131+
source:
132+
sourceType: Catalog
133+
catalog:
134+
packageName: test
135+
selector:
136+
matchLabels:
137+
"olm.operatorframework.io/metadata.name": test-catalog
138+
"""
139+
And ClusterExtension is rolled out
140+
And ClusterExtension is available
141+
And resource "deployment/test-operator" is available
142+
And resource "configmap/test-configmap" is available
143+
And ClusterCatalog "test" is deleted
144+
# Catalog deletion triggers automatic reconciliation via ClusterCatalog watch
145+
# Wait for reconciliation to complete by checking the status condition
146+
When ClusterExtension reports Installed as True
147+
Then resource "deployment/test-operator" is available
148+
And resource "configmap/test-configmap" is available
149+
150+
Scenario: Resources are restored after catalog deletion
151+
Given ClusterExtension is applied
152+
"""
153+
apiVersion: olm.operatorframework.io/v1
154+
kind: ClusterExtension
155+
metadata:
156+
name: ${NAME}
157+
spec:
158+
namespace: ${TEST_NAMESPACE}
159+
serviceAccount:
160+
name: olm-sa
161+
source:
162+
sourceType: Catalog
163+
catalog:
164+
packageName: test
165+
selector:
166+
matchLabels:
167+
"olm.operatorframework.io/metadata.name": test-catalog
168+
"""
169+
And ClusterExtension is rolled out
170+
And ClusterExtension is available
171+
And resource "configmap/test-configmap" exists
172+
And ClusterCatalog "test" is deleted
173+
When resource "configmap/test-configmap" is removed
174+
Then resource "configmap/test-configmap" is eventually restored
175+
176+
Scenario: Config changes are allowed even when the catalog does not exist anymore
177+
Given ClusterExtension is applied
178+
"""
179+
apiVersion: olm.operatorframework.io/v1
180+
kind: ClusterExtension
181+
metadata:
182+
name: ${NAME}
183+
spec:
184+
namespace: ${TEST_NAMESPACE}
185+
serviceAccount:
186+
name: olm-sa
187+
source:
188+
sourceType: Catalog
189+
catalog:
190+
packageName: test
191+
selector:
192+
matchLabels:
193+
"olm.operatorframework.io/metadata.name": test-catalog
194+
"""
195+
And ClusterExtension is rolled out
196+
And ClusterExtension is available
197+
And ClusterCatalog "test" is deleted
198+
When ClusterExtension is updated to add preflight config
199+
"""
200+
apiVersion: olm.operatorframework.io/v1
201+
kind: ClusterExtension
202+
metadata:
203+
name: ${NAME}
204+
spec:
205+
namespace: ${TEST_NAMESPACE}
206+
serviceAccount:
207+
name: olm-sa
208+
install:
209+
preflight:
210+
crdUpgradeSafety:
211+
enforcement: None
212+
source:
213+
sourceType: Catalog
214+
catalog:
215+
packageName: test
216+
selector:
217+
matchLabels:
218+
"olm.operatorframework.io/metadata.name": test-catalog
219+
"""
220+
# Wait for reconciliation of the updated spec (config change should succeed without catalog)
221+
And ClusterExtension is available
222+
Then ClusterExtension reports Installed as True
223+
224+
Scenario: Version upgrade does not proceed when catalog does not exist
225+
Given ClusterExtension is applied
226+
"""
227+
apiVersion: olm.operatorframework.io/v1
228+
kind: ClusterExtension
229+
metadata:
230+
name: ${NAME}
231+
spec:
232+
namespace: ${TEST_NAMESPACE}
233+
serviceAccount:
234+
name: olm-sa
235+
source:
236+
sourceType: Catalog
237+
catalog:
238+
packageName: test
239+
version: "1.0.0"
240+
selector:
241+
matchLabels:
242+
"olm.operatorframework.io/metadata.name": test-catalog
243+
"""
244+
And ClusterExtension is rolled out
245+
And ClusterExtension is available
246+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
247+
And ClusterCatalog "test" is deleted
248+
When ClusterExtension is updated to change version
249+
"""
250+
apiVersion: olm.operatorframework.io/v1
251+
kind: ClusterExtension
252+
metadata:
253+
name: ${NAME}
254+
spec:
255+
namespace: ${TEST_NAMESPACE}
256+
serviceAccount:
257+
name: olm-sa
258+
source:
259+
sourceType: Catalog
260+
catalog:
261+
packageName: test
262+
version: "1.0.1"
263+
selector:
264+
matchLabels:
265+
"olm.operatorframework.io/metadata.name": test-catalog
266+
"""
267+
# Wait for reconciliation after the version change request
268+
And ClusterExtension reports Progressing as True with Reason Retrying
269+
# Verify upgrade did not proceed: version remains at 1.0.0 (not 1.0.1)
270+
Then bundle "test-operator.1.0.0" is installed in version "1.0.0"
271+
And ClusterExtension reports Installed as True
272+
# Note: Retrying status means controller will auto-upgrade when catalog becomes available
273+
274+
@BoxcutterRuntime
275+
Scenario: Extension with revisions continues running after catalog deletion
276+
Given ClusterExtension is applied
277+
"""
278+
apiVersion: olm.operatorframework.io/v1
279+
kind: ClusterExtension
280+
metadata:
281+
name: ${NAME}
282+
spec:
283+
namespace: ${TEST_NAMESPACE}
284+
serviceAccount:
285+
name: olm-sa
286+
source:
287+
sourceType: Catalog
288+
catalog:
289+
packageName: test
290+
selector:
291+
matchLabels:
292+
"olm.operatorframework.io/metadata.name": test-catalog
293+
"""
294+
And ClusterExtension is rolled out
295+
And ClusterExtension is available
296+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
297+
And resource "deployment/test-operator" is available
298+
And ClusterCatalog "test" is deleted
299+
# Wait for reconciliation to complete after catalog deletion
300+
When ClusterExtension reports Installed as True
301+
Then resource "deployment/test-operator" is available
302+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
303+
304+
@BoxcutterRuntime
305+
Scenario: Revision remains available after catalog deletion
306+
Given ClusterExtension is applied
307+
"""
308+
apiVersion: olm.operatorframework.io/v1
309+
kind: ClusterExtension
310+
metadata:
311+
name: ${NAME}
312+
spec:
313+
namespace: ${TEST_NAMESPACE}
314+
serviceAccount:
315+
name: olm-sa
316+
source:
317+
sourceType: Catalog
318+
catalog:
319+
packageName: test
320+
version: "1.2.0"
321+
selector:
322+
matchLabels:
323+
"olm.operatorframework.io/metadata.name": test-catalog
324+
"""
325+
And ClusterExtension is rolled out
326+
And ClusterExtension is available
327+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
328+
And ClusterCatalog "test" is deleted
329+
# Catalog deletion should NOT affect workload availability
330+
# Wait for reconciliation to complete after catalog deletion
331+
When ClusterExtension reports Installed as True
332+
Then ClusterExtension is available
333+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
334+
And resource "deployment/test-operator" is available

test/e2e/steps/steps.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func RegisterSteps(sc *godog.ScenarioContext) {
8585
sc.Step(`^(?i)ClusterCatalog "([^"]+)" serves bundles$`, CatalogServesBundles)
8686
sc.Step(`^"([^"]+)" catalog image version "([^"]+)" is also tagged as "([^"]+)"$`, TagCatalogImage)
8787
sc.Step(`^(?i)ClusterCatalog "([^"]+)" image version "([^"]+)" is also tagged as "([^"]+)"$`, TagCatalogImage)
88+
sc.Step(`^(?i)ClusterCatalog "([^"]+)" is deleted$`, CatalogIsDeleted)
8889

8990
sc.Step(`^(?i)operator "([^"]+)" target namespace is "([^"]+)"$`, OperatorTargetNamespace)
9091
sc.Step(`^(?i)Prometheus metrics are returned in the response$`, PrometheusMetricsAreReturned)
@@ -664,6 +665,17 @@ func TagCatalogImage(name, oldTag, newTag string) error {
664665
return crane.Tag(imageRef, newTag, crane.Insecure)
665666
}
666667

668+
func CatalogIsDeleted(ctx context.Context, catalogName string) error {
669+
catalogFullName := fmt.Sprintf("%s-catalog", catalogName)
670+
// Using --wait=true makes kubectl wait for the resource to be fully deleted,
671+
// eliminating the need for manual polling
672+
_, err := k8sClient("delete", "clustercatalog", catalogFullName, "--ignore-not-found=true", "--wait=true")
673+
if err != nil {
674+
return fmt.Errorf("failed to delete catalog: %v", err)
675+
}
676+
return nil
677+
}
678+
667679
func PrometheusMetricsAreReturned(ctx context.Context) error {
668680
sc := scenarioCtx(ctx)
669681
for podName, mr := range sc.metricsResponse {

0 commit comments

Comments
 (0)