@@ -11,6 +11,8 @@ import (
1111 . "github.com/openmcp-project/controller-utils/pkg/testing/matchers"
1212
1313 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+ "k8s.io/apimachinery/pkg/runtime"
15+ "k8s.io/client-go/tools/record"
1416
1517 "github.com/openmcp-project/controller-utils/pkg/conditions"
1618)
@@ -213,4 +215,205 @@ var _ = Describe("Conditions", func() {
213215
214216 })
215217
218+ Context ("EventRecorder" , func () {
219+
220+ var recorder * record.FakeRecorder
221+
222+ dummy := & dummyObject {
223+ TypeMeta : metav1.TypeMeta {
224+ Kind : "Dummy" ,
225+ APIVersion : "dummy/v1" ,
226+ },
227+ }
228+
229+ BeforeEach (func () {
230+ recorder = record .NewFakeRecorder (100 )
231+ })
232+
233+ AfterEach (func () {
234+ close (recorder .Events )
235+ })
236+
237+ Context ("Verbosity: EventPerChange" , func () {
238+
239+ It ("should record an event for each changed condition status" , func () {
240+ cons := testConditionSet ()
241+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventPerChange )
242+ trueCon1 := conditions .GetCondition (cons , "true" )
243+ trueCon2 := conditions .GetCondition (cons , "alsoTrue" )
244+ _ , changed := updater .
245+ UpdateCondition (trueCon1 .Type , invert (trueCon1 .Status ), trueCon1 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
246+ UpdateCondition (trueCon2 .Type , invert (trueCon2 .Status ), trueCon2 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
247+ Record (dummy ).Conditions ()
248+ Expect (changed ).To (BeTrue ())
249+
250+ events := flush (recorder .Events )
251+ Expect (events ).To (ConsistOf (
252+ ContainSubstring ("Condition '%s' changed from '%s' to '%s'" , trueCon1 .Type , trueCon1 .Status , invert (trueCon1 .Status )),
253+ ContainSubstring ("Condition '%s' changed from '%s' to '%s'" , trueCon2 .Type , trueCon2 .Status , invert (trueCon2 .Status )),
254+ ))
255+ })
256+
257+ It ("should not record any events if no condition status changed, even if other fields changed" , func () {
258+ cons := testConditionSet ()
259+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventPerChange )
260+ trueCon1 := conditions .GetCondition (cons , "true" )
261+ trueCon2 := conditions .GetCondition (cons , "alsoTrue" )
262+ _ , changed := updater .
263+ UpdateCondition (trueCon1 .Type , trueCon1 .Status , trueCon1 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
264+ UpdateCondition (trueCon2 .Type , trueCon2 .Status , trueCon2 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
265+ Record (dummy ).Conditions ()
266+ Expect (changed ).To (BeTrue ())
267+
268+ events := flush (recorder .Events )
269+ Expect (events ).To (BeEmpty ())
270+ })
271+
272+ It ("should record added and lost conditions" , func () {
273+ cons := testConditionSet ()
274+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventPerChange )
275+ _ , changed := updater .
276+ UpdateCondition ("new" , metav1 .ConditionUnknown , 1 , "newReason" , "newMessage" ).
277+ RemoveCondition ("true" ).
278+ Record (dummy ).Conditions ()
279+ Expect (changed ).To (BeTrue ())
280+
281+ events := flush (recorder .Events )
282+ Expect (events ).To (ConsistOf (
283+ ContainSubstring ("Condition 'new' added with status '%s'" , metav1 .ConditionUnknown ),
284+ ContainSubstring ("Condition 'true' with status '%s' removed" , metav1 .ConditionTrue ),
285+ ))
286+ })
287+
288+ })
289+
290+ Context ("Verbosity: EventPerNewStatus" , func () {
291+
292+ It ("should record an event for each new status that any condition has reached" , func () {
293+ cons := testConditionSet ()
294+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventPerNewStatus )
295+ trueCon1 := conditions .GetCondition (cons , "true" )
296+ trueCon2 := conditions .GetCondition (cons , "alsoTrue" )
297+ falseCon := conditions .GetCondition (cons , "false" )
298+ _ , changed := updater .
299+ UpdateCondition (trueCon1 .Type , metav1 .ConditionUnknown , trueCon1 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
300+ UpdateCondition (trueCon2 .Type , metav1 .ConditionUnknown , trueCon2 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
301+ UpdateCondition ("anotherOne" , metav1 .ConditionUnknown , 1 , "newReason" , "newMessage" ).
302+ UpdateCondition (falseCon .Type , invert (falseCon .Status ), falseCon .ObservedGeneration + 1 , "newReason" , "newMessage" ).
303+ Record (dummy ).Conditions ()
304+ Expect (changed ).To (BeTrue ())
305+
306+ events := flush (recorder .Events )
307+ Expect (events ).To (ConsistOf (
308+ And (
309+ ContainSubstring ("The following conditions changed to '%s'" , metav1 .ConditionUnknown ),
310+ ContainSubstring (trueCon1 .Type ),
311+ ContainSubstring (trueCon2 .Type ),
312+ ContainSubstring ("anotherOne" ),
313+ ),
314+ And (
315+ ContainSubstring ("The following conditions changed to '%s'" , invert (falseCon .Status )),
316+ ContainSubstring (falseCon .Type ),
317+ ),
318+ ))
319+ })
320+
321+ It ("should not record any events if no condition status changed, even if other fields changed" , func () {
322+ cons := testConditionSet ()
323+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventPerNewStatus )
324+ trueCon1 := conditions .GetCondition (cons , "true" )
325+ trueCon2 := conditions .GetCondition (cons , "alsoTrue" )
326+ _ , changed := updater .
327+ UpdateCondition (trueCon1 .Type , trueCon1 .Status , trueCon1 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
328+ UpdateCondition (trueCon2 .Type , trueCon2 .Status , trueCon2 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
329+ Record (dummy ).Conditions ()
330+ Expect (changed ).To (BeTrue ())
331+
332+ events := flush (recorder .Events )
333+ Expect (events ).To (BeEmpty ())
334+ })
335+
336+ It ("should record lost conditions" , func () {
337+ cons := testConditionSet ()
338+ updater := conditions .ConditionUpdater (cons , true ).WithEventRecorder (recorder , conditions .EventPerNewStatus )
339+ _ , changed := updater .Record (dummy ).Conditions ()
340+ Expect (changed ).To (BeTrue ())
341+
342+ events := flush (recorder .Events )
343+ Expect (events ).To (ConsistOf (
344+ And (
345+ ContainSubstring ("The following conditions were removed" ),
346+ ContainSubstring ("true" ),
347+ ContainSubstring ("false" ),
348+ ContainSubstring ("alsoTrue" ),
349+ ),
350+ ))
351+ })
352+
353+ })
354+
355+ Context ("Verbosity: EventIfChanged" , func () {
356+
357+ It ("should only record a single event, no matter how many conditions changed" , func () {
358+ cons := testConditionSet ()
359+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventIfChanged )
360+ trueCon := conditions .GetCondition (cons , "true" )
361+ falseCon := conditions .GetCondition (cons , "false" )
362+ _ , changed := updater .
363+ UpdateCondition (trueCon .Type , invert (trueCon .Status ), trueCon .ObservedGeneration + 1 , "newReason" , "newMessage" ).
364+ UpdateCondition (falseCon .Type , invert (falseCon .Status ), falseCon .ObservedGeneration + 1 , "newReason" , "newMessage" ).
365+ UpdateCondition ("new" , metav1 .ConditionUnknown , 1 , "newReason" , "newMessage" ).
366+ RemoveCondition ("alsoTrue" ).
367+ Record (dummy ).Conditions ()
368+ Expect (changed ).To (BeTrue ())
369+
370+ events := flush (recorder .Events )
371+ Expect (events ).To (ConsistOf (
372+ And (
373+ ContainSubstring ("The following conditions have changed" ),
374+ ContainSubstring ("true" ),
375+ ContainSubstring ("false" ),
376+ ContainSubstring ("alsoTrue" ),
377+ ContainSubstring ("new" ),
378+ ),
379+ ))
380+ })
381+
382+ It ("should not record any events if no condition status changed, even if other fields changed" , func () {
383+ cons := testConditionSet ()
384+ updater := conditions .ConditionUpdater (cons , false ).WithEventRecorder (recorder , conditions .EventIfChanged )
385+ trueCon1 := conditions .GetCondition (cons , "true" )
386+ trueCon2 := conditions .GetCondition (cons , "alsoTrue" )
387+ _ , changed := updater .
388+ UpdateCondition (trueCon1 .Type , trueCon1 .Status , trueCon1 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
389+ UpdateCondition (trueCon2 .Type , trueCon2 .Status , trueCon2 .ObservedGeneration + 1 , "newReason" , "newMessage" ).
390+ Record (dummy ).Conditions ()
391+ Expect (changed ).To (BeTrue ())
392+
393+ events := flush (recorder .Events )
394+ Expect (events ).To (BeEmpty ())
395+ })
396+
397+ })
398+
399+ })
400+
216401})
402+
403+ type dummyObject struct {
404+ metav1.TypeMeta `json:",inline"`
405+ }
406+
407+ func (d * dummyObject ) DeepCopyObject () runtime.Object {
408+ return & dummyObject {
409+ TypeMeta : d .TypeMeta ,
410+ }
411+ }
412+
413+ func flush (c chan string ) []string {
414+ res := []string {}
415+ for len (c ) > 0 {
416+ res = append (res , <- c )
417+ }
418+ return res
419+ }
0 commit comments