@@ -185,6 +185,147 @@ func TestImagePolicyReconciler_ignoresImageRepoNotReadyEvent(t *testing.T) {
185185 }).Should (BeTrue ())
186186}
187187
188+ func TestImagePolicyReconciler_imageRepoRevisionLifeCycle (t * testing.T ) {
189+ g := NewWithT (t )
190+
191+ namespaceName := "imagepolicy-" + randStringRunes (5 )
192+ namespace := & corev1.Namespace {
193+ ObjectMeta : metav1.ObjectMeta {Name : namespaceName },
194+ }
195+ g .Expect (k8sClient .Create (ctx , namespace )).ToNot (HaveOccurred ())
196+ t .Cleanup (func () {
197+ g .Expect (k8sClient .Delete (ctx , namespace )).NotTo (HaveOccurred ())
198+ })
199+
200+ imageRepo := & imagev1.ImageRepository {
201+ ObjectMeta : metav1.ObjectMeta {
202+ Namespace : namespaceName ,
203+ Name : "repo" ,
204+ },
205+ Spec : imagev1.ImageRepositorySpec {
206+ Image : "ghcr.io/stefanprodan/podinfo" ,
207+ },
208+ }
209+ g .Expect (k8sClient .Create (ctx , imageRepo )).NotTo (HaveOccurred ())
210+ t .Cleanup (func () {
211+ g .Expect (k8sClient .Delete (ctx , imageRepo )).NotTo (HaveOccurred ())
212+ })
213+
214+ g .Eventually (func () bool {
215+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imageRepo ), imageRepo )
216+ return err == nil && conditions .IsReady (imageRepo ) &&
217+ imageRepo .Generation == conditions .GetObservedGeneration (imageRepo , meta .ReadyCondition )
218+ }, timeout ).Should (BeTrue ())
219+
220+ imagePolicy := & imagev1.ImagePolicy {
221+ ObjectMeta : metav1.ObjectMeta {
222+ Namespace : namespaceName ,
223+ Name : "test-imagepolicy" ,
224+ },
225+ Spec : imagev1.ImagePolicySpec {
226+ ImageRepositoryRef : meta.NamespacedObjectReference {
227+ Name : imageRepo .Name ,
228+ },
229+ FilterTags : & imagev1.TagFilter {
230+ Pattern : `^6\.7\.\d+$` ,
231+ },
232+ Policy : imagev1.ImagePolicyChoice {
233+ SemVer : & imagev1.SemVerPolicy {
234+ Range : "6.7.x" ,
235+ },
236+ },
237+ },
238+ }
239+ g .Expect (k8sClient .Create (ctx , imagePolicy )).NotTo (HaveOccurred ())
240+ t .Cleanup (func () {
241+ g .Expect (k8sClient .Delete (ctx , imagePolicy )).NotTo (HaveOccurred ())
242+ })
243+
244+ g .Eventually (func () bool {
245+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imagePolicy ), imagePolicy )
246+ return err == nil && conditions .IsReady (imagePolicy ) &&
247+ imagePolicy .Generation == conditions .GetObservedGeneration (imagePolicy , meta .ReadyCondition ) &&
248+ imagePolicy .Status .LatestRef != nil &&
249+ imagePolicy .Status .LatestRef .Tag == "6.7.1"
250+ }, timeout ).Should (BeTrue ())
251+ expectedImagePolicyLastTransitionTime := conditions .GetLastTransitionTime (imagePolicy , meta .ReadyCondition ).Time
252+
253+ // Now force a reconciliation by setting the annotation.
254+ var requestedAt string
255+ g .Eventually (func () bool {
256+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imageRepo ), imageRepo )
257+ if err != nil {
258+ return false
259+ }
260+ p := patch .NewSerialPatcher (imageRepo , k8sClient )
261+ requestedAt = time .Now ().Format (time .RFC3339Nano )
262+ if imageRepo .Annotations == nil {
263+ imageRepo .Annotations = make (map [string ]string )
264+ }
265+ imageRepo .Annotations ["reconcile.fluxcd.io/requestedAt" ] = requestedAt
266+ return p .Patch (ctx , imageRepo ) == nil
267+ }, timeout ).Should (BeTrue ())
268+
269+ // Wait for the ImageRepository to reconcile.
270+ g .Eventually (func () bool {
271+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imageRepo ), imageRepo )
272+ return err == nil && conditions .IsReady (imageRepo ) &&
273+ imageRepo .Status .LastHandledReconcileAt == requestedAt
274+ }, timeout ).Should (BeTrue ())
275+
276+ // Check that the ImagePolicy is still ready and does not get updated.
277+ g .Eventually (func () bool {
278+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imagePolicy ), imagePolicy )
279+ return err == nil && conditions .IsReady (imagePolicy ) &&
280+ imagePolicy .Status .LatestRef != nil &&
281+ imagePolicy .Status .LatestRef .Tag == "6.7.1"
282+ }, timeout ).Should (BeTrue ())
283+
284+ // Wait a bit and check that the ImagePolicy remains ready.
285+ time .Sleep (time .Second )
286+ g .Eventually (func () bool {
287+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imagePolicy ), imagePolicy )
288+ return err == nil && conditions .IsReady (imagePolicy ) &&
289+ imagePolicy .Status .LatestRef != nil &&
290+ imagePolicy .Status .LatestRef .Tag == "6.7.1"
291+ }, timeout ).Should (BeTrue ())
292+
293+ // Check that the last transition time of the ImagePolicy Ready condition did not change since the beginning.
294+ lastTransitionTime := conditions .GetLastTransitionTime (imagePolicy , meta .ReadyCondition ).Time
295+ g .Expect (lastTransitionTime ).To (Equal (expectedImagePolicyLastTransitionTime ))
296+
297+ // Now add an exclusion rule to force the checksum to change.
298+ firstChecksum := imageRepo .Status .LastScanResult .Revision
299+ g .Eventually (func () bool {
300+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imageRepo ), imageRepo )
301+ if err != nil {
302+ return false
303+ }
304+ p := patch .NewSerialPatcher (imageRepo , k8sClient )
305+ imageRepo .Spec .ExclusionList = []string {`^6\.7\.1$` }
306+ return p .Patch (ctx , imageRepo ) == nil
307+ }, timeout ).Should (BeTrue ())
308+
309+ // Wait for the ImageRepository to reconcile.
310+ g .Eventually (func () bool {
311+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imageRepo ), imageRepo )
312+ return err == nil && conditions .IsReady (imageRepo ) &&
313+ imageRepo .Generation == conditions .GetObservedGeneration (imageRepo , meta .ReadyCondition ) &&
314+ imageRepo .Status .LastScanResult .Revision != firstChecksum
315+ }, timeout ).Should (BeTrue ())
316+
317+ // Check that the ImagePolicy receives the update and the latest tag changes.
318+ g .Eventually (func () bool {
319+ err := k8sClient .Get (ctx , client .ObjectKeyFromObject (imagePolicy ), imagePolicy )
320+ if err != nil {
321+ return false
322+ }
323+ return conditions .IsReady (imagePolicy ) &&
324+ imagePolicy .Generation == conditions .GetObservedGeneration (imagePolicy , meta .ReadyCondition ) &&
325+ imagePolicy .Status .LatestRef .Tag == "6.7.0"
326+ }, timeout ).Should (BeTrue ())
327+ }
328+
188329func TestImagePolicyReconciler_invalidImage (t * testing.T ) {
189330 g := NewWithT (t )
190331
0 commit comments