@@ -731,3 +731,132 @@ def test_ssl_context_with_all_ssl_options(mock_pool_manager, mock_create_context
731731 call_kwargs = mock_pool_manager .call_args [1 ]
732732 assert call_kwargs ["ssl_context" ] == mock_ssl_context
733733 assert call_kwargs ["maxsize" ] == 8
734+
735+
736+ def test_request_does_not_clear_pool_after_request ():
737+ """Ensure request() does not call close()/pool_manager.clear() after each request,
738+ so pooled connections are preserved for reuse."""
739+ mock_config = MagicMock (
740+ spec = [
741+ "verify_ssl" ,
742+ "ssl_ca_cert" ,
743+ "cert_file" ,
744+ "key_file" ,
745+ "assert_hostname" ,
746+ "retries" ,
747+ "socket_options" ,
748+ "connection_pool_maxsize" ,
749+ "timeout_millisec" ,
750+ "proxy" ,
751+ "proxy_headers" ,
752+ ]
753+ )
754+ mock_config .ssl_ca_cert = None
755+ mock_config .cert_file = None
756+ mock_config .key_file = None
757+ mock_config .verify_ssl = True
758+ mock_config .connection_pool_maxsize = 4
759+ mock_config .timeout_millisec = 5000
760+ mock_config .proxy = None
761+ mock_config .proxy_headers = None
762+
763+ client = RESTClientObject (configuration = mock_config )
764+ mock_pool_manager = MagicMock ()
765+ client .pool_manager = mock_pool_manager
766+
767+ mock_raw_response = MagicMock ()
768+ mock_raw_response .status = 200
769+ mock_raw_response .reason = "OK"
770+ mock_raw_response .data = b'{"ok":true}'
771+
772+ mock_pool_manager .request .return_value = mock_raw_response
773+
774+ # Make multiple requests
775+ client .request (method = "GET" , url = "http://example.com" , _preload_content = True )
776+ client .request (method = "GET" , url = "http://example.com" , _preload_content = True )
777+
778+ # pool_manager.clear() should never have been called
779+ mock_pool_manager .clear .assert_not_called ()
780+
781+
782+ def test_request_closes_response_on_error ():
783+ """Ensure that if handle_response_exception raises, the raw response is closed
784+ so the connection is not leaked from the pool."""
785+ mock_config = MagicMock (
786+ spec = [
787+ "verify_ssl" ,
788+ "ssl_ca_cert" ,
789+ "cert_file" ,
790+ "key_file" ,
791+ "assert_hostname" ,
792+ "retries" ,
793+ "socket_options" ,
794+ "connection_pool_maxsize" ,
795+ "timeout_millisec" ,
796+ "proxy" ,
797+ "proxy_headers" ,
798+ ]
799+ )
800+ mock_config .ssl_ca_cert = None
801+ mock_config .cert_file = None
802+ mock_config .key_file = None
803+ mock_config .verify_ssl = True
804+ mock_config .connection_pool_maxsize = 4
805+ mock_config .timeout_millisec = 5000
806+ mock_config .proxy = None
807+ mock_config .proxy_headers = None
808+
809+ client = RESTClientObject (configuration = mock_config )
810+ mock_pool_manager = MagicMock ()
811+ client .pool_manager = mock_pool_manager
812+
813+ mock_raw_response = MagicMock ()
814+ mock_raw_response .status = 500
815+ mock_raw_response .reason = "Internal Server Error"
816+ mock_raw_response .data = b'{"error":"something went wrong"}'
817+ mock_raw_response .getheaders .return_value = {}
818+
819+ mock_pool_manager .request .return_value = mock_raw_response
820+
821+ with pytest .raises (ServiceException ):
822+ client .request (method = "GET" , url = "http://example.com" , _preload_content = True )
823+
824+ # Verify raw_response.close() was called to release the connection
825+ mock_raw_response .close .assert_called_once ()
826+
827+
828+ def test_api_client_close_calls_rest_client_close ():
829+ """Ensure the sync ApiClient.close() delegates to rest_client.close()
830+ so pooled connections are cleaned up at shutdown."""
831+ from openfga_sdk .configuration import Configuration
832+ from openfga_sdk .sync .api_client import ApiClient
833+
834+ configuration = Configuration (
835+ api_url = "http://api.fga.example" ,
836+ )
837+
838+ api_client = ApiClient (configuration )
839+ mock_rest_client = MagicMock ()
840+ api_client .rest_client = mock_rest_client
841+
842+ api_client .close ()
843+
844+ mock_rest_client .close .assert_called_once ()
845+
846+
847+ def test_api_client_context_manager_calls_close ():
848+ """Ensure the sync ApiClient context manager calls close() on exit,
849+ which in turn cleans up the REST client's connection pool."""
850+ from openfga_sdk .configuration import Configuration
851+ from openfga_sdk .sync .api_client import ApiClient
852+
853+ configuration = Configuration (
854+ api_url = "http://api.fga.example" ,
855+ )
856+
857+ with ApiClient (configuration ) as api_client :
858+ mock_rest_client = MagicMock ()
859+ api_client .rest_client = mock_rest_client
860+
861+ # After exiting the context manager, close() should have been called
862+ mock_rest_client .close .assert_called_once ()
0 commit comments