Skip to content

Commit 95f7f9a

Browse files
test: add e2e tests for workload resilience when catalog is deleted
1 parent 9d8fda0 commit 95f7f9a

File tree

2 files changed

+350
-0
lines changed

2 files changed

+350
-0
lines changed
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
Feature: Workload resilience when catalog is deleted
2+
3+
As an OLM user, I want my installed extensions to continue working
4+
even if the catalog they were installed from is deleted.
5+
6+
Background:
7+
Given OLM is available
8+
And ClusterCatalog "test" serves bundles
9+
And ServiceAccount "olm-sa" with needed permissions is available in ${TEST_NAMESPACE}
10+
11+
# STANDARD RUNTIME TESTS
12+
13+
Scenario: Extension continues running after catalog deletion
14+
Given ClusterExtension is applied
15+
"""
16+
apiVersion: olm.operatorframework.io/v1
17+
kind: ClusterExtension
18+
metadata:
19+
name: ${NAME}
20+
spec:
21+
namespace: ${TEST_NAMESPACE}
22+
serviceAccount:
23+
name: olm-sa
24+
source:
25+
sourceType: Catalog
26+
catalog:
27+
packageName: test
28+
selector:
29+
matchLabels:
30+
"olm.operatorframework.io/metadata.name": test-catalog
31+
"""
32+
And ClusterExtension is rolled out
33+
And ClusterExtension is available
34+
And resource "deployment/test-operator" is available
35+
And resource "configmap/test-configmap" is available
36+
When ClusterCatalog "test" is deleted
37+
Then resource "deployment/test-operator" is available
38+
And resource "configmap/test-configmap" is available
39+
And ClusterExtension reports Installed as True
40+
41+
Scenario: Resources are restored after catalog deletion
42+
Given ClusterExtension is applied
43+
"""
44+
apiVersion: olm.operatorframework.io/v1
45+
kind: ClusterExtension
46+
metadata:
47+
name: ${NAME}
48+
spec:
49+
namespace: ${TEST_NAMESPACE}
50+
serviceAccount:
51+
name: olm-sa
52+
source:
53+
sourceType: Catalog
54+
catalog:
55+
packageName: test
56+
selector:
57+
matchLabels:
58+
"olm.operatorframework.io/metadata.name": test-catalog
59+
"""
60+
And ClusterExtension is rolled out
61+
And ClusterExtension is available
62+
And resource "configmap/test-configmap" exists
63+
When ClusterCatalog "test" is deleted
64+
And resource "configmap/test-configmap" is removed
65+
Then resource "configmap/test-configmap" is eventually restored
66+
67+
Scenario: Config changes work without catalog
68+
Given ClusterExtension is applied
69+
"""
70+
apiVersion: olm.operatorframework.io/v1
71+
kind: ClusterExtension
72+
metadata:
73+
name: ${NAME}
74+
spec:
75+
namespace: ${TEST_NAMESPACE}
76+
serviceAccount:
77+
name: olm-sa
78+
source:
79+
sourceType: Catalog
80+
catalog:
81+
packageName: test
82+
selector:
83+
matchLabels:
84+
"olm.operatorframework.io/metadata.name": test-catalog
85+
"""
86+
And ClusterExtension is rolled out
87+
And ClusterExtension is available
88+
When ClusterCatalog "test" is deleted
89+
And ClusterExtension is updated to add preflight config
90+
"""
91+
apiVersion: olm.operatorframework.io/v1
92+
kind: ClusterExtension
93+
metadata:
94+
name: ${NAME}
95+
spec:
96+
namespace: ${TEST_NAMESPACE}
97+
serviceAccount:
98+
name: olm-sa
99+
install:
100+
preflight:
101+
crdUpgradeSafety:
102+
enforcement: None
103+
source:
104+
sourceType: Catalog
105+
catalog:
106+
packageName: test
107+
selector:
108+
matchLabels:
109+
"olm.operatorframework.io/metadata.name": test-catalog
110+
"""
111+
Then ClusterExtension reports Installed as True
112+
113+
Scenario: Version upgrade blocked without catalog
114+
Given ClusterExtension is applied
115+
"""
116+
apiVersion: olm.operatorframework.io/v1
117+
kind: ClusterExtension
118+
metadata:
119+
name: ${NAME}
120+
spec:
121+
namespace: ${TEST_NAMESPACE}
122+
serviceAccount:
123+
name: olm-sa
124+
source:
125+
sourceType: Catalog
126+
catalog:
127+
packageName: test
128+
version: "1.0.0"
129+
selector:
130+
matchLabels:
131+
"olm.operatorframework.io/metadata.name": test-catalog
132+
"""
133+
And ClusterExtension is rolled out
134+
And ClusterExtension is available
135+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
136+
When ClusterCatalog "test" is deleted
137+
And ClusterExtension is updated to change version
138+
"""
139+
apiVersion: olm.operatorframework.io/v1
140+
kind: ClusterExtension
141+
metadata:
142+
name: ${NAME}
143+
spec:
144+
namespace: ${TEST_NAMESPACE}
145+
serviceAccount:
146+
name: olm-sa
147+
source:
148+
sourceType: Catalog
149+
catalog:
150+
packageName: test
151+
version: "1.0.1"
152+
selector:
153+
matchLabels:
154+
"olm.operatorframework.io/metadata.name": test-catalog
155+
"""
156+
Then ClusterExtension reports Progressing as True with Reason Retrying
157+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
158+
159+
# BOXCUTTER RUNTIME (EXPERIMENTAL) TESTS
160+
161+
@BoxcutterRuntime
162+
Scenario: Extension with revisions continues running after catalog deletion
163+
Given ClusterExtension is applied
164+
"""
165+
apiVersion: olm.operatorframework.io/v1
166+
kind: ClusterExtension
167+
metadata:
168+
name: ${NAME}
169+
spec:
170+
namespace: ${TEST_NAMESPACE}
171+
serviceAccount:
172+
name: olm-sa
173+
source:
174+
sourceType: Catalog
175+
catalog:
176+
packageName: test
177+
selector:
178+
matchLabels:
179+
"olm.operatorframework.io/metadata.name": test-catalog
180+
"""
181+
And ClusterExtension is rolled out
182+
And ClusterExtension is available
183+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
184+
And resource "deployment/test-operator" is available
185+
When ClusterCatalog "test" is deleted
186+
Then resource "deployment/test-operator" is available
187+
And ClusterExtension reports Installed as True
188+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
189+
190+
@BoxcutterRuntime
191+
Scenario: Revision resources are restored after catalog deletion
192+
Given ClusterExtension is applied
193+
"""
194+
apiVersion: olm.operatorframework.io/v1
195+
kind: ClusterExtension
196+
metadata:
197+
name: ${NAME}
198+
spec:
199+
namespace: ${TEST_NAMESPACE}
200+
serviceAccount:
201+
name: olm-sa
202+
source:
203+
sourceType: Catalog
204+
catalog:
205+
packageName: test
206+
selector:
207+
matchLabels:
208+
"olm.operatorframework.io/metadata.name": test-catalog
209+
"""
210+
And ClusterExtension is rolled out
211+
And ClusterExtension is available
212+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
213+
And resource "configmap/test-configmap" exists
214+
When ClusterCatalog "test" is deleted
215+
And resource "configmap/test-configmap" is removed
216+
Then resource "configmap/test-configmap" is eventually restored
217+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
218+
219+
@BoxcutterRuntime
220+
Scenario: Revision remains available when workload recovers after catalog deletion
221+
Given ClusterExtension is applied
222+
"""
223+
apiVersion: olm.operatorframework.io/v1
224+
kind: ClusterExtension
225+
metadata:
226+
name: ${NAME}
227+
spec:
228+
namespace: ${TEST_NAMESPACE}
229+
serviceAccount:
230+
name: olm-sa
231+
source:
232+
sourceType: Catalog
233+
catalog:
234+
packageName: test
235+
version: "1.0.2"
236+
selector:
237+
matchLabels:
238+
"olm.operatorframework.io/metadata.name": test-catalog
239+
"""
240+
And ClusterExtension is rolled out
241+
And ClusterExtension is available
242+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
243+
When ClusterCatalog "test" is deleted
244+
And resource "deployment/test-operator" reports as not ready
245+
Then ClusterExtensionRevision "${NAME}-1" reports Available as False with Reason ProbeFailure
246+
When resource "deployment/test-operator" reports as ready
247+
Then ClusterExtension is available
248+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
249+
250+
@BoxcutterRuntime
251+
Scenario: Version upgrade with revisions blocked without catalog
252+
Given ClusterExtension is applied
253+
"""
254+
apiVersion: olm.operatorframework.io/v1
255+
kind: ClusterExtension
256+
metadata:
257+
name: ${NAME}
258+
spec:
259+
namespace: ${TEST_NAMESPACE}
260+
serviceAccount:
261+
name: olm-sa
262+
source:
263+
sourceType: Catalog
264+
catalog:
265+
packageName: test
266+
version: "1.0.0"
267+
upgradeConstraintPolicy: SelfCertified
268+
selector:
269+
matchLabels:
270+
"olm.operatorframework.io/metadata.name": test-catalog
271+
"""
272+
And ClusterExtension is rolled out
273+
And ClusterExtension is available
274+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
275+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
276+
When ClusterCatalog "test" is deleted
277+
And ClusterExtension is updated to change version
278+
"""
279+
apiVersion: olm.operatorframework.io/v1
280+
kind: ClusterExtension
281+
metadata:
282+
name: ${NAME}
283+
spec:
284+
namespace: ${TEST_NAMESPACE}
285+
serviceAccount:
286+
name: olm-sa
287+
source:
288+
sourceType: Catalog
289+
catalog:
290+
packageName: test
291+
version: "1.2.0"
292+
upgradeConstraintPolicy: SelfCertified
293+
selector:
294+
matchLabels:
295+
"olm.operatorframework.io/metadata.name": test-catalog
296+
"""
297+
Then ClusterExtension reports Progressing as True with Reason Retrying
298+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
299+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
300+
301+
@BoxcutterRuntime
302+
Scenario: Multiple revisions remain stable after catalog deletion
303+
Given ClusterExtension is applied
304+
"""
305+
apiVersion: olm.operatorframework.io/v1
306+
kind: ClusterExtension
307+
metadata:
308+
name: ${NAME}
309+
spec:
310+
namespace: ${TEST_NAMESPACE}
311+
serviceAccount:
312+
name: olm-sa
313+
source:
314+
sourceType: Catalog
315+
catalog:
316+
packageName: test
317+
version: "1.0.0"
318+
upgradeConstraintPolicy: SelfCertified
319+
selector:
320+
matchLabels:
321+
"olm.operatorframework.io/metadata.name": test-catalog
322+
"""
323+
And ClusterExtension is rolled out
324+
And ClusterExtension is available
325+
When ClusterExtension is updated to version "1.0.2"
326+
Then ClusterExtension reports "${NAME}-1, ${NAME}-2" as active revisions
327+
When ClusterCatalog "test" is deleted
328+
Then ClusterExtension reports "${NAME}-1, ${NAME}-2" as active revisions
329+
And ClusterExtensionRevision "${NAME}-2" reports Progressing as True with Reason Succeeded
330+
And resource "deployment/test-operator" is available
331+

test/e2e/steps/steps.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ 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)
89+
90+
sc.Step(`^(?i)ClusterExtension is updated to add preflight config$`, ResourceIsApplied)
91+
sc.Step(`^(?i)ClusterExtension is updated to change version$`, ResourceIsApplied)
92+
sc.Step(`^(?i)ClusterExtension is updated to set config\.watchNamespace field$`, ResourceIsApplied)
8893

8994
sc.Step(`^(?i)operator "([^"]+)" target namespace is "([^"]+)"$`, OperatorTargetNamespace)
9095
sc.Step(`^(?i)Prometheus metrics are returned in the response$`, PrometheusMetricsAreReturned)
@@ -664,6 +669,20 @@ func TagCatalogImage(name, oldTag, newTag string) error {
664669
return crane.Tag(imageRef, newTag, crane.Insecure)
665670
}
666671

672+
func CatalogIsDeleted(ctx context.Context, catalogName string) error {
673+
_, err := k8sClient("delete", "clustercatalog", fmt.Sprintf("%s-catalog", catalogName), "--ignore-not-found=true")
674+
if err != nil {
675+
return fmt.Errorf("failed to delete catalog: %v", err)
676+
}
677+
678+
// Wait for catalog to be fully deleted
679+
waitFor(ctx, func() bool {
680+
_, err := k8sClient("get", "clustercatalog", fmt.Sprintf("%s-catalog", catalogName))
681+
return err != nil // Returns true when catalog is not found (deleted)
682+
})
683+
return nil
684+
}
685+
667686
func PrometheusMetricsAreReturned(ctx context.Context) error {
668687
sc := scenarioCtx(ctx)
669688
for podName, mr := range sc.metricsResponse {

0 commit comments

Comments
 (0)