@@ -16,6 +16,7 @@ import (
1616 "k8s.io/utils/pointer"
1717 ctrl "sigs.k8s.io/controller-runtime"
1818 "sigs.k8s.io/controller-runtime/pkg/client"
19+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
1920
2021 operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
2122 "github.com/operator-framework/operator-controller/controllers"
@@ -80,6 +81,38 @@ var _ = Describe("Operator Controller Test", func() {
8081 Expect (cond .Message ).To (Equal (fmt .Sprintf ("package '%s' not found" , pkgName )))
8182 })
8283 })
84+ When ("the operator specifies a version that does not exist" , func () {
85+ var pkgName string
86+ BeforeEach (func () {
87+ By ("initializing cluster state" )
88+ pkgName = fmt .Sprintf ("exists-%s" , rand .String (6 ))
89+ operator = & operatorsv1alpha1.Operator {
90+ ObjectMeta : metav1.ObjectMeta {Name : opKey .Name },
91+ Spec : operatorsv1alpha1.OperatorSpec {
92+ PackageName : pkgName ,
93+ Version : "0.50.0" , // this version of the package does not exist
94+ },
95+ }
96+ err := cl .Create (ctx , operator )
97+ Expect (err ).NotTo (HaveOccurred ())
98+ })
99+ It ("sets resolution failure status" , func () {
100+ By ("running reconcile" )
101+ res , err := reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : opKey })
102+ Expect (res ).To (Equal (ctrl.Result {}))
103+ Expect (err ).To (MatchError (fmt .Sprintf ("package '%s' at version '0.50.0' not found" , pkgName )))
104+
105+ By ("fetching updated operator after reconcile" )
106+ Expect (cl .Get (ctx , opKey , operator )).NotTo (HaveOccurred ())
107+
108+ By ("checking the expected conditions" )
109+ cond := apimeta .FindStatusCondition (operator .Status .Conditions , operatorsv1alpha1 .TypeReady )
110+ Expect (cond ).NotTo (BeNil ())
111+ Expect (cond .Status ).To (Equal (metav1 .ConditionFalse ))
112+ Expect (cond .Reason ).To (Equal (operatorsv1alpha1 .ReasonResolutionFailed ))
113+ Expect (cond .Message ).To (Equal (fmt .Sprintf ("package '%s' at version '0.50.0' not found" , pkgName )))
114+ })
115+ })
83116 When ("the operator specifies a valid available package" , func () {
84117 const pkgName = "prometheus"
85118 BeforeEach (func () {
@@ -568,6 +601,54 @@ var _ = Describe("Operator Controller Test", func() {
568601 Expect (err ).To (Not (HaveOccurred ()))
569602 })
570603 })
604+ When ("an invalid semver is provided that bypasses the regex validation" , func () {
605+ var (
606+ operator * operatorsv1alpha1.Operator
607+ opKey types.NamespacedName
608+ pkgName string
609+ fakeClient client.Client
610+ )
611+ BeforeEach (func () {
612+ opKey = types.NamespacedName {Name : fmt .Sprintf ("operator-validation-test-%s" , rand .String (8 ))}
613+
614+ By ("injecting creating a client with the bad operator CR" )
615+ pkgName = fmt .Sprintf ("exists-%s" , rand .String (6 ))
616+ operator = & operatorsv1alpha1.Operator {
617+ ObjectMeta : metav1.ObjectMeta {Name : opKey .Name },
618+ Spec : operatorsv1alpha1.OperatorSpec {
619+ PackageName : pkgName ,
620+ Version : "1.2.3-123abc_def" , // bad semver that matches the regex on the CR validation
621+ },
622+ }
623+
624+ // this bypasses client/server-side CR validation and allows us to test the reconciler's validation
625+ fakeClient = fake .NewClientBuilder ().WithScheme (sch ).WithObjects (operator ).Build ()
626+
627+ By ("changing the reconciler client to the fake client" )
628+ reconciler .Client = fakeClient
629+ })
630+ AfterEach (func () {
631+ By ("changing the reconciler client back to the real client" )
632+ reconciler .Client = cl
633+ })
634+
635+ It ("should add an invalid spec condition and *not* re-enqueue for reconciliation" , func () {
636+ By ("running reconcile" )
637+ res , err := reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : opKey })
638+ Expect (res ).To (Equal (ctrl.Result {}))
639+ Expect (err ).ToNot (HaveOccurred ())
640+
641+ By ("fetching updated operator after reconcile" )
642+ Expect (fakeClient .Get (ctx , opKey , operator )).NotTo (HaveOccurred ())
643+
644+ By ("checking the expected conditions" )
645+ cond := apimeta .FindStatusCondition (operator .Status .Conditions , operatorsv1alpha1 .TypeReady )
646+ Expect (cond ).NotTo (BeNil ())
647+ Expect (cond .Status ).To (Equal (metav1 .ConditionFalse ))
648+ Expect (cond .Reason ).To (Equal (operatorsv1alpha1 .ReasonInvalidSpec ))
649+ Expect (cond .Message ).To (Equal ("invalid .spec.version: Invalid character(s) found in prerelease \" 123abc_def\" " ))
650+ })
651+ })
571652})
572653
573654func verifyInvariants (ctx context.Context , op * operatorsv1alpha1.Operator ) {
0 commit comments