@@ -351,6 +351,71 @@ func TestClusterExtensionInstallRegistry(t *testing.T) {
351351 }
352352}
353353
354+ func TestClusterExtensionInstallFailsWithoutServiceAccount (t * testing.T ) {
355+ t .Log ("When a cluster extension is installed from a catalog" )
356+ t .Log ("And the ServiceAccount does not exist" )
357+
358+ // Step 1: Setup test environment without creating an SA
359+ clusterExtensionName := fmt .Sprintf ("clusterextension-%s" , rand .String (8 ))
360+
361+ ns , err := createNamespace (context .Background (), clusterExtensionName )
362+ require .NoError (t , err )
363+
364+ extensionCatalog , err := createTestCatalog (context .Background (), testCatalogName , os .Getenv (testCatalogRefEnvVar ))
365+ require .NoError (t , err )
366+
367+ // Important: We do NOT create a ServiceAccount here
368+ defer testCleanup (t , extensionCatalog , nil , nil , ns )
369+ defer utils .CollectTestArtifacts (t , artifactName , c , cfg )
370+
371+ // Step 2: Define the ClusterExtension with a non-existent SA
372+ clusterExtension := & ocv1.ClusterExtension {
373+ ObjectMeta : metav1.ObjectMeta {
374+ Name : clusterExtensionName ,
375+ },
376+ Spec : ocv1.ClusterExtensionSpec {
377+ Source : ocv1.SourceConfig {
378+ SourceType : "Catalog" ,
379+ Catalog : & ocv1.CatalogSource {
380+ PackageName : "test" ,
381+ Selector : & metav1.LabelSelector {
382+ MatchLabels : map [string ]string {"olm.operatorframework.io/metadata.name" : extensionCatalog .Name },
383+ },
384+ },
385+ },
386+ Namespace : ns .Name ,
387+ ServiceAccount : ocv1.ServiceAccountReference {
388+ Name : "non-existent-sa" , // This SA does NOT exist
389+ },
390+ },
391+ }
392+
393+ t .Log ("By creating the ClusterExtension resource without a ServiceAccount" )
394+ require .NoError (t , c .Create (context .Background (), clusterExtension ))
395+
396+ // Step 3: Validate failure due to missing ServiceAccount
397+ t .Log ("By eventually reporting an installation failure due to missing ServiceAccount" )
398+ require .EventuallyWithT (t , func (ct * assert.CollectT ) {
399+ assert .NoError (ct , c .Get (context .Background (), types.NamespacedName {Name : clusterExtension .Name }, clusterExtension ))
400+
401+ // Validate that Progressing reports failure
402+ cond := apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1 .TypeProgressing )
403+ if assert .NotNil (ct , cond ) {
404+ assert .Equal (ct , metav1 .ConditionTrue , cond .Status )
405+ assert .Equal (ct , ocv1 .ReasonRetrying , cond .Reason )
406+ assert .Contains (ct , cond .Message , "installation cannot proceed due to missing ServiceAccount" )
407+ }
408+
409+ // Validate that Installed condition is false
410+ installCond := apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1 .TypeInstalled )
411+ if assert .NotNil (ct , installCond ) {
412+ assert .Equal (ct , metav1 .ConditionUnknown , installCond .Status )
413+ assert .Equal (ct , ocv1 .ReasonFailed , installCond .Reason )
414+ assert .Contains (ct , installCond .Message , "service account" )
415+ }
416+ }, pollDuration , pollInterval )
417+ }
418+
354419func TestClusterExtensionInstallRegistryDynamic (t * testing.T ) {
355420 // NOTE: Like 'TestClusterExtensionInstallRegistry', this test also requires extra configuration in /etc/containers/registries.conf
356421 packageName := "dynamic"
0 commit comments