Skip to content

Commit bb642c0

Browse files
NO-SNOW replace os.environ patching with monkeypatch everywhere in unit tests (#2500)
(cherry picked from commit d1d3880)
1 parent 8b20873 commit bb642c0

File tree

4 files changed

+51
-76
lines changed

4 files changed

+51
-76
lines changed

test/unit/test_auth_workload_identity.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
import logging
3-
import os
43
from base64 import b64decode
54
from unittest import mock
65
from urllib.parse import parse_qs, urlparse
@@ -414,11 +413,11 @@ def test_explicit_azure_omits_client_id_if_not_set(fake_azure_metadata_service):
414413
assert fake_azure_metadata_service.requested_client_id is None
415414

416415

417-
def test_explicit_azure_uses_explicit_client_id_if_set(fake_azure_metadata_service):
418-
with mock.patch.dict(
419-
os.environ, {"MANAGED_IDENTITY_CLIENT_ID": "custom-client-id"}
420-
):
421-
auth_class = AuthByWorkloadIdentity(provider=AttestationProvider.AZURE)
422-
auth_class.prepare(conn=None)
416+
def test_explicit_azure_uses_explicit_client_id_if_set(
417+
fake_azure_metadata_service, monkeypatch
418+
):
419+
monkeypatch.setenv("MANAGED_IDENTITY_CLIENT_ID", "custom-client-id")
420+
auth_class = AuthByWorkloadIdentity(provider=AttestationProvider.AZURE)
421+
auth_class.prepare(conn=None)
423422

424423
assert fake_azure_metadata_service.requested_client_id == "custom-client-id"

test/unit/test_connection.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import json
55
import logging
6-
import os
76
import stat
87
import sys
98
from pathlib import Path
@@ -201,11 +200,11 @@ def test_is_still_running():
201200

202201

203202
@pytest.mark.skipolddriver
204-
def test_partner_env_var(mock_post_requests):
203+
def test_partner_env_var(mock_post_requests, monkeypatch):
205204
PARTNER_NAME = "Amanda"
206205

207-
with patch.dict(os.environ, {ENV_VAR_PARTNER: PARTNER_NAME}):
208-
assert fake_connector().application == PARTNER_NAME
206+
monkeypatch.setenv(ENV_VAR_PARTNER, PARTNER_NAME)
207+
assert fake_connector().application == PARTNER_NAME
209208

210209
assert (
211210
mock_post_requests["data"]["CLIENT_ENVIRONMENT"]["APPLICATION"] == PARTNER_NAME

test/unit/test_ocsp.py

Lines changed: 40 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import platform
1111
import time
1212
from concurrent.futures.thread import ThreadPoolExecutor
13-
from os import environ, path
13+
from os import path
1414
from unittest import mock
1515

1616
import asn1crypto.x509
@@ -78,7 +78,7 @@ def overwrite_ocsp_cache(tmpdir):
7878

7979

8080
@pytest.fixture(autouse=True)
81-
def worker_specific_cache_dir(tmpdir, request):
81+
def worker_specific_cache_dir(tmpdir, request, monkeypatch):
8282
"""Create worker-specific cache directory to avoid file lock conflicts in parallel execution.
8383
8484
Note: Tests that explicitly manage their own cache directories (like test_ocsp_cache_when_server_is_down)
@@ -88,13 +88,12 @@ def worker_specific_cache_dir(tmpdir, request):
8888
# Get worker ID for parallel execution (pytest-xdist)
8989
worker_id = os.environ.get("PYTEST_XDIST_WORKER", "master")
9090

91-
# Store original cache dir environment variable
92-
original_cache_dir = os.environ.get("SF_OCSP_RESPONSE_CACHE_DIR")
91+
# monkeypatch will automatically handle restoration
9392

9493
# Set worker-specific cache directory to prevent main cache file conflicts
9594
worker_cache_dir = tmpdir.join(f"ocsp_cache_{worker_id}")
9695
worker_cache_dir.ensure(dir=True)
97-
os.environ["SF_OCSP_RESPONSE_CACHE_DIR"] = str(worker_cache_dir)
96+
monkeypatch.setenv("SF_OCSP_RESPONSE_CACHE_DIR", str(worker_cache_dir))
9897

9998
# Only handle the OCSP_RESPONSE_VALIDATION_CACHE to prevent conflicts
10099
# Let tests manage SF_OCSP_RESPONSE_CACHE_DIR themselves if they need to
@@ -131,11 +130,7 @@ def worker_specific_cache_dir(tmpdir, request):
131130
# If modules not available, just yield the directory
132131
yield str(tmpdir)
133132
finally:
134-
# Restore original cache directory environment variable
135-
if original_cache_dir is not None:
136-
os.environ["SF_OCSP_RESPONSE_CACHE_DIR"] = original_cache_dir
137-
else:
138-
os.environ.pop("SF_OCSP_RESPONSE_CACHE_DIR", None)
133+
# monkeypatch will automatically restore the original environment variable
139134

140135
# Reset cache dir back to original state
141136
try:
@@ -235,7 +230,7 @@ def test_ocsp_wo_cache_server():
235230
assert ocsp.validate(url, connection), f"Failed to validate: {url}"
236231

237232

238-
def test_ocsp_wo_cache_file():
233+
def test_ocsp_wo_cache_file(monkeypatch):
239234
"""OCSP tests without File cache.
240235
241236
Notes:
@@ -248,7 +243,7 @@ def test_ocsp_wo_cache_file():
248243
except FileNotFoundError:
249244
# File doesn't exist, which is fine for this test
250245
pass
251-
environ["SF_OCSP_RESPONSE_CACHE_DIR"] = "/etc"
246+
monkeypatch.setenv("SF_OCSP_RESPONSE_CACHE_DIR", "/etc")
252247
OCSPCache.reset_cache_dir()
253248

254249
try:
@@ -257,11 +252,10 @@ def test_ocsp_wo_cache_file():
257252
connection = _openssl_connect(url)
258253
assert ocsp.validate(url, connection), f"Failed to validate: {url}"
259254
finally:
260-
del environ["SF_OCSP_RESPONSE_CACHE_DIR"]
261255
OCSPCache.reset_cache_dir()
262256

263257

264-
def test_ocsp_fail_open_w_single_endpoint():
258+
def test_ocsp_fail_open_w_single_endpoint(monkeypatch):
265259
SnowflakeOCSP.clear_cache()
266260

267261
try:
@@ -270,33 +264,28 @@ def test_ocsp_fail_open_w_single_endpoint():
270264
# File doesn't exist, which is fine for this test
271265
pass
272266

273-
environ["SF_OCSP_TEST_MODE"] = "true"
274-
environ["SF_TEST_OCSP_URL"] = "http://httpbin.org/delay/10"
275-
environ["SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT"] = "5"
267+
monkeypatch.setenv("SF_OCSP_TEST_MODE", "true")
268+
monkeypatch.setenv("SF_TEST_OCSP_URL", "http://httpbin.org/delay/10")
269+
monkeypatch.setenv("SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT", "5")
276270

277271
ocsp = SFOCSP(use_ocsp_cache_server=False)
278272
connection = _openssl_connect("snowflake.okta.com")
279273

280-
try:
281-
assert ocsp.validate(
282-
"snowflake.okta.com", connection
283-
), "Failed to validate: {}".format("snowflake.okta.com")
284-
finally:
285-
del environ["SF_OCSP_TEST_MODE"]
286-
del environ["SF_TEST_OCSP_URL"]
287-
del environ["SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT"]
274+
assert ocsp.validate(
275+
"snowflake.okta.com", connection
276+
), "Failed to validate: {}".format("snowflake.okta.com")
288277

289278

290279
@pytest.mark.skipif(
291280
ER_OCSP_RESPONSE_CERT_STATUS_REVOKED is None,
292281
reason="No ER_OCSP_RESPONSE_CERT_STATUS_REVOKED is available.",
293282
)
294-
def test_ocsp_fail_close_w_single_endpoint():
283+
def test_ocsp_fail_close_w_single_endpoint(monkeypatch):
295284
SnowflakeOCSP.clear_cache()
296285

297-
environ["SF_OCSP_TEST_MODE"] = "true"
298-
environ["SF_TEST_OCSP_URL"] = "http://httpbin.org/delay/10"
299-
environ["SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT"] = "5"
286+
monkeypatch.setenv("SF_OCSP_TEST_MODE", "true")
287+
monkeypatch.setenv("SF_TEST_OCSP_URL", "http://httpbin.org/delay/10")
288+
monkeypatch.setenv("SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT", "5")
300289

301290
OCSPCache.del_cache_file()
302291

@@ -306,21 +295,16 @@ def test_ocsp_fail_close_w_single_endpoint():
306295
with pytest.raises(RevocationCheckError) as ex:
307296
ocsp.validate("snowflake.okta.com", connection)
308297

309-
try:
310-
assert (
311-
ex.value.errno == ER_OCSP_RESPONSE_FETCH_FAILURE
312-
), "Connection should have failed"
313-
finally:
314-
del environ["SF_OCSP_TEST_MODE"]
315-
del environ["SF_TEST_OCSP_URL"]
316-
del environ["SF_TEST_CA_OCSP_RESPONDER_CONNECTION_TIMEOUT"]
298+
assert (
299+
ex.value.errno == ER_OCSP_RESPONSE_FETCH_FAILURE
300+
), "Connection should have failed"
317301

318302

319-
def test_ocsp_bad_validity():
303+
def test_ocsp_bad_validity(monkeypatch):
320304
SnowflakeOCSP.clear_cache()
321305

322-
environ["SF_OCSP_TEST_MODE"] = "true"
323-
environ["SF_TEST_OCSP_FORCE_BAD_RESPONSE_VALIDITY"] = "true"
306+
monkeypatch.setenv("SF_OCSP_TEST_MODE", "true")
307+
monkeypatch.setenv("SF_TEST_OCSP_FORCE_BAD_RESPONSE_VALIDITY", "true")
324308

325309
try:
326310
OCSPCache.del_cache_file()
@@ -334,12 +318,10 @@ def test_ocsp_bad_validity():
334318
assert ocsp.validate(
335319
"snowflake.okta.com", connection
336320
), "Connection should have passed with fail open"
337-
del environ["SF_OCSP_TEST_MODE"]
338-
del environ["SF_TEST_OCSP_FORCE_BAD_RESPONSE_VALIDITY"]
339321

340322

341-
def test_ocsp_single_endpoint():
342-
environ["SF_OCSP_ACTIVATE_NEW_ENDPOINT"] = "True"
323+
def test_ocsp_single_endpoint(monkeypatch):
324+
monkeypatch.setenv("SF_OCSP_ACTIVATE_NEW_ENDPOINT", "True")
343325
SnowflakeOCSP.clear_cache()
344326
ocsp = SFOCSP()
345327
ocsp.OCSP_CACHE_SERVER.NEW_DEFAULT_CACHE_SERVER_BASE_URL = "https://snowflake.preprod3.us-west-2-dev.external-zone.snowflakecomputing.com:8085/ocsp/"
@@ -348,8 +330,6 @@ def test_ocsp_single_endpoint():
348330
"snowflake.okta.com", connection
349331
), "Failed to validate: {}".format("snowflake.okta.com")
350332

351-
del environ["SF_OCSP_ACTIVATE_NEW_ENDPOINT"]
352-
353333

354334
def test_ocsp_by_post_method():
355335
"""OCSP tests."""
@@ -375,15 +355,17 @@ def test_ocsp_with_file_cache(tmpdir):
375355

376356

377357
@pytest.mark.skipolddriver
378-
def test_ocsp_with_bogus_cache_files(tmpdir, random_ocsp_response_validation_cache):
358+
def test_ocsp_with_bogus_cache_files(
359+
tmpdir, random_ocsp_response_validation_cache, monkeypatch
360+
):
379361
with mock.patch(
380362
"snowflake.connector.ocsp_snowflake.OCSP_RESPONSE_VALIDATION_CACHE",
381363
random_ocsp_response_validation_cache,
382364
):
383365
from snowflake.connector.ocsp_snowflake import OCSPResponseValidationResult
384366

385367
"""Attempts to use bogus OCSP response data."""
386-
cache_file_name, target_hosts = _store_cache_in_file(tmpdir)
368+
cache_file_name, target_hosts = _store_cache_in_file(monkeypatch, tmpdir)
387369

388370
ocsp = SFOCSP()
389371
OCSPCache.read_ocsp_response_cache_file(ocsp, cache_file_name)
@@ -414,15 +396,17 @@ def test_ocsp_with_bogus_cache_files(tmpdir, random_ocsp_response_validation_cac
414396

415397

416398
@pytest.mark.skipolddriver
417-
def test_ocsp_with_outdated_cache(tmpdir, random_ocsp_response_validation_cache):
399+
def test_ocsp_with_outdated_cache(
400+
tmpdir, random_ocsp_response_validation_cache, monkeypatch
401+
):
418402
with mock.patch(
419403
"snowflake.connector.ocsp_snowflake.OCSP_RESPONSE_VALIDATION_CACHE",
420404
random_ocsp_response_validation_cache,
421405
):
422406
from snowflake.connector.ocsp_snowflake import OCSPResponseValidationResult
423407

424408
"""Attempts to use outdated OCSP response cache file."""
425-
cache_file_name, target_hosts = _store_cache_in_file(tmpdir)
409+
cache_file_name, target_hosts = _store_cache_in_file(monkeypatch, tmpdir)
426410

427411
ocsp = SFOCSP()
428412

@@ -452,10 +436,8 @@ def test_ocsp_with_outdated_cache(tmpdir, random_ocsp_response_validation_cache)
452436
), "must be empty. outdated cache should not be loaded"
453437

454438

455-
def _store_cache_in_file(tmpdir, target_hosts=None):
456-
if target_hosts is None:
457-
target_hosts = TARGET_HOSTS
458-
os.environ["SF_OCSP_RESPONSE_CACHE_DIR"] = str(tmpdir)
439+
def _store_cache_in_file(monkeypatch, tmpdir):
440+
monkeypatch.setenv("SF_OCSP_RESPONSE_CACHE_DIR", str(tmpdir))
459441
OCSPCache.reset_cache_dir()
460442
filename = path.join(str(tmpdir), "ocsp_response_cache.json")
461443

@@ -464,13 +446,13 @@ def _store_cache_in_file(tmpdir, target_hosts=None):
464446
ocsp = SFOCSP(
465447
ocsp_response_cache_uri="file://" + filename, use_ocsp_cache_server=False
466448
)
467-
for hostname in target_hosts:
449+
for hostname in TARGET_HOSTS:
468450
connection = _openssl_connect(hostname)
469451
assert ocsp.validate(hostname, connection), "Failed to validate: {}".format(
470452
hostname
471453
)
472454
assert path.exists(filename), "OCSP response cache file"
473-
return filename, target_hosts
455+
return filename, TARGET_HOSTS
474456

475457

476458
def test_ocsp_with_invalid_cache_file():
@@ -658,11 +640,11 @@ def test_building_retry_url():
658640
assert OCSP_SERVER.OCSP_RETRY_URL is None
659641

660642

661-
def test_building_new_retry():
643+
def test_building_new_retry(monkeypatch):
662644
OCSP_SERVER = OCSPServer()
663645
OCSP_SERVER.OCSP_RETRY_URL = None
664646
hname = "a1.us-east-1.snowflakecomputing.com"
665-
os.environ["SF_OCSP_ACTIVATE_NEW_ENDPOINT"] = "true"
647+
monkeypatch.setenv("SF_OCSP_ACTIVATE_NEW_ENDPOINT", "true")
666648
OCSP_SERVER.reset_ocsp_endpoint(hname)
667649
assert (
668650
OCSP_SERVER.CACHE_SERVER_URL
@@ -698,8 +680,6 @@ def test_building_new_retry():
698680
== "https://ocspssd.snowflakecomputing.com/ocsp/retry"
699681
)
700682

701-
del os.environ["SF_OCSP_ACTIVATE_NEW_ENDPOINT"]
702-
703683

704684
@pytest.mark.parametrize(
705685
"hash_algorithm",

test/unit/test_proxies.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from __future__ import annotations
33

44
import logging
5-
import os
65
import unittest.mock
76

87
import pytest
@@ -28,10 +27,10 @@ def test_get_proxy_url():
2827

2928

3029
@pytest.mark.skipolddriver
31-
def test_socks_5_proxy_missing_proxy_header_attribute(caplog):
30+
def test_socks_5_proxy_missing_proxy_header_attribute(caplog, monkeypatch):
3231
from snowflake.connector.vendored.urllib3.poolmanager import ProxyManager
3332

34-
os.environ["HTTPS_PROXY"] = "socks5://localhost:8080"
33+
monkeypatch.setenv("HTTPS_PROXY", "socks5://localhost:8080")
3534

3635
class MockSOCKSProxyManager:
3736
def __init__(self):
@@ -81,8 +80,6 @@ def mock_proxy_manager_for_url_wiht_header(*args, **kwargs):
8180
)
8281
assert "Unable to set 'Host' to proxy manager of type" not in caplog.text
8382

84-
del os.environ["HTTPS_PROXY"]
85-
8683

8784
@pytest.mark.skipolddriver
8885
@pytest.mark.parametrize("proxy_method", ["explicit_args", "env_vars"])

0 commit comments

Comments
 (0)