Skip to content

Commit 9909590

Browse files
Add tests for config error handling
Tests check: - Config errors are permanent (not retried) - Status shows "Failed" when config is wrong - Namespace names are validated - AllNamespaces operators reject watchNamespace config Includes both unit tests and end-to-end tests. Assisted-by: Claude <noreply@anthropic.com>
1 parent 6e7bdf9 commit 9909590

2 files changed

Lines changed: 162 additions & 3 deletions

File tree

internal/operator-controller/applier/provider_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"sigs.k8s.io/controller-runtime/pkg/client"
14+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
1415

1516
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1617

@@ -100,6 +101,74 @@ func Test_RegistryV1ManifestProvider_Integration(t *testing.T) {
100101
require.Contains(t, err.Error(), "invalid ClusterExtension configuration")
101102
})
102103

104+
t.Run("returns terminal error for invalid config", func(t *testing.T) {
105+
provider := applier.RegistryV1ManifestProvider{
106+
BundleRenderer: render.BundleRenderer{
107+
ResourceGenerators: []render.ResourceGenerator{
108+
func(rv1 *bundle.RegistryV1, opts render.Options) ([]client.Object, error) {
109+
return nil, nil
110+
},
111+
},
112+
},
113+
IsSingleOwnNamespaceEnabled: true,
114+
}
115+
116+
// Bundle with SingleNamespace install mode requiring watchNamespace config
117+
bundleFS := bundlefs.Builder().WithPackageName("test").
118+
WithCSV(clusterserviceversion.Builder().WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace).Build()).Build()
119+
120+
// ClusterExtension without required config
121+
ext := &ocv1.ClusterExtension{
122+
Spec: ocv1.ClusterExtensionSpec{
123+
Namespace: "install-namespace",
124+
// No config provided - should fail validation
125+
},
126+
}
127+
128+
_, err := provider.Get(bundleFS, ext)
129+
require.Error(t, err)
130+
require.Contains(t, err.Error(), "invalid ClusterExtension configuration")
131+
// Assert that config validation errors are terminal (not retriable)
132+
require.ErrorIs(t, err, reconcile.TerminalError(nil), "config validation errors should be terminal")
133+
})
134+
135+
t.Run("returns terminal error for invalid DNS-1123 watchNamespace", func(t *testing.T) {
136+
provider := applier.RegistryV1ManifestProvider{
137+
BundleRenderer: render.BundleRenderer{
138+
ResourceGenerators: []render.ResourceGenerator{
139+
func(rv1 *bundle.RegistryV1, opts render.Options) ([]client.Object, error) {
140+
return nil, nil
141+
},
142+
},
143+
},
144+
IsSingleOwnNamespaceEnabled: true,
145+
}
146+
147+
// Bundle with SingleNamespace install mode requiring watchNamespace config
148+
bundleFS := bundlefs.Builder().WithPackageName("test").
149+
WithCSV(clusterserviceversion.Builder().WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace).Build()).Build()
150+
151+
// ClusterExtension with invalid DNS-1123 namespace name (trailing dash)
152+
ext := &ocv1.ClusterExtension{
153+
Spec: ocv1.ClusterExtensionSpec{
154+
Namespace: "install-namespace",
155+
Config: &ocv1.ClusterExtensionConfig{
156+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
157+
Inline: &apiextensionsv1.JSON{
158+
Raw: []byte(`{"watchNamespace": "invalid-namespace-"}`),
159+
},
160+
},
161+
},
162+
}
163+
164+
_, err := provider.Get(bundleFS, ext)
165+
require.Error(t, err)
166+
require.Contains(t, err.Error(), "invalid ClusterExtension configuration")
167+
require.Contains(t, err.Error(), "invalid namespace name")
168+
// Assert that DNS-1123 validation errors are also terminal
169+
require.ErrorIs(t, err, reconcile.TerminalError(nil), "DNS-1123 validation errors should be terminal")
170+
})
171+
103172
t.Run("returns rendered manifests", func(t *testing.T) {
104173
provider := applier.RegistryV1ManifestProvider{
105174
BundleRenderer: registryv1.Renderer,

test/e2e/features/install.feature

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,15 @@ Feature: Install ClusterExtension
117117
matchLabels:
118118
"olm.operatorframework.io/metadata.name": test-catalog
119119
"""
120-
And ClusterExtension reports Progressing as True with Reason Retrying and Message:
120+
And ClusterExtension reports Progressing as False with Reason Blocked and Message:
121121
"""
122122
error for resolved bundle "single-namespace-operator.1.0.0" with version "1.0.0":
123123
invalid ClusterExtension configuration: invalid configuration: required field "watchNamespace" is missing
124124
"""
125+
And ClusterExtension reports Installed as False with Reason Failed and Message:
126+
"""
127+
No bundle installed
128+
"""
125129
When ClusterExtension is updated to set config.watchNamespace field
126130
"""
127131
apiVersion: olm.operatorframework.io/v1
@@ -169,12 +173,16 @@ Feature: Install ClusterExtension
169173
matchLabels:
170174
"olm.operatorframework.io/metadata.name": test-catalog
171175
"""
172-
And ClusterExtension reports Progressing as True with Reason Retrying and Message:
176+
And ClusterExtension reports Progressing as False with Reason Blocked and Message:
173177
"""
174178
error for resolved bundle "own-namespace-operator.1.0.0" with version
175179
"1.0.0": invalid ClusterExtension configuration: invalid configuration: required
176180
field "watchNamespace" is missing
177181
"""
182+
And ClusterExtension reports Installed as False with Reason Failed and Message:
183+
"""
184+
No bundle installed
185+
"""
178186
And ClusterExtension is updated to include the watchNamespace configuration
179187
"""
180188
apiVersion: olm.operatorframework.io/v1
@@ -197,14 +205,18 @@ Feature: Install ClusterExtension
197205
matchLabels:
198206
"olm.operatorframework.io/metadata.name": test-catalog
199207
"""
200-
And ClusterExtension reports Progressing as True with Reason Retrying and Message:
208+
And ClusterExtension reports Progressing as False with Reason Blocked and Message:
201209
"""
202210
error for resolved bundle "own-namespace-operator.1.0.0" with version
203211
"1.0.0": invalid ClusterExtension configuration: invalid configuration: 'some-ns'
204212
is not valid ownNamespaceInstallMode: invalid value "some-ns": watchNamespace
205213
must be "${TEST_NAMESPACE}" (the namespace where the operator is installed) because this
206214
operator only supports OwnNamespace install mode
207215
"""
216+
And ClusterExtension reports Installed as False with Reason Failed and Message:
217+
"""
218+
No bundle installed
219+
"""
208220
When ClusterExtension is updated to set watchNamespace to own namespace value
209221
"""
210222
apiVersion: olm.operatorframework.io/v1
@@ -231,6 +243,84 @@ Feature: Install ClusterExtension
231243
And ClusterExtension is available
232244
And operator "own-namespace-operator" target namespace is "${TEST_NAMESPACE}"
233245

246+
@SingleOwnNamespaceInstallSupport
247+
Scenario: Reject invalid watchNamespace format (DNS-1123 violation)
248+
Given ServiceAccount "olm-admin" in test namespace is cluster admin
249+
And resource is applied
250+
"""
251+
apiVersion: v1
252+
kind: Namespace
253+
metadata:
254+
name: single-namespace-operator-target
255+
"""
256+
When ClusterExtension is applied
257+
"""
258+
apiVersion: olm.operatorframework.io/v1
259+
kind: ClusterExtension
260+
metadata:
261+
name: ${NAME}
262+
spec:
263+
namespace: ${TEST_NAMESPACE}
264+
serviceAccount:
265+
name: olm-admin
266+
config:
267+
configType: Inline
268+
inline:
269+
watchNamespace: ${TEST_NAMESPACE}- # trailing '-' violates DNS-1123
270+
source:
271+
sourceType: Catalog
272+
catalog:
273+
packageName: single-namespace-operator
274+
selector:
275+
matchLabels:
276+
"olm.operatorframework.io/metadata.name": test-catalog
277+
"""
278+
Then ClusterExtension reports Progressing as False with Reason Blocked and Message includes:
279+
"""
280+
invalid ClusterExtension configuration: invalid configuration: invalid namespace name
281+
"""
282+
And ClusterExtension reports Installed as False with Reason Failed and Message:
283+
"""
284+
No bundle installed
285+
"""
286+
287+
@SingleOwnNamespaceInstallSupport
288+
@WebhookProviderCertManager
289+
Scenario: Reject watchNamespace for operator that does not support Single/OwnNamespace install modes
290+
Given ServiceAccount "olm-admin" in test namespace is cluster admin
291+
When ClusterExtension is applied
292+
"""
293+
apiVersion: olm.operatorframework.io/v1
294+
kind: ClusterExtension
295+
metadata:
296+
name: ${NAME}
297+
spec:
298+
namespace: ${TEST_NAMESPACE}
299+
serviceAccount:
300+
name: olm-admin
301+
config:
302+
configType: Inline
303+
inline:
304+
watchNamespace: ${TEST_NAMESPACE}
305+
source:
306+
sourceType: Catalog
307+
catalog:
308+
packageName: webhook-operator
309+
selector:
310+
matchLabels:
311+
"olm.operatorframework.io/metadata.name": test-catalog
312+
"""
313+
Then ClusterExtension reports Progressing as False with Reason Blocked and Message includes:
314+
"""
315+
error for resolved bundle "webhook-operator.1.0.0" with version "1.0.0":
316+
invalid ClusterExtension configuration: invalid configuration:
317+
additionalProperties 'watchNamespace' not allowed
318+
"""
319+
And ClusterExtension reports Installed as False with Reason Failed and Message:
320+
"""
321+
No bundle installed
322+
"""
323+
234324
@WebhookProviderCertManager
235325
Scenario: Install operator having webhooks
236326
Given ServiceAccount "olm-admin" in test namespace is cluster admin

0 commit comments

Comments
 (0)