@@ -74,8 +74,12 @@ def test_healthcheck_transport_failure(client):
7474
7575
7676@pytest .mark .parametrize ("verify_ssl" , [True , False ])
77- def test_make_request_verify_ssl_true_by_default (config , verify_ssl ):
78- """Verifies SSL setting is passed through to the `requests` call."""
77+ def test_session_verify_reflects_config (config , verify_ssl ):
78+ """
79+ `verify_ssl` is applied to the client's `requests.Session` once at construction.
80+
81+ Every outgoing call then inherits it without per-call boilerplate.
82+ """
7983 config_with_ssl = DataMasqueInstanceConfig (
8084 base_url = config .base_url ,
8185 username = config .username ,
@@ -84,24 +88,14 @@ def test_make_request_verify_ssl_true_by_default(config, verify_ssl):
8488 )
8589 client = DataMasqueClient (config_with_ssl )
8690
87- with patch (
88- "datamasque.client.base.requests.request" ,
89- return_value = make_ok_response (),
90- ) as mock_request :
91- client .make_request ("GET" , "/api/test/" )
92-
93- _ , kwargs = mock_request .call_args
94- assert kwargs ["verify" ] is verify_ssl
91+ assert client ._session .verify is verify_ssl
9592
9693
9794def test_make_request_verify_ssl_true_does_not_touch_global_warning_filter (client ):
9895 """With `verify_ssl=True`, the client should not modify `warnings.filters`."""
9996 filters_before = list (warnings .filters )
10097
101- with patch (
102- "datamasque.client.base.requests.request" ,
103- return_value = make_ok_response (),
104- ):
98+ with patch .object (client ._session , "request" , return_value = make_ok_response ()):
10599 client .make_request ("GET" , "/api/test/" )
106100
107101 assert warnings .filters == filters_before
@@ -125,10 +119,7 @@ def raise_insecure_warning_then_respond(*_args, **_kwargs):
125119
126120 with warnings .catch_warnings (record = True ) as captured :
127121 warnings .simplefilter ("always" ) # ensure we'd otherwise see the warning
128- with patch (
129- "datamasque.client.base.requests.request" ,
130- side_effect = raise_insecure_warning_then_respond ,
131- ):
122+ with patch .object (client ._session , "request" , side_effect = raise_insecure_warning_then_respond ):
132123 client .make_request ("GET" , "/api/test/" )
133124
134125 # The warning raised inside the request call was suppressed by the client.
@@ -289,6 +280,37 @@ def test_token_source_called_again_on_401_retry():
289280 assert client .token == "Token t2"
290281
291282
283+ def test_401_does_not_retry_when_requires_authorization_is_false (client ):
284+ """
285+ A 401 on an anonymous request must surface as-is, not trigger a re-auth retry.
286+
287+ `/api/users/admin-install/` returns 401 once any user exists -- the endpoint
288+ is gated on "no user has been created yet" and DRF treats it as a normal
289+ auth-required endpoint thereafter. Re-authing on that 401 would both
290+ misdiagnose the failure ("login credentials are correct") and waste a
291+ round-trip on a call the caller said doesn't need auth.
292+ """
293+ with requests_mock .Mocker () as m :
294+ m .post (
295+ "http://test-server/api/users/admin-install/" ,
296+ status_code = 401 ,
297+ json = {"detail" : "Authentication credentials were not provided." },
298+ )
299+
300+ with pytest .raises (DataMasqueApiError ) as excinfo :
301+ client .make_request (
302+ "POST" ,
303+ "/api/users/admin-install/" ,
304+ data = {"email" : "x@y" , "username" : "x" , "password" : "p" , "re_password" : "p" , "allowed_hosts" : []},
305+ requires_authorization = False ,
306+ )
307+
308+ assert excinfo .value .response .status_code == 401
309+ # Exactly one request: no re-auth roundtrip to /api/auth/token/login/ and no replay.
310+ assert m .call_count == 1
311+ assert m .request_history [0 ].path == "/api/users/admin-install/"
312+
313+
292314def test_token_source_callable_exception_propagates ():
293315 """Errors from `token_source` are surfaced to the caller, not swallowed."""
294316
0 commit comments