@@ -1709,6 +1709,65 @@ var _ = Describe("Scheduled Leases", func() {
17091709 })
17101710 })
17111711
1712+ When ("an ended lease has the ended label" , func () {
1713+ It ("should short-circuit without running reconciliation logic" , func () {
1714+ lease := leaseDutA2Sec .DeepCopy ()
1715+ lease .Spec .Duration = & metav1.Duration {Duration : 100 * time .Millisecond }
1716+
1717+ ctx := context .Background ()
1718+ Expect (k8sClient .Create (ctx , lease )).To (Succeed ())
1719+ _ = reconcileLease (ctx , lease )
1720+
1721+ Eventually (func () bool {
1722+ _ = reconcileLease (ctx , lease )
1723+ return getLease (ctx , lease .Name ).Status .Ended
1724+ }).WithTimeout (500 * time .Millisecond ).WithPolling (50 * time .Millisecond ).Should (BeTrue ())
1725+
1726+ updatedLease := getLease (ctx , lease .Name )
1727+ Expect (updatedLease .Labels ).To (HaveKeyWithValue (
1728+ string (jumpstarterdevv1alpha1 .LeaseLabelEnded ),
1729+ jumpstarterdevv1alpha1 .LeaseLabelEndedValue ,
1730+ ))
1731+
1732+ // Reconciling again should be a no-op (short-circuit)
1733+ result := reconcileLease (ctx , lease )
1734+ Expect (result .RequeueAfter ).To (BeZero ())
1735+ })
1736+ })
1737+
1738+ When ("an ended lease is missing the ended label" , func () {
1739+ It ("should backfill the label on the next reconcile" , func () {
1740+ lease := leaseDutA2Sec .DeepCopy ()
1741+ lease .Spec .Duration = & metav1.Duration {Duration : 100 * time .Millisecond }
1742+
1743+ ctx := context .Background ()
1744+ Expect (k8sClient .Create (ctx , lease )).To (Succeed ())
1745+ _ = reconcileLease (ctx , lease )
1746+
1747+ Eventually (func () bool {
1748+ _ = reconcileLease (ctx , lease )
1749+ return getLease (ctx , lease .Name ).Status .Ended
1750+ }).WithTimeout (500 * time .Millisecond ).WithPolling (50 * time .Millisecond ).Should (BeTrue ())
1751+
1752+ // Simulate split-brain: remove the ended label as if metadata update failed
1753+ updatedLease := getLease (ctx , lease .Name )
1754+ delete (updatedLease .Labels , string (jumpstarterdevv1alpha1 .LeaseLabelEnded ))
1755+ Expect (k8sClient .Update (ctx , updatedLease )).To (Succeed ())
1756+
1757+ // Verify label is gone
1758+ updatedLease = getLease (ctx , lease .Name )
1759+ Expect (updatedLease .Labels ).NotTo (HaveKey (string (jumpstarterdevv1alpha1 .LeaseLabelEnded )))
1760+
1761+ // Reconcile should backfill the label
1762+ _ = reconcileLease (ctx , lease )
1763+ updatedLease = getLease (ctx , lease .Name )
1764+ Expect (updatedLease .Labels ).To (HaveKeyWithValue (
1765+ string (jumpstarterdevv1alpha1 .LeaseLabelEnded ),
1766+ jumpstarterdevv1alpha1 .LeaseLabelEndedValue ,
1767+ ))
1768+ })
1769+ })
1770+
17121771 // UpdateLease mutation tests
17131772 // Note: These tests simulate what UpdateLease does via gRPC by directly
17141773 // modifying the lease spec and calling ReconcileLeaseTimeFields
0 commit comments