Skip to content

Commit 6a9ffdd

Browse files
test: add e2e tests for workload resilience when catalog is deleted
1 parent b08a054 commit 6a9ffdd

2 files changed

Lines changed: 345 additions & 0 deletions

File tree

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
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+
And ClusterCatalog "test" is deleted
37+
# Catalog deletion triggers automatic reconciliation via ClusterCatalog watch
38+
# Wait for reconciliation to complete by checking the status condition
39+
When ClusterExtension reports Installed as True
40+
Then resource "deployment/test-operator" is available
41+
And resource "configmap/test-configmap" is available
42+
43+
Scenario: Resources are restored after catalog deletion
44+
Given ClusterExtension is applied
45+
"""
46+
apiVersion: olm.operatorframework.io/v1
47+
kind: ClusterExtension
48+
metadata:
49+
name: ${NAME}
50+
spec:
51+
namespace: ${TEST_NAMESPACE}
52+
serviceAccount:
53+
name: olm-sa
54+
source:
55+
sourceType: Catalog
56+
catalog:
57+
packageName: test
58+
selector:
59+
matchLabels:
60+
"olm.operatorframework.io/metadata.name": test-catalog
61+
"""
62+
And ClusterExtension is rolled out
63+
And ClusterExtension is available
64+
And resource "configmap/test-configmap" exists
65+
And ClusterCatalog "test" is deleted
66+
When resource "configmap/test-configmap" is removed
67+
Then resource "configmap/test-configmap" is eventually restored
68+
69+
Scenario: Config changes are allowed even when the catalog does not exist anymore
70+
Given ClusterExtension is applied
71+
"""
72+
apiVersion: olm.operatorframework.io/v1
73+
kind: ClusterExtension
74+
metadata:
75+
name: ${NAME}
76+
spec:
77+
namespace: ${TEST_NAMESPACE}
78+
serviceAccount:
79+
name: olm-sa
80+
source:
81+
sourceType: Catalog
82+
catalog:
83+
packageName: test
84+
selector:
85+
matchLabels:
86+
"olm.operatorframework.io/metadata.name": test-catalog
87+
"""
88+
And ClusterExtension is rolled out
89+
And ClusterExtension is available
90+
And ClusterCatalog "test" is deleted
91+
When ClusterExtension is updated to add preflight config
92+
"""
93+
apiVersion: olm.operatorframework.io/v1
94+
kind: ClusterExtension
95+
metadata:
96+
name: ${NAME}
97+
spec:
98+
namespace: ${TEST_NAMESPACE}
99+
serviceAccount:
100+
name: olm-sa
101+
install:
102+
preflight:
103+
crdUpgradeSafety:
104+
enforcement: None
105+
source:
106+
sourceType: Catalog
107+
catalog:
108+
packageName: test
109+
selector:
110+
matchLabels:
111+
"olm.operatorframework.io/metadata.name": test-catalog
112+
"""
113+
Then ClusterExtension reports Installed as True
114+
115+
Scenario: Version upgrade blocked when catalog does not exist
116+
Given ClusterExtension is applied
117+
"""
118+
apiVersion: olm.operatorframework.io/v1
119+
kind: ClusterExtension
120+
metadata:
121+
name: ${NAME}
122+
spec:
123+
namespace: ${TEST_NAMESPACE}
124+
serviceAccount:
125+
name: olm-sa
126+
source:
127+
sourceType: Catalog
128+
catalog:
129+
packageName: test
130+
version: "1.0.0"
131+
selector:
132+
matchLabels:
133+
"olm.operatorframework.io/metadata.name": test-catalog
134+
"""
135+
And ClusterExtension is rolled out
136+
And ClusterExtension is available
137+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
138+
When ClusterCatalog "test" is deleted
139+
And ClusterExtension is updated to change version
140+
"""
141+
apiVersion: olm.operatorframework.io/v1
142+
kind: ClusterExtension
143+
metadata:
144+
name: ${NAME}
145+
spec:
146+
namespace: ${TEST_NAMESPACE}
147+
serviceAccount:
148+
name: olm-sa
149+
source:
150+
sourceType: Catalog
151+
catalog:
152+
packageName: test
153+
version: "1.0.1"
154+
selector:
155+
matchLabels:
156+
"olm.operatorframework.io/metadata.name": test-catalog
157+
"""
158+
Then ClusterExtension reports Progressing as True with Reason Retrying
159+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
160+
161+
# BOXCUTTER RUNTIME (EXPERIMENTAL) TESTS
162+
163+
@BoxcutterRuntime
164+
Scenario: Extension with revisions continues running after catalog deletion
165+
Given ClusterExtension is applied
166+
"""
167+
apiVersion: olm.operatorframework.io/v1
168+
kind: ClusterExtension
169+
metadata:
170+
name: ${NAME}
171+
spec:
172+
namespace: ${TEST_NAMESPACE}
173+
serviceAccount:
174+
name: olm-sa
175+
source:
176+
sourceType: Catalog
177+
catalog:
178+
packageName: test
179+
selector:
180+
matchLabels:
181+
"olm.operatorframework.io/metadata.name": test-catalog
182+
"""
183+
And ClusterExtension is rolled out
184+
And ClusterExtension is available
185+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
186+
And resource "deployment/test-operator" is available
187+
When ClusterCatalog "test" is deleted
188+
Then resource "deployment/test-operator" is available
189+
And ClusterExtension reports Installed as True
190+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
191+
192+
@BoxcutterRuntime
193+
Scenario: Revision resources are restored after catalog deletion
194+
Given ClusterExtension is applied
195+
"""
196+
apiVersion: olm.operatorframework.io/v1
197+
kind: ClusterExtension
198+
metadata:
199+
name: ${NAME}
200+
spec:
201+
namespace: ${TEST_NAMESPACE}
202+
serviceAccount:
203+
name: olm-sa
204+
source:
205+
sourceType: Catalog
206+
catalog:
207+
packageName: test
208+
selector:
209+
matchLabels:
210+
"olm.operatorframework.io/metadata.name": test-catalog
211+
"""
212+
And ClusterExtension is rolled out
213+
And ClusterExtension is available
214+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
215+
And resource "configmap/test-configmap" exists
216+
When ClusterCatalog "test" is deleted
217+
And resource "configmap/test-configmap" is removed
218+
Then resource "configmap/test-configmap" is eventually restored
219+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
220+
221+
@BoxcutterRuntime
222+
Scenario: Revision remains available after catalog deletion
223+
Given ClusterExtension is applied
224+
"""
225+
apiVersion: olm.operatorframework.io/v1
226+
kind: ClusterExtension
227+
metadata:
228+
name: ${NAME}
229+
spec:
230+
namespace: ${TEST_NAMESPACE}
231+
serviceAccount:
232+
name: olm-sa
233+
source:
234+
sourceType: Catalog
235+
catalog:
236+
packageName: test
237+
version: "1.2.0"
238+
selector:
239+
matchLabels:
240+
"olm.operatorframework.io/metadata.name": test-catalog
241+
"""
242+
And ClusterExtension is rolled out
243+
And ClusterExtension is available
244+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
245+
And ClusterCatalog "test" is deleted
246+
# Catalog deletion should NOT affect workload availability
247+
# Wait for reconciliation to complete after catalog deletion
248+
When ClusterExtension reports Installed as True
249+
Then ClusterExtension is available
250+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
251+
And resource "deployment/test-operator" is available
252+
253+
@BoxcutterRuntime
254+
Scenario: Version upgrade with revisions blocked without catalog
255+
Given ClusterExtension is applied
256+
"""
257+
apiVersion: olm.operatorframework.io/v1
258+
kind: ClusterExtension
259+
metadata:
260+
name: ${NAME}
261+
spec:
262+
namespace: ${TEST_NAMESPACE}
263+
serviceAccount:
264+
name: olm-sa
265+
source:
266+
sourceType: Catalog
267+
catalog:
268+
packageName: test
269+
version: "1.0.0"
270+
upgradeConstraintPolicy: SelfCertified
271+
selector:
272+
matchLabels:
273+
"olm.operatorframework.io/metadata.name": test-catalog
274+
"""
275+
And ClusterExtension is rolled out
276+
And ClusterExtension is available
277+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
278+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
279+
When ClusterCatalog "test" is deleted
280+
And ClusterExtension is updated to change version
281+
"""
282+
apiVersion: olm.operatorframework.io/v1
283+
kind: ClusterExtension
284+
metadata:
285+
name: ${NAME}
286+
spec:
287+
namespace: ${TEST_NAMESPACE}
288+
serviceAccount:
289+
name: olm-sa
290+
source:
291+
sourceType: Catalog
292+
catalog:
293+
packageName: test
294+
version: "1.2.0"
295+
upgradeConstraintPolicy: SelfCertified
296+
selector:
297+
matchLabels:
298+
"olm.operatorframework.io/metadata.name": test-catalog
299+
"""
300+
Then ClusterExtension reports Progressing as True with Reason Retrying
301+
And bundle "test-operator.1.0.0" is installed in version "1.0.0"
302+
And ClusterExtensionRevision "${NAME}-1" reports Available as True with Reason ProbesSucceeded
303+
304+
@BoxcutterRuntime
305+
Scenario: Multiple revisions remain stable 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.0.0"
321+
upgradeConstraintPolicy: SelfCertified
322+
selector:
323+
matchLabels:
324+
"olm.operatorframework.io/metadata.name": test-catalog
325+
"""
326+
And ClusterExtension is rolled out
327+
And ClusterExtension is available
328+
When ClusterExtension is updated to version "1.0.2"
329+
Then ClusterExtension reports "${NAME}-1, ${NAME}-2" as active revisions
330+
When ClusterCatalog "test" is deleted
331+
Then ClusterExtension reports "${NAME}-1, ${NAME}-2" as active revisions
332+
And ClusterExtensionRevision "${NAME}-2" reports Progressing as True with Reason Succeeded
333+
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)