@@ -7,8 +7,11 @@ import (
7
7
"testing"
8
8
9
9
"github.com/stretchr/testify/require"
10
+ "gotest.tools/v3/assert"
10
11
appsv1 "k8s.io/api/apps/v1"
11
12
corev1 "k8s.io/api/core/v1"
13
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
14
+ "k8s.io/apimachinery/pkg/runtime/schema"
12
15
"sigs.k8s.io/controller-runtime/pkg/client"
13
16
14
17
"github.com/operator-framework/api/pkg/operators/v1alpha1"
@@ -267,3 +270,162 @@ func Test_BundleValidatorCallsAllValidationFnsInOrder(t *testing.T) {
267
270
require .NoError (t , val .Validate (nil ))
268
271
require .Equal (t , "hi" , actual )
269
272
}
273
+ func Test_Render_WithNilBundleValidator (t * testing.T ) {
274
+ defer func () {
275
+ if r := recover (); r == nil {
276
+ t .Error ("expected panic when BundleValidator is nil" )
277
+ }
278
+ }()
279
+
280
+ renderer := render.BundleRenderer {}
281
+ _ , _ = renderer .Render (bundle.RegistryV1 {}, "ns" )
282
+ }
283
+
284
+ func Test_Render_WithNoResourceGenerators (t * testing.T ) {
285
+ renderer := render.BundleRenderer {
286
+ BundleValidator : render.BundleValidator {
287
+ func (_ * bundle.RegistryV1 ) []error { return nil },
288
+ },
289
+ }
290
+
291
+ _ , err := renderer .Render (bundle.RegistryV1 {
292
+ CSV : MakeCSV (WithInstallModeSupportFor (v1alpha1 .InstallModeTypeAllNamespaces )),
293
+ }, "test" , render .WithTargetNamespaces ("test" ), render .WithUniqueNameGenerator (render .DefaultUniqueNameGenerator ))
294
+
295
+ require .NoError (t , err )
296
+ }
297
+
298
+ func Test_Render_ReturnsExactSameObjectReferences (t * testing.T ) {
299
+ obj1 := fakeUnstructured ("Service" , "ns" , "svc" )
300
+ obj2 := fakeUnstructured ("ConfigMap" , "ns" , "cfg" )
301
+
302
+ mockGen := render .ResourceGenerator (func (_ * bundle.RegistryV1 , _ render.Options ) ([]client.Object , error ) {
303
+ return []client.Object {obj1 , obj2 }, nil
304
+ })
305
+
306
+ renderer := render.BundleRenderer {
307
+ BundleValidator : render.BundleValidator {func (_ * bundle.RegistryV1 ) []error { return nil }},
308
+ ResourceGenerators : []render.ResourceGenerator {mockGen },
309
+ }
310
+
311
+ result , err := renderer .Render (bundle.RegistryV1 {
312
+ CSV : MakeCSV (WithInstallModeSupportFor (v1alpha1 .InstallModeTypeAllNamespaces )),
313
+ }, "ns" , render .WithTargetNamespaces ("ns" ), render .WithUniqueNameGenerator (render .DefaultUniqueNameGenerator ))
314
+
315
+ require .NoError (t , err )
316
+ require .Same (t , obj1 , result [0 ])
317
+ require .Same (t , obj2 , result [1 ])
318
+ }
319
+
320
+ // Test_Render_ValidatesOutputForAllInstallModes ensures that the BundleRenderer
321
+ // correctly generates and returns the exact list of client.Objects produced by the
322
+ // ResourceGenerators, across all supported install modes (AllNamespaces, SingleNamespace, OwnNamespace).
323
+ func Test_Render_ValidatesOutputForAllInstallModes (t * testing.T ) {
324
+ testCases := []struct {
325
+ name string
326
+ installNamespace string
327
+ watchNamespace string
328
+ installModes []v1alpha1.InstallMode
329
+ expectedNS string
330
+ }{
331
+ {
332
+ name : "AllNamespaces" ,
333
+ installNamespace : "mock-system" ,
334
+ watchNamespace : "" ,
335
+ installModes : []v1alpha1.InstallMode {
336
+ {Type : v1alpha1 .InstallModeTypeAllNamespaces , Supported : true },
337
+ },
338
+ expectedNS : "mock-system" ,
339
+ },
340
+ {
341
+ name : "SingleNamespace" ,
342
+ installNamespace : "mock-system" ,
343
+ watchNamespace : "mock-watch" ,
344
+ installModes : []v1alpha1.InstallMode {
345
+ {Type : v1alpha1 .InstallModeTypeSingleNamespace , Supported : true },
346
+ },
347
+ expectedNS : "mock-watch" ,
348
+ },
349
+ {
350
+ name : "OwnNamespace" ,
351
+ installNamespace : "mock-system" ,
352
+ watchNamespace : "mock-system" ,
353
+ installModes : []v1alpha1.InstallMode {
354
+ {Type : v1alpha1 .InstallModeTypeOwnNamespace , Supported : true },
355
+ },
356
+ expectedNS : "mock-system" ,
357
+ },
358
+ }
359
+
360
+ for _ , tc := range testCases {
361
+ t .Run (tc .name , func (t * testing.T ) {
362
+ // Given the mocks
363
+ expectedObjects := []client.Object {
364
+ fakeUnstructured ("ClusterRole" , "" , "mock-operator.v0-role" ),
365
+ fakeUnstructured ("ClusterRoleBinding" , "" , "mock-operator.v0-binding" ),
366
+ fakeUnstructured ("ConfigMap" , tc .expectedNS , "mock-operator-manager-config" ),
367
+ fakeUnstructured ("CustomResourceDefinition" , "" , "mocks.argoproj.io" ),
368
+ fakeUnstructured ("Deployment" , tc .expectedNS , "mock-operator-controller-manager" ),
369
+ fakeUnstructured ("Service" , tc .expectedNS , "mock-operator-controller-manager-metrics-service" ),
370
+ fakeUnstructured ("ServiceAccount" , tc .expectedNS , "mock-operator-controller-manager" ),
371
+ }
372
+
373
+ mockGen := render .ResourceGenerator (func (_ * bundle.RegistryV1 , _ render.Options ) ([]client.Object , error ) {
374
+ return expectedObjects , nil
375
+ })
376
+
377
+ mockBundle := bundle.RegistryV1 {
378
+ CSV : v1alpha1.ClusterServiceVersion {
379
+ Spec : v1alpha1.ClusterServiceVersionSpec {
380
+ InstallModes : tc .installModes ,
381
+ },
382
+ },
383
+ }
384
+
385
+ renderer := render.BundleRenderer {
386
+ BundleValidator : render.BundleValidator {
387
+ func (_ * bundle.RegistryV1 ) []error { return nil },
388
+ },
389
+ ResourceGenerators : []render.ResourceGenerator {mockGen },
390
+ }
391
+
392
+ opts := []render.Option {
393
+ render .WithTargetNamespaces (tc .watchNamespace ),
394
+ render .WithUniqueNameGenerator (render .DefaultUniqueNameGenerator ),
395
+ }
396
+
397
+ // When we call:
398
+ objs , err := renderer .Render (mockBundle , tc .installNamespace , opts ... )
399
+
400
+ // We expected have no error and ensure that the objects
401
+ // returned match with the resource generator's output.
402
+ require .NoError (t , err )
403
+ require .Len (t , objs , len (expectedObjects ))
404
+
405
+ for i , obj := range objs {
406
+ exp := expectedObjects [i ]
407
+ assert .Equal (t , exp .GetObjectKind ().GroupVersionKind ().Kind , obj .GetObjectKind ().GroupVersionKind ().Kind )
408
+ assert .Equal (t , exp .GetName (), obj .GetName (), "unexpected name at index %d" , i )
409
+ assert .Equal (t , exp .GetNamespace (), obj .GetNamespace (), "unexpected namespace at index %d" , i )
410
+ }
411
+ })
412
+ }
413
+ }
414
+
415
+ func fakeUnstructured (kind , namespace , name string ) client.Object {
416
+ obj := & unstructured.Unstructured {}
417
+ group := ""
418
+ version := "v1"
419
+ if kind == "CustomResourceDefinition" {
420
+ group = "apiextensions.k8s.io"
421
+ version = "v1"
422
+ }
423
+ obj .SetGroupVersionKind (schema.GroupVersionKind {
424
+ Group : group ,
425
+ Version : version ,
426
+ Kind : kind ,
427
+ })
428
+ obj .SetNamespace (namespace )
429
+ obj .SetName (name )
430
+ return obj
431
+ }
0 commit comments