@@ -9,23 +9,25 @@ import (
99
1010 o "github.com/onsi/gomega"
1111
12+ buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
13+ "github.com/shipwright-io/operator/api/v1alpha1"
14+ tektonoperatorv1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
15+ tektonoperatorv1alpha1client "github.com/tektoncd/operator/pkg/client/clientset/versioned/fake"
1216 appsv1 "k8s.io/api/apps/v1"
1317 corev1 "k8s.io/api/core/v1"
1418 rbacv1 "k8s.io/api/rbac/v1"
19+ crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1520 crdclientv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
1621 "k8s.io/apimachinery/pkg/api/errors"
1722 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1823 "k8s.io/apimachinery/pkg/runtime"
1924 "k8s.io/apimachinery/pkg/types"
25+ "knative.dev/pkg/apis"
26+ duckv1 "knative.dev/pkg/apis/duck/v1"
2027 "sigs.k8s.io/controller-runtime/pkg/client"
2128 "sigs.k8s.io/controller-runtime/pkg/client/fake"
2229 "sigs.k8s.io/controller-runtime/pkg/log/zap"
2330 "sigs.k8s.io/controller-runtime/pkg/reconcile"
24-
25- "github.com/shipwright-io/operator/api/v1alpha1"
26- tektonoperatorv1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
27- tektonoperatorv1alpha1client "github.com/tektoncd/operator/pkg/client/clientset/versioned/fake"
28- crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2931)
3032
3133// bootstrapShipwrightBuildReconciler start up a new instance of ShipwrightBuildReconciler which is
@@ -44,10 +46,12 @@ func bootstrapShipwrightBuildReconciler(
4446 s .AddKnownTypes (v1alpha1 .GroupVersion , & v1alpha1.ShipwrightBuild {})
4547 s .AddKnownTypes (rbacv1 .SchemeGroupVersion , & rbacv1.ClusterRoleBinding {})
4648 s .AddKnownTypes (rbacv1 .SchemeGroupVersion , & rbacv1.ClusterRole {})
49+ s .AddKnownTypes (tektonoperatorv1alpha1 .SchemeGroupVersion , & tektonoperatorv1alpha1.TektonConfig {})
50+ s .AddKnownTypes (buildv1alpha1 .SchemeGroupVersion , & buildv1alpha1.ClusterBuildStrategy {})
4751
4852 logger := zap .New ()
4953
50- c := fake .NewClientBuilder ().WithScheme (s ).WithObjects (b ).Build ()
54+ c := fake .NewClientBuilder ().WithScheme (s ).WithObjects (b ).WithStatusSubresource ( & v1alpha1. ShipwrightBuild {}). Build ()
5155 var crdClient * crdclientv1.Clientset
5256 var toClient * tektonoperatorv1alpha1client.Clientset
5357 if len (tcrds ) > 0 {
@@ -245,3 +249,117 @@ func TestShipwrightBuildReconciler_Reconcile(t *testing.T) {
245249 })
246250 }
247251}
252+
253+ func TestShipwrightBuildReconciler_OperandReadiness (t * testing.T ) {
254+ g := o .NewGomegaWithT (t )
255+
256+ // ShipwrightBuild object
257+ b := & v1alpha1.ShipwrightBuild {
258+ ObjectMeta : metav1.ObjectMeta {
259+ Name : "name" ,
260+ Namespace : "default" ,
261+ },
262+ Spec : v1alpha1.ShipwrightBuildSpec {
263+ TargetNamespace : "namespace" ,
264+ },
265+ Status : v1alpha1.ShipwrightBuildStatus {
266+ Conditions : []metav1.Condition {
267+ {
268+ Type : ConditionReady ,
269+ Status : metav1 .ConditionTrue ,
270+ },
271+ },
272+ },
273+ }
274+
275+ // Mock TektonConfig to simulate Tekton Operator installation
276+ tektonConfig := & tektonoperatorv1alpha1.TektonConfig {
277+ ObjectMeta : metav1.ObjectMeta {
278+ Name : "config" ,
279+ },
280+ Status : tektonoperatorv1alpha1.TektonConfigStatus {
281+ Status : duckv1.Status {
282+ Conditions : duckv1.Conditions {
283+ {
284+ Type : ConditionReady ,
285+ Status : corev1 .ConditionFalse ,
286+ Reason : "Installed" ,
287+ Message : "TektonConfig is not ready" ,
288+ },
289+ },
290+ },
291+ },
292+ }
293+ // Preload the fake client with a valid ClusterBuildStrategy to pass buildstrategy reconciliation
294+ cbs := & buildv1alpha1.ClusterBuildStrategy {
295+ ObjectMeta : metav1.ObjectMeta {
296+ Name : "buildah" ,
297+ },
298+ Spec : buildv1alpha1.BuildStrategySpec {
299+ BuildSteps : []buildv1alpha1.BuildStep {
300+ {
301+ Container : corev1.Container {
302+ Name : "build-step" ,
303+ Image : "quay.io/buildah/stable" ,
304+ },
305+ },
306+ },
307+ },
308+ }
309+
310+ // Prepare cr
311+ crd1 := & crdv1.CustomResourceDefinition {}
312+ crd1 .Name = "taskruns.tekton.dev"
313+ crd2 := & crdv1.CustomResourceDefinition {}
314+ crd2 .Name = "tektonconfigs.operator.tekton.dev"
315+ crd2 .Labels = map [string ]string {"operator.tekton.dev/release" : common .TektonOpMinSupportedVersion }
316+ crd3 := & crdv1.CustomResourceDefinition {}
317+ crd3 .Name = "clusterbuildstrategies.shipwright.io"
318+ crds := []* crdv1.CustomResourceDefinition {crd1 , crd2 , crd3 }
319+
320+ // Bootstrap the reconciler with the mock objects
321+ c , _ , _ , r := bootstrapShipwrightBuildReconciler (t , b , nil , crds )
322+
323+ // Inject a pre-created valid tektonconfig
324+ _ , err := r .TektonOperatorClient .TektonConfigs ().Create (context .TODO (), tektonConfig , metav1.CreateOptions {})
325+ g .Expect (err ).To (o .BeNil ())
326+
327+ // Verify creation of tektonconfig
328+ cfg , err := r .TektonOperatorClient .TektonConfigs ().Get (context .TODO (), "config" , metav1.GetOptions {})
329+ g .Expect (err ).To (o .BeNil ())
330+ g .Expect (cfg .Name ).To (o .Equal ("config" ))
331+ g .Expect (cfg .Status .Conditions [0 ].Type ).To (o .Equal (apis .ConditionReady ))
332+
333+ // Simulate reconciliation
334+ namespacedName := types.NamespacedName {Namespace : "default" , Name : "name" }
335+ req := reconcile.Request {NamespacedName : namespacedName }
336+ res , err := r .Reconcile (context .TODO (), req )
337+ g .Expect (err ).To (o .BeNil ())
338+ g .Expect (res .Requeue ).To (o .BeTrue (), "Reconciliation should requeue when TektonConfig is not ready" )
339+
340+ // Verify that the ShipwrightBuild is marked as not ready
341+ updated := & v1alpha1.ShipwrightBuild {}
342+ err = c .Get (context .TODO (), req .NamespacedName , updated )
343+ g .Expect (err ).To (o .BeNil ())
344+ g .Expect (updated .Status .IsReady ()).To (o .BeFalse (), "ShipwrightBuild should not be ready when TektonConfig is not ready" )
345+
346+ // Simulate TektonConfig becoming ready
347+ tektonConfig .Status .Conditions [0 ].Status = corev1 .ConditionTrue
348+ tektonConfig .Status .Conditions [0 ].Reason = "Installed"
349+ tektonConfig .Status .Conditions [0 ].Message = "TektonConfig is now ready"
350+ _ , err = r .TektonOperatorClient .TektonConfigs ().Update (context .TODO (), tektonConfig , metav1.UpdateOptions {})
351+ g .Expect (err ).To (o .BeNil ())
352+
353+ // Inject a pre-created valid ClusterBuildStrategy
354+ err = c .Create (context .TODO (), cbs )
355+ g .Expect (err ).To (o .BeNil ())
356+ // Trigger reconciliation again
357+ res , err = r .Reconcile (context .TODO (), req )
358+ g .Expect (err ).To (o .BeNil ())
359+ g .Expect (res .Requeue ).To (o .BeFalse (), "Should not requeue after TektonConfig is ready" )
360+
361+ // Fetch and verify ShipwrightBuild is now ready
362+ err = c .Get (context .TODO (), req .NamespacedName , updated )
363+ g .Expect (err ).To (o .BeNil ())
364+ g .Expect (updated .Status .IsReady ()).To (o .BeTrue (), "ShipwrightBuild should be ready when TektonConfig is ready" )
365+ }
0 commit comments