@@ -2,6 +2,7 @@ package reconciler
22
33import (
44 "context"
5+ "maps"
56 "path"
67 "testing"
78 "time"
@@ -10,6 +11,7 @@ import (
1011 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
1112 "github.com/openshift-pipelines/pipelines-as-code/pkg/events"
1213 "github.com/openshift-pipelines/pipelines-as-code/pkg/kubeinteraction"
14+ queuepkg "github.com/openshift-pipelines/pipelines-as-code/pkg/queue"
1315 testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
1416 tektontest "github.com/openshift-pipelines/pipelines-as-code/pkg/test/tekton"
1517 pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
@@ -19,6 +21,7 @@ import (
1921 "gotest.tools/v3/assert"
2022 corev1 "k8s.io/api/core/v1"
2123 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+ "k8s.io/apimachinery/pkg/types"
2225 "k8s.io/client-go/tools/cache"
2326 duckv1 "knative.dev/pkg/apis/duck/v1"
2427 "knative.dev/pkg/controller"
@@ -113,8 +116,14 @@ func TestSelectLeaseQueueRecoveryKeys(t *testing.T) {
113116 newLeaseRecoveryPR ("valid" , "test-ns" , "repo-b" , now .Add (3 * time .Second ), map [string ]string {}, false ),
114117 newLeaseRecoveryPR ("valid-after-malformed" , "test-ns" , "repo-c" , now .Add (4 * time .Second ), map [string ]string {}, false ),
115118 newLeaseRecoveryPR ("other-namespace" , "other-ns" , "repo-a" , now .Add (4 * time .Second ), map [string ]string {}, false ),
119+ newLeaseRecoveryPR ("waiting-behind-started" , "test-ns" , "repo-e" , now .Add (4 * time .Second ), map [string ]string {}, false ),
120+ newLeaseRecoveryStartedPR ("running" , "repo-e" , now .Add (5 * time .Second )),
121+ newLeaseRecoveryPR ("actively-claimed" , "test-ns" , "repo-f" , now .Add (6 * time .Second ), map [string ]string {
122+ keys .QueueClaimedBy : "watcher-1" ,
123+ keys .QueueClaimedAt : now .Format (time .RFC3339Nano ),
124+ }, false ),
116125 newLeaseRecoveryPR ("missing-repo" , "test-ns" , "" , now .Add (5 * time .Second ), map [string ]string {}, false ),
117- newLeaseRecoveryStartedPR ("started" , "test-ns" , " repo-d" , now .Add (6 * time .Second )),
126+ newLeaseRecoveryStartedPR ("started" , "repo-d" , now .Add (6 * time .Second )),
118127 newLeaseRecoveryPR ("done" , "test-ns" , "repo-d" , now .Add (7 * time .Second ), map [string ]string {}, true ),
119128 },
120129 want : []string {
@@ -128,9 +137,9 @@ func TestSelectLeaseQueueRecoveryKeys(t *testing.T) {
128137
129138 for _ , tt := range tests {
130139 t .Run (tt .name , func (t * testing.T ) {
131- keys := selectLeaseQueueRecoveryKeys (tt .pipelineRuns )
132- got := make ([]string , 0 , len (keys ))
133- for _ , key := range keys {
140+ recoveryKeys := selectLeaseQueueRecoveryKeysAt (tt .pipelineRuns , now , queuepkg . DefaultLeaseClaimTTL () )
141+ got := make ([]string , 0 , len (recoveryKeys ))
142+ for _ , key := range recoveryKeys {
134143 got = append (got , key .String ())
135144 }
136145 assert .DeepEqual (t , got , tt .want )
@@ -155,7 +164,7 @@ func TestRunLeaseQueueRecovery(t *testing.T) {
155164 newLeaseRecoveryPR ("first" , "test-ns" , "repo-a" , now , map [string ]string {}, false ),
156165 newLeaseRecoveryPR ("second" , "test-ns" , "repo-a" , now .Add (time .Second ), map [string ]string {}, false ),
157166 newLeaseRecoveryPR ("third" , "test-ns" , "repo-b" , now .Add (2 * time .Second ), map [string ]string {}, false ),
158- newLeaseRecoveryStartedPR ("started" , "test-ns" , " repo-c" , now .Add (3 * time .Second )),
167+ newLeaseRecoveryStartedPR ("started" , "repo-c" , now .Add (3 * time .Second )),
159168 } {
160169 assert .NilError (t , indexer .Add (pipelineRun ))
161170 _ , err := stdata .Pipeline .TektonV1 ().PipelineRuns (pipelineRun .Namespace ).Create (ctx , pipelineRun , metav1.CreateOptions {})
@@ -271,6 +280,73 @@ func TestRunLeaseQueueRecoverySkipsStaleAdvancedLivePipelineRun(t *testing.T) {
271280 }
272281}
273282
283+ func TestRunLeaseQueueRecoverySkipsHealthyQueuedRuns (t * testing.T ) {
284+ observer , catcher := zapobserver .New (zap .DebugLevel )
285+ logger := zap .New (observer ).Sugar ()
286+ ctx , _ := rtesting .SetupFakeContext (t )
287+ now := time .Unix (1_700_001_300 , 0 )
288+ claimedAt := time .Now ().UTC ().Format (time .RFC3339Nano )
289+
290+ started := newLeaseRecoveryStartedPR ("running" , "repo-a" , now )
291+ waiting := newLeaseRecoveryPR ("waiting" , "test-ns" , "repo-a" , now .Add (time .Second ), map [string ]string {}, false )
292+ claimed := newLeaseRecoveryPR ("claimed" , "test-ns" , "repo-b" , now .Add (2 * time .Second ), map [string ]string {
293+ keys .QueueClaimedBy : "watcher-1" ,
294+ keys .QueueClaimedAt : claimedAt ,
295+ }, false )
296+
297+ stdata , _ := testclient .SeedTestData (t , ctx , testclient.Data {
298+ PipelineRuns : []* pipelinev1.PipelineRun {started , waiting , claimed },
299+ })
300+ wh := & fakeReconciler {}
301+ impl := controller .NewContext (context .TODO (), wh , controller.ControllerOptions {
302+ WorkQueueName : "LeaseRecovery" ,
303+ Logger : logger .Named ("LeaseRecovery" ),
304+ })
305+
306+ indexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {})
307+ for _ , pipelineRun := range []* pipelinev1.PipelineRun {started , waiting , claimed } {
308+ assert .NilError (t , indexer .Add (pipelineRun ))
309+ }
310+
311+ emitter := events .NewEventEmitter (stdata .Kube , logger )
312+ runLeaseQueueRecovery (ctx , logger , impl , tektonv1lister .NewPipelineRunLister (indexer ), stdata .Pipeline , emitter )
313+
314+ assert .Equal (t , catcher .FilterMessageSnippet ("Adding to queue" ).Len (), 0 )
315+
316+ for _ , name := range []string {"waiting" , "claimed" } {
317+ updated , err := stdata .Pipeline .TektonV1 ().PipelineRuns ("test-ns" ).Get (ctx , name , metav1.GetOptions {})
318+ assert .NilError (t , err )
319+ assert .Equal (t , updated .GetAnnotations ()[keys .QueueDecision ], "" )
320+ }
321+
322+ events , err := stdata .Kube .CoreV1 ().Events ("test-ns" ).List (ctx , metav1.ListOptions {})
323+ assert .NilError (t , err )
324+ recoveryEvents := 0
325+ for _ , event := range events .Items {
326+ if event .Reason == "QueueRecoveryRequeued" {
327+ recoveryEvents ++
328+ }
329+ }
330+ assert .Equal (t , recoveryEvents , 0 )
331+ }
332+
333+ func selectLeaseQueueRecoveryKeysAt (
334+ pipelineRuns []* pipelinev1.PipelineRun ,
335+ now time.Time ,
336+ claimTTL time.Duration ,
337+ ) []types.NamespacedName {
338+ selected := selectLeaseQueueRecoveryCandidatesAt (pipelineRuns , now , claimTTL )
339+
340+ recoveryKeys := make ([]types.NamespacedName , 0 , len (selected ))
341+ for _ , pipelineRun := range selected {
342+ recoveryKeys = append (recoveryKeys , types.NamespacedName {
343+ Namespace : pipelineRun .GetNamespace (),
344+ Name : pipelineRun .GetName (),
345+ })
346+ }
347+ return recoveryKeys
348+ }
349+
274350func newLeaseRecoveryPR (
275351 name , namespace , repo string ,
276352 createdAt time.Time ,
@@ -284,9 +360,7 @@ func newLeaseRecoveryPR(
284360 if repo != "" {
285361 annotations [keys .Repository ] = repo
286362 }
287- for key , value := range extraAnnotations {
288- annotations [key ] = value
289- }
363+ maps .Copy (annotations , extraAnnotations )
290364
291365 pipelineRun := & pipelinev1.PipelineRun {
292366 ObjectMeta : metav1.ObjectMeta {
@@ -308,11 +382,11 @@ func newLeaseRecoveryPR(
308382 return pipelineRun
309383}
310384
311- func newLeaseRecoveryStartedPR (name , namespace , repo string , createdAt time.Time ) * pipelinev1.PipelineRun {
385+ func newLeaseRecoveryStartedPR (name , repo string , createdAt time.Time ) * pipelinev1.PipelineRun {
312386 return & pipelinev1.PipelineRun {
313387 ObjectMeta : metav1.ObjectMeta {
314388 Name : name ,
315- Namespace : namespace ,
389+ Namespace : "test-ns" ,
316390 CreationTimestamp : metav1.Time {Time : createdAt },
317391 Annotations : map [string ]string {
318392 keys .Repository : repo ,
0 commit comments