2222from kubernetes .informer .cache import ObjectCache , _meta_namespace_key
2323from kubernetes .informer .informer import (
2424 ADDED ,
25+ BOOKMARK ,
2526 DELETED ,
2627 ERROR ,
2728 MODIFIED ,
@@ -269,6 +270,7 @@ def fake_stream(func, **kw):
269270 cached = informer .cache .get_by_key ("default/mod-pod" )
270271 self .assertIs (cached , pod_v2 )
271272
273+
272274 def test_start_is_idempotent (self ):
273275 list_func = MagicMock ()
274276 list_resp = MagicMock ()
@@ -289,6 +291,75 @@ def test_start_is_idempotent(self):
289291 self .assertIs (informer ._thread , first_thread )
290292 informer .stop ()
291293
294+ def test_bookmark_event_fires_handler (self ):
295+ bookmark_obj = {"metadata" : {"resourceVersion" : "42" }}
296+ events = [
297+ {"type" : "BOOKMARK" , "object" : bookmark_obj , "raw_object" : bookmark_obj },
298+ ]
299+
300+ received = []
301+ list_func = MagicMock ()
302+ list_resp = MagicMock ()
303+ list_resp .items = []
304+ list_resp .metadata = MagicMock (resource_version = "1" )
305+ list_func .return_value = list_resp
306+
307+ informer = SharedInformer (list_func = list_func )
308+ informer .add_event_handler (BOOKMARK , received .append )
309+
310+ with patch ("kubernetes.informer.informer.Watch" ) as MockWatch :
311+ mock_w = MagicMock ()
312+
313+ def fake_stream (func , ** kw ):
314+ yield from events
315+ informer ._stop_event .set ()
316+
317+ mock_w .stream .side_effect = fake_stream
318+ MockWatch .return_value = mock_w
319+
320+ informer .start ()
321+ informer ._thread .join (timeout = 3 )
322+
323+ self .assertEqual (len (received ), 1 )
324+ self .assertEqual (received [0 ], bookmark_obj )
325+ # Cache should be unchanged (BOOKMARK does not add/modify/delete objects)
326+ self .assertEqual (informer .cache .list (), [])
327+
328+ def test_bookmark_event_does_not_modify_cache (self ):
329+ pod = _make_pod ("default" , "stable-pod" )
330+ bookmark_obj = {"metadata" : {"resourceVersion" : "99" }}
331+ events = [
332+ {"type" : "ADDED" , "object" : pod },
333+ {"type" : "BOOKMARK" , "object" : bookmark_obj , "raw_object" : bookmark_obj },
334+ ]
335+
336+ list_func = MagicMock ()
337+ list_resp = MagicMock ()
338+ list_resp .items = []
339+ list_resp .metadata = MagicMock (resource_version = "1" )
340+ list_func .return_value = list_resp
341+
342+ informer = SharedInformer (list_func = list_func )
343+
344+ with patch ("kubernetes.informer.informer.Watch" ) as MockWatch :
345+ mock_w = MagicMock ()
346+
347+ def fake_stream (func , ** kw ):
348+ yield from events
349+ informer ._stop_event .set ()
350+
351+ mock_w .stream .side_effect = fake_stream
352+ MockWatch .return_value = mock_w
353+
354+ informer .start ()
355+ informer ._thread .join (timeout = 3 )
356+
357+ # BOOKMARK must not have altered the cache content
358+ cached = informer .cache .list ()
359+ self .assertEqual (len (cached ), 1 )
360+ self .assertIs (cached [0 ], pod )
361+
292362
293363if __name__ == "__main__" :
294364 unittest .main ()
365+
0 commit comments