@@ -10828,6 +10828,63 @@ def test_normalizer_redacts_and_bounds(self):
1082810828 assert out == preserved
1082910829 assert replaced is False
1083010830
10831+ def test_normalizer_preserves_post_normalization_key_collisions (self ):
10832+ """Normalized keys never silently overwrite an earlier value."""
10833+ normalize = bigquery_agent_analytics_plugin ._normalize_json_native
10834+
10835+ unsupported_first , replaced = normalize (
10836+ {object (): "unsupported" , "[UNSUPPORTED_KEY_1]" : "genuine" },
10837+ 10000 ,
10838+ )
10839+ assert unsupported_first == {
10840+ "[UNSUPPORTED_KEY_1]" : "unsupported" ,
10841+ "[KEY_COLLISION_2][UNSUPPORTED_KEY_1]" : "genuine" ,
10842+ }
10843+ assert replaced is True
10844+
10845+ genuine_first , replaced = normalize (
10846+ {"[UNSUPPORTED_KEY_1]" : "genuine" , object (): "unsupported" },
10847+ 10000 ,
10848+ )
10849+ assert genuine_first == {
10850+ "[UNSUPPORTED_KEY_1]" : "genuine" ,
10851+ "[KEY_COLLISION_2][UNSUPPORTED_KEY_1]" : "unsupported" ,
10852+ }
10853+ assert replaced is True
10854+
10855+ marker_reserved , replaced = normalize (
10856+ {
10857+ object (): "unsupported" ,
10858+ "[KEY_COLLISION_2][UNSUPPORTED_KEY_1]" : "reserved" ,
10859+ "[UNSUPPORTED_KEY_1]" : "genuine" ,
10860+ },
10861+ 10000 ,
10862+ )
10863+ assert marker_reserved == {
10864+ "[UNSUPPORTED_KEY_1]" : "unsupported" ,
10865+ "[KEY_COLLISION_2][UNSUPPORTED_KEY_1]" : "reserved" ,
10866+ "[KEY_COLLISION_3][UNSUPPORTED_KEY_1]" : "genuine" ,
10867+ }
10868+ assert replaced is True
10869+
10870+ budget_reserved , replaced = normalize (
10871+ {
10872+ "[SANITIZE_BUDGET_EXCEEDED]" : "reserved" ,
10873+ "[KEY_COLLISION_1][SANITIZE_BUDGET_EXCEEDED]" : "marker" ,
10874+ "omitted" : "value" ,
10875+ },
10876+ 10000 ,
10877+ budget = [3 ],
10878+ )
10879+ assert budget_reserved == {
10880+ "[SANITIZE_BUDGET_EXCEEDED]" : "reserved" ,
10881+ "[KEY_COLLISION_1][SANITIZE_BUDGET_EXCEEDED]" : "marker" ,
10882+ "[KEY_COLLISION_2][SANITIZE_BUDGET_EXCEEDED]" : (
10883+ "[SANITIZE_BUDGET_EXCEEDED]"
10884+ ),
10885+ }
10886+ assert replaced is True
10887+
1083110888 @pytest .mark .asyncio
1083210889 async def test_native_secret_mapping_via_model_field_redacted (
1083310890 self ,
@@ -12822,6 +12879,30 @@ async def blocking_shutdown(timeout=None):
1282212879 assert plugin ._is_shutting_down is False
1282312880 assert loop not in plugin ._loop_state_by_loop
1282412881
12882+ @pytest .mark .asyncio
12883+ async def test_get_loop_state_uses_single_lookup (
12884+ self , mock_auth_default , mock_bq_client
12885+ ):
12886+ """A concurrent removal cannot split an existence check from lookup."""
12887+ _ = mock_auth_default , mock_bq_client
12888+ plugin = bigquery_agent_analytics_plugin .BigQueryAgentAnalyticsPlugin (
12889+ PROJECT_ID , DATASET_ID , table_id = TABLE_ID
12890+ )
12891+ loop = asyncio .get_running_loop ()
12892+ expected_state = mock .MagicMock ()
12893+
12894+ class DeleteOnContainsDict (dict ):
12895+
12896+ def __contains__ (self , key ):
12897+ present = super ().__contains__ (key )
12898+ if present :
12899+ del self [key ]
12900+ return present
12901+
12902+ plugin ._loop_state_by_loop = DeleteOnContainsDict ({loop : expected_state })
12903+
12904+ assert await plugin ._get_loop_state () is expected_state
12905+
1282512906 @pytest .mark .asyncio
1282612907 async def test_writer_built_during_shutdown_is_not_published (
1282712908 self , mock_auth_default , mock_bq_client
0 commit comments