@@ -258,16 +258,31 @@ def assert_events(expected_events: dict,
258258 timeout (int): The seconds to wait for the events to be asserted
259259 """
260260 start = datetime .now ()
261+ events_since_last_match = []
262+ # Keep track of all events by evt.type so we can show near-misses
263+ events_by_type = {}
261264 for log in sinsp .read ():
262265 if not log :
263266 continue
264267 received_event = parse_log (log )
265268
269+ matched = False
266270 for event in expected_events :
267271 if validate_event (event , received_event ):
268272 expected_events .remove (event )
273+ matched = True
269274 break
270275
276+ if matched :
277+ events_since_last_match = []
278+ else :
279+ events_since_last_match .append (received_event )
280+
281+ # Track events by type for near-miss reporting
282+ if received_event is not None :
283+ evt_type = received_event .get ('evt.type' , '<unknown>' )
284+ events_by_type .setdefault (evt_type , []).append (received_event )
285+
271286 if not expected_events :
272287 # No more events to be matched. Leave.
273288 break
@@ -277,7 +292,36 @@ def assert_events(expected_events: dict,
277292
278293 # If any event was unmatched, raise an assert.
279294 if expected_events :
280- assert False , f"Did not receive expected events: { expected_events } "
295+ max_dump = 50
296+ msg_parts = [f"Did not receive expected events:" ]
297+ for evt in expected_events :
298+ msg_parts .append (f" { evt } " )
299+
300+ total = len (events_since_last_match )
301+ if total > 0 :
302+ msg_parts .append (f"\n Events seen since last successful match ({ total } total, showing last { min (total , max_dump )} ):" )
303+ for evt in events_since_last_match [- max_dump :]:
304+ if evt is not None :
305+ summary = {k : evt .get (k , '<missing>' ) for expected in expected_events for k in expected }
306+ msg_parts .append (f" { summary } " )
307+ else :
308+ msg_parts .append (" None (unparseable event)" )
309+
310+ # Show near-miss events: all events matching the evt.type of unmatched expected events
311+ wanted_types = {e .get ('evt.type' ) for e in expected_events if 'evt.type' in e }
312+ if wanted_types :
313+ for wt in sorted (wanted_types ):
314+ candidates = events_by_type .get (wt , [])
315+ if candidates :
316+ shown = candidates [- max_dump :]
317+ msg_parts .append (f"\n Near-miss events with evt.type={ wt } ({ len (candidates )} total, showing last { len (shown )} ):" )
318+ for evt in shown :
319+ summary = {k : evt .get (k , '<missing>' ) for expected in expected_events for k in expected }
320+ msg_parts .append (f" { summary } " )
321+ else :
322+ msg_parts .append (f"\n No events with evt.type={ wt } were seen at all" )
323+
324+ assert False , "\n " .join (msg_parts )
281325
282326
283327def sinsp_validation (container : docker .models .containers .Container ) -> (bool , str ):
0 commit comments