@@ -2226,7 +2226,7 @@ async def test_on_agent_error_callback_logs_correctly(
22262226 callback_context = callback_context ,
22272227 error = error ,
22282228 )
2229- await asyncio . sleep ( 0.05 )
2229+ await bq_plugin_inst . flush ( )
22302230 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
22312231 log_entry = next (r for r in rows if r ["event_type" ] == "AGENT_ERROR" )
22322232 assert log_entry ["error_message" ] == "Agent crashed"
@@ -2267,7 +2267,7 @@ async def test_on_agent_error_does_not_pop_foreign_invocation_span(
22672267 callback_context = callback_context ,
22682268 error = error ,
22692269 )
2270- await asyncio . sleep ( 0.05 )
2270+ await bq_plugin_inst . flush ( )
22712271
22722272 # The invocation root was NOT consumed by the agent-error pop.
22732273 assert trace_manager .get_current_span_id () == inv_span_id
@@ -2297,7 +2297,7 @@ async def test_on_run_error_callback_logs_correctly(
22972297 invocation_context = invocation_context ,
22982298 error = error ,
22992299 )
2300- await asyncio . sleep ( 0.05 )
2300+ await bq_plugin_inst . flush ( )
23012301 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
23022302 log_entry = next (r for r in rows if r ["event_type" ] == "INVOCATION_ERROR" )
23032303 assert log_entry ["error_message" ] == "Invocation failed"
@@ -2376,7 +2376,7 @@ async def test_traceback_not_truncated_with_negative_max_len(
23762376 ),
23772377 error = error ,
23782378 )
2379- await asyncio . sleep ( 0.05 )
2379+ await plugin . flush ( )
23802380 rows = await _get_captured_rows_async (
23812381 mock_write_client , dummy_arrow_schema
23822382 )
@@ -5698,7 +5698,7 @@ async def test_hitl_confirmation_emits_additional_event(
56985698 await bq_plugin_inst .on_event_callback (
56995699 invocation_context = invocation_context , event = event
57005700 )
5701- await asyncio . sleep ( 0.05 )
5701+ await bq_plugin_inst . flush ( )
57025702 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
57035703 event_types = [r ["event_type" ] for r in rows ]
57045704 assert "HITL_CONFIRMATION_REQUEST" in event_types
@@ -5715,7 +5715,7 @@ async def test_hitl_credential_emits_additional_event(
57155715 await bq_plugin_inst .on_event_callback (
57165716 invocation_context = invocation_context , event = event
57175717 )
5718- await asyncio . sleep ( 0.05 )
5718+ await bq_plugin_inst . flush ( )
57195719 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
57205720 event_types = [r ["event_type" ] for r in rows ]
57215721 assert "HITL_CREDENTIAL_REQUEST" in event_types
@@ -5732,7 +5732,7 @@ async def test_hitl_completion_emits_additional_event(
57325732 await bq_plugin_inst .on_event_callback (
57335733 invocation_context = invocation_context , event = event
57345734 )
5735- await asyncio . sleep ( 0.05 )
5735+ await bq_plugin_inst . flush ( )
57365736 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
57375737 event_types = [r ["event_type" ] for r in rows ]
57385738 assert "HITL_CONFIRMATION_REQUEST_COMPLETED" in event_types
@@ -5749,7 +5749,7 @@ async def test_regular_tool_no_hitl_event(
57495749 await bq_plugin_inst .on_event_callback (
57505750 invocation_context = invocation_context , event = event
57515751 )
5752- await asyncio . sleep ( 0.05 )
5752+ await bq_plugin_inst . flush ( )
57535753 # No HITL events should be emitted for non-HITL function calls.
57545754 # on_event_callback only logs STATE_DELTA and HITL events; a regular
57555755 # function call produces neither.
@@ -7903,7 +7903,7 @@ async def test_cache_metadata_logged_when_present(
79037903 callback_context = callback_context ,
79047904 llm_response = llm_response ,
79057905 )
7906- await asyncio . sleep ( 0.05 )
7906+ await bq_plugin_inst . flush ( )
79077907 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
79087908 log_entry = next (r for r in rows if r ["event_type" ] == "LLM_RESPONSE" )
79097909
@@ -7938,7 +7938,7 @@ def __init__(self):
79387938 callback_context = callback_context ,
79397939 llm_response = mock_response ,
79407940 )
7941- await asyncio . sleep ( 0.05 )
7941+ await bq_plugin_inst . flush ( )
79427942 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
79437943 log_entry = next (r for r in rows if r ["event_type" ] == "LLM_RESPONSE" )
79447944
@@ -7986,7 +7986,7 @@ async def test_a2a_interaction_logged_for_response_metadata(
79867986 )
79877987 assert result is None
79887988
7989- await asyncio . sleep ( 0.05 )
7989+ await bq_plugin_inst . flush ( )
79907990 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
79917991 event_types = [r ["event_type" ] for r in rows ]
79927992 assert "A2A_INTERACTION" in event_types
@@ -8025,7 +8025,7 @@ async def test_a2a_interaction_logged_for_request_metadata(
80258025 )
80268026 assert result is None
80278027
8028- await asyncio . sleep ( 0.05 )
8028+ await bq_plugin_inst . flush ( )
80298029 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
80308030 event_types = [r ["event_type" ] for r in rows ]
80318031 assert "A2A_INTERACTION" in event_types
@@ -8058,7 +8058,7 @@ async def test_no_a2a_interaction_for_irrelevant_metadata(
80588058 )
80598059 assert result is None
80608060
8061- await asyncio . sleep ( 0.05 )
8061+ await bq_plugin_inst . flush ( )
80628062 # No events logged — a2a:task_id alone is not a meaningful
80638063 # interaction payload.
80648064 assert mock_write_client .append_rows .call_count == 0
@@ -8078,7 +8078,7 @@ async def test_no_a2a_interaction_for_no_metadata(
80788078 )
80798079 assert result is None
80808080
8081- await asyncio . sleep ( 0.05 )
8081+ await bq_plugin_inst . flush ( )
80828082 assert mock_write_client .append_rows .call_count == 0
80838083
80848084
@@ -8392,7 +8392,7 @@ async def test_logs_final_text_response(
83928392 await bq_plugin_inst .on_event_callback (
83938393 invocation_context = invocation_context , event = event
83948394 )
8395- await asyncio . sleep ( 0.05 )
8395+ await bq_plugin_inst . flush ( )
83968396 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
83978397 agent_resp_rows = [r for r in rows if r ["event_type" ] == "AGENT_RESPONSE" ]
83988398 assert len (agent_resp_rows ) == 1
@@ -8420,7 +8420,7 @@ async def test_skips_function_call_events(
84208420 await bq_plugin_inst .on_event_callback (
84218421 invocation_context = invocation_context , event = event
84228422 )
8423- await asyncio . sleep ( 0.05 )
8423+ await bq_plugin_inst . flush ( )
84248424 assert mock_write_client .append_rows .call_count == 0
84258425
84268426 @pytest .mark .asyncio
@@ -8441,7 +8441,7 @@ async def test_skips_function_response_events(
84418441 await bq_plugin_inst .on_event_callback (
84428442 invocation_context = invocation_context , event = event
84438443 )
8444- await asyncio . sleep ( 0.05 )
8444+ await bq_plugin_inst . flush ( )
84458445 assert mock_write_client .append_rows .call_count == 0
84468446
84478447 @pytest .mark .asyncio
@@ -8461,7 +8461,7 @@ async def test_skips_partial_events(
84618461 await bq_plugin_inst .on_event_callback (
84628462 invocation_context = invocation_context , event = event
84638463 )
8464- await asyncio . sleep ( 0.05 )
8464+ await bq_plugin_inst . flush ( )
84658465 assert mock_write_client .append_rows .call_count == 0
84668466
84678467 @pytest .mark .asyncio
@@ -8488,7 +8488,7 @@ async def test_skips_long_running_tool_events(
84888488 await bq_plugin_inst .on_event_callback (
84898489 invocation_context = invocation_context , event = event
84908490 )
8491- await asyncio . sleep ( 0.05 )
8491+ await bq_plugin_inst . flush ( )
84928492 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
84938493 types_emitted = [r ["event_type" ] for r in rows ]
84948494 assert "AGENT_RESPONSE" not in types_emitted
@@ -8513,7 +8513,7 @@ async def test_skips_thought_only_events(
85138513 await bq_plugin_inst .on_event_callback (
85148514 invocation_context = invocation_context , event = event
85158515 )
8516- await asyncio . sleep ( 0.05 )
8516+ await bq_plugin_inst . flush ( )
85178517 assert mock_write_client .append_rows .call_count == 0
85188518
85198519 @pytest .mark .asyncio
@@ -8539,7 +8539,7 @@ async def test_mixed_thought_and_visible_logs_only_visible(
85398539 await bq_plugin_inst .on_event_callback (
85408540 invocation_context = invocation_context , event = event
85418541 )
8542- await asyncio . sleep ( 0.05 )
8542+ await bq_plugin_inst . flush ( )
85438543 rows = await _get_captured_rows_async (mock_write_client , dummy_arrow_schema )
85448544 agent_resp_rows = [r for r in rows if r ["event_type" ] == "AGENT_RESPONSE" ]
85458545 assert len (agent_resp_rows ) == 1
@@ -8563,7 +8563,7 @@ async def test_skips_empty_part_events(
85638563 await bq_plugin_inst .on_event_callback (
85648564 invocation_context = invocation_context , event = event
85658565 )
8566- await asyncio . sleep ( 0.05 )
8566+ await bq_plugin_inst . flush ( )
85678567 assert mock_write_client .append_rows .call_count == 0
85688568
85698569 @pytest .mark .asyncio
@@ -8582,7 +8582,7 @@ async def test_skips_empty_text_events(
85828582 await bq_plugin_inst .on_event_callback (
85838583 invocation_context = invocation_context , event = event
85848584 )
8585- await asyncio . sleep ( 0.05 )
8585+ await bq_plugin_inst . flush ( )
85868586 assert mock_write_client .append_rows .call_count == 0
85878587
85888588 @pytest .mark .asyncio
@@ -8609,7 +8609,7 @@ async def test_skips_executable_code_only_events(
86098609 await bq_plugin_inst .on_event_callback (
86108610 invocation_context = invocation_context , event = event
86118611 )
8612- await asyncio . sleep ( 0.05 )
8612+ await bq_plugin_inst . flush ( )
86138613 assert mock_write_client .append_rows .call_count == 0
86148614
86158615
@@ -9913,7 +9913,7 @@ async def test_final_attributes_pass_redacts_direct_producers(
99139913 },
99149914 ),
99159915 )
9916- await asyncio . sleep ( 0.01 )
9916+ await plugin . flush ( )
99179917 log_entry = await _get_captured_event_dict_async (
99189918 mock_write_client , dummy_arrow_schema
99199919 )
@@ -10460,20 +10460,21 @@ async def fake_lazy_setup(**kwargs):
1046010460
1046110461 def run_in_fresh_loop ():
1046210462 try :
10463- with mock .patch .object (
10464- plugin , "_lazy_setup" , side_effect = fake_lazy_setup
10465- ):
10466- asyncio .run (plugin ._ensure_started ())
10463+ asyncio .run (plugin ._ensure_started ())
1046710464 except BaseException as e : # noqa: BLE001 - collecting for assertion
1046810465 errors .append (e )
1046910466
10470- threads = [
10471- platform_thread .create_thread (run_in_fresh_loop ) for _ in range (2 )
10472- ]
10473- for t in threads :
10474- t .start ()
10475- for t in threads :
10476- t .join (timeout = 10 )
10467+ # Patch from this thread only. patch.object swaps a single shared
10468+ # attribute and is not itself thread safe, so entering it from both
10469+ # threads raced on _lazy_setup instead of on the code under test.
10470+ with mock .patch .object (plugin , "_lazy_setup" , side_effect = fake_lazy_setup ):
10471+ threads = [
10472+ platform_thread .create_thread (run_in_fresh_loop ) for _ in range (2 )
10473+ ]
10474+ for t in threads :
10475+ t .start ()
10476+ for t in threads :
10477+ t .join (timeout = 10 )
1047710478 assert not errors , f"cross-loop startup raised: { errors } "
1047810479
1047910480 def test_concurrent_stale_cleanup_folds_once (
@@ -10593,24 +10594,27 @@ async def slow_setup(**kwargs):
1059310594
1059410595 def run_in_fresh_loop ():
1059510596 try :
10596- with mock .patch .object (plugin , "_lazy_setup" , side_effect = slow_setup ):
10597- barrier .wait (timeout = 5 )
10598- asyncio .run (plugin ._ensure_started ())
10597+ barrier .wait (timeout = 5 )
10598+ asyncio .run (plugin ._ensure_started ())
1059910599 except BaseException as e : # noqa: BLE001
1060010600 errors .append (e )
1060110601
10602- threads = [
10603- platform_thread .create_thread (run_in_fresh_loop ) for _ in range (2 )
10604- ]
10605- for t in threads :
10606- t .start ()
10607- # Deterministic rendezvous: hold the owner inside setup until BOTH
10608- # threads have entered _ensure_started.
10609- entered .wait (timeout = 5 )
10610- release .set ()
10611- for t in threads :
10612- t .join (timeout = 10 )
10613- assert not t .is_alive (), "thread failed to terminate"
10602+ # Patch from this thread only. patch.object swaps a single shared
10603+ # attribute and is not itself thread safe, so entering it from both
10604+ # threads raced on _lazy_setup instead of on the code under test.
10605+ with mock .patch .object (plugin , "_lazy_setup" , side_effect = slow_setup ):
10606+ threads = [
10607+ platform_thread .create_thread (run_in_fresh_loop ) for _ in range (2 )
10608+ ]
10609+ for t in threads :
10610+ t .start ()
10611+ # Deterministic rendezvous: hold the owner inside setup until BOTH
10612+ # threads have entered _ensure_started.
10613+ entered .wait (timeout = 5 )
10614+ release .set ()
10615+ for t in threads :
10616+ t .join (timeout = 10 )
10617+ assert not t .is_alive (), "thread failed to terminate"
1061410618
1061510619 assert not errors , f"cross-loop startup raised: { errors } "
1061610620 assert len (setup_calls ) == 1 , f"shared setup ran { len (setup_calls )} times"
@@ -10697,7 +10701,7 @@ async def test_namedtuple_attribute_does_not_drop_row(
1069710701 extra_attributes = {"point" : Point (1 , 2 )},
1069810702 ),
1069910703 )
10700- await asyncio . sleep ( 0.01 )
10704+ await plugin . flush ( )
1070110705 log_entry = await _get_captured_event_dict_async (
1070210706 mock_write_client , dummy_arrow_schema
1070310707 )
@@ -10786,7 +10790,7 @@ async def test_depth_capped_payload_flags_row_truncated(
1078610790 extra_attributes = {"deep" : deep },
1078710791 ),
1078810792 )
10789- await asyncio . sleep ( 0.01 )
10793+ await plugin . flush ( )
1079010794 log_entry = await _get_captured_event_dict_async (
1079110795 mock_write_client , dummy_arrow_schema
1079210796 )
0 commit comments