@@ -610,3 +610,105 @@ def notify_host_list_changed(self, changes: Dict[str, Set[HostEvent]]):
610610 def notify_connection_changed (self , changes : Set [ConnectionEvent ]) -> OldConnectionSuggestedAction :
611611 self ._calls .append (type (self ).__name__ + ":notify_connection_changed" )
612612 raise AwsWrapperError ()
613+
614+
615+ def test_default_plugin_excluded_from_is_subscribed (mocker , mock_telemetry_factory ):
616+ # DefaultPlugin subscribes to "*", but it must not mark a method as subscribed on its own --
617+ # otherwise the direct-call bypass in _execute_with_subscribed_plugins is unreachable.
618+ mocker .patch .object (PluginManager , "__init__" , lambda w , x , y , z : None )
619+ manager = PluginManager (mocker .MagicMock (), mocker .MagicMock (), mocker .MagicMock ())
620+ manager ._plugins = [DefaultPlugin (mocker .MagicMock (), mocker .MagicMock ())]
621+ manager ._telemetry_factory = mock_telemetry_factory
622+
623+ assert not manager ._make_pipeline (DbApiMethod .CURSOR_EXECUTE .method_name ).is_subscribed
624+ assert not manager ._make_pipeline (DbApiMethod .CONNECT .method_name ).is_subscribed
625+
626+ # A real subscribing plugin still sets the flag, and only for the methods it subscribes to.
627+ manager ._plugins = [TestPluginTwo ([]), DefaultPlugin (mocker .MagicMock (), mocker .MagicMock ())]
628+ assert manager ._make_pipeline (DbApiMethodTest .TEST_CALL_A .method_name ).is_subscribed
629+ assert not manager ._make_pipeline (DbApiMethod .CURSOR_FETCHALL .method_name ).is_subscribed
630+
631+
632+ def test_unsubscribed_method_bypasses_pipeline (mocker , container , mock_telemetry_factory ):
633+ # With only DefaultPlugin in the chain, a non-network-bound method skips the pipeline entirely
634+ # but must still refresh the cached in-transaction state.
635+ calls = []
636+ container .plugin_service .is_network_bound_method .side_effect = \
637+ lambda name : name == DbApiMethod .CURSOR_EXECUTE .method_name
638+ container .plugin_service .update_in_transaction .side_effect = \
639+ lambda * args : calls .append ("update_in_transaction" )
640+ container .plugin_service .driver_dialect .execute .side_effect = \
641+ lambda method_name , func , * args , ** kwargs : (calls .append ("dialect.execute" ), func ())[1 ]
642+
643+ mocker .patch .object (PluginManager , "__init__" , lambda w , x , y , z : None )
644+ manager = PluginManager (mocker .MagicMock (), mocker .MagicMock (), mocker .MagicMock ())
645+ manager ._plugins = [DefaultPlugin (container .plugin_service , mocker .MagicMock ())]
646+ manager ._container = container
647+ manager ._telemetry_factory = mock_telemetry_factory
648+ manager ._telemetry_factory .open_telemetry_context .return_value = None
649+ manager ._telemetry_in_use = False
650+ manager ._function_cache = [None ] * (DbApiMethod .ALL .id + 1 )
651+
652+ def _execute (method ):
653+ return manager ._execute_with_subscribed_plugins (
654+ method ,
655+ lambda plugin , next_func : plugin .execute (mocker .MagicMock (), method .method_name , next_func ),
656+ lambda : (calls .append ("target" ), "result_value" )[1 ])
657+
658+ # Not network bound -> bypass, no DriverDialect.execute, transaction state still updated.
659+ assert _execute (DbApiMethod .CURSOR_LASTROWID ) == "result_value"
660+ assert calls == ["target" , "update_in_transaction" ]
661+
662+ # Network bound -> stays on the pipeline so the socket timeout guard is preserved.
663+ calls .clear ()
664+ assert _execute (DbApiMethod .CURSOR_EXECUTE ) == "result_value"
665+ assert calls == ["dialect.execute" , "target" , "update_in_transaction" ]
666+
667+ # Telemetry on -> back on the pipeline even for the otherwise-bypassable method, so the
668+ # per-plugin NESTED spans are still emitted.
669+ calls .clear ()
670+ manager ._telemetry_in_use = True
671+ manager ._function_cache = [None ] * (DbApiMethod .ALL .id + 1 )
672+ assert _execute (DbApiMethod .CURSOR_LASTROWID ) == "result_value"
673+ assert calls == ["dialect.execute" , "target" , "update_in_transaction" ]
674+
675+
676+ def test_must_use_pipeline (mocker , container , mock_telemetry_factory ):
677+ # must_use_pipeline is the single authority for the bypass decision, so each term matters.
678+ container .plugin_service .is_network_bound_method .side_effect = \
679+ lambda name : name == DbApiMethod .CURSOR_EXECUTE .method_name
680+
681+ mocker .patch .object (PluginManager , "__init__" , lambda w , x , y , z : None )
682+ manager = PluginManager (mocker .MagicMock (), mocker .MagicMock (), mocker .MagicMock ())
683+ manager ._plugins = [DefaultPlugin (container .plugin_service , mocker .MagicMock ())]
684+ manager ._container = container
685+ manager ._telemetry_factory = mock_telemetry_factory
686+ manager ._telemetry_in_use = False
687+ manager ._function_cache = [None ] * (DbApiMethod .ALL .id + 1 )
688+
689+ # Chain not built yet -> nothing to decide on, so the pipeline is required.
690+ assert manager .must_use_pipeline (DbApiMethod .CURSOR_LASTROWID )
691+
692+ # Built, unsubscribed, not network bound, telemetry off -> bypass allowed.
693+ manager ._function_cache [DbApiMethod .CURSOR_LASTROWID .id ] = \
694+ manager ._make_pipeline (DbApiMethod .CURSOR_LASTROWID .method_name )
695+ assert not manager .must_use_pipeline (DbApiMethod .CURSOR_LASTROWID )
696+
697+ # always_use_pipeline and network-bound methods are always required.
698+ assert manager .must_use_pipeline (DbApiMethod .CONNECT )
699+ manager ._function_cache [DbApiMethod .CURSOR_EXECUTE .id ] = \
700+ manager ._make_pipeline (DbApiMethod .CURSOR_EXECUTE .method_name )
701+ assert manager .must_use_pipeline (DbApiMethod .CURSOR_EXECUTE )
702+
703+ # Telemetry re-enables the pipeline for the otherwise-bypassable method.
704+ manager ._telemetry_in_use = True
705+ assert manager .must_use_pipeline (DbApiMethod .CURSOR_LASTROWID )
706+
707+ # A real subscribed plugin also forces the pipeline.
708+ subscriber = mocker .MagicMock ()
709+ subscriber .subscribed_methods = {DbApiMethod .CURSOR_LASTROWID .method_name }
710+ manager ._plugins = [subscriber , DefaultPlugin (container .plugin_service , mocker .MagicMock ())]
711+ manager ._telemetry_in_use = False
712+ manager ._function_cache [DbApiMethod .CURSOR_LASTROWID .id ] = \
713+ manager ._make_pipeline (DbApiMethod .CURSOR_LASTROWID .method_name )
714+ assert manager .must_use_pipeline (DbApiMethod .CURSOR_LASTROWID )
0 commit comments