33from __future__ import annotations
44
55import asyncio
6- import os
76from unittest import mock
87
98import httpx
9+ import pytest
1010
1111from dataretrieval .utils import (
12- _AUTHORIZED_API_KEY_HOST ,
1312 HTTPX_ASYNC_DEFAULTS ,
1413 _default_headers ,
1514 _get ,
@@ -21,79 +20,70 @@ class TestDefaultHeadersHostScoping:
2120
2221 FAKE_TOKEN = "test-fake-token-abc123"
2322
23+ @pytest .fixture (autouse = True )
24+ def _api_token (self , monkeypatch : pytest .MonkeyPatch ) -> None :
25+ """Install one harmless token for every host-scoping behavior test."""
26+ monkeypatch .setenv ("API_USGS_PAT" , self .FAKE_TOKEN )
27+
2428 def test_key_included_for_waterdata_host (self ):
2529 """Key IS added when target URL matches api.waterdata.usgs.gov."""
2630 url = "https://api.waterdata.usgs.gov/ogcapi/v0/collections/daily/items"
27- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
28- headers = _default_headers (url )
31+ headers = _default_headers (url )
2932 assert headers .get ("X-Api-Key" ) == self .FAKE_TOKEN
3033
3134 def test_key_excluded_for_external_host (self ):
3235 """Key is NOT added for an external (non-USGS) host."""
3336 url = "https://nwis.waterservices.usgs.gov/nwis/iv/"
34- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
35- headers = _default_headers (url )
37+ headers = _default_headers (url )
3638 assert "X-Api-Key" not in headers
3739
3840 def test_key_excluded_for_wateruse_host (self ):
3941 """Key is NOT added for the NWDC water-use host (api.water.usgs.gov)."""
4042 url = "https://api.water.usgs.gov/nwaa-data/data"
41- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
42- headers = _default_headers (url )
43+ headers = _default_headers (url )
4344 assert "X-Api-Key" not in headers
4445
4546 def test_key_excluded_for_rating_asset_host (self ):
4647 """Key is NOT added for rating asset downloads (S3/external)."""
4748 url = "https://labs.waterdata.usgs.gov/sta/v1.1/Datastreams(123)/rating.rdb"
48- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
49- headers = _default_headers (url )
49+ headers = _default_headers (url )
5050 assert "X-Api-Key" not in headers
5151
5252 def test_key_excluded_for_lookalike_host (self ):
5353 """Key is NOT sent to a typosquatting/lookalike domain."""
5454 url = "https://api.waterdata.usgs.gov.evil.com/ogcapi/v0/daily/items"
55- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
56- headers = _default_headers (url )
55+ headers = _default_headers (url )
5756 assert "X-Api-Key" not in headers
5857
5958 def test_key_excluded_when_no_url_provided (self ):
6059 """Key is NOT added when target_url is None (legacy callers)."""
61- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
62- headers = _default_headers (None )
60+ headers = _default_headers (None )
6361 assert "X-Api-Key" not in headers
6462
65- def test_key_excluded_when_no_token_set (self ):
63+ def test_key_excluded_when_no_token_set (
64+ self , monkeypatch : pytest .MonkeyPatch
65+ ) -> None :
6666 """No key header at all when API_USGS_PAT is not set."""
67- with mock .patch .dict (os .environ , {}, clear = True ):
68- # Ensure the env var is absent
69- os .environ .pop ("API_USGS_PAT" , None )
70- headers = _default_headers ("https://api.waterdata.usgs.gov/ogcapi/v0/daily" )
67+ monkeypatch .delenv ("API_USGS_PAT" )
68+ headers = _default_headers ("https://api.waterdata.usgs.gov/ogcapi/v0/daily" )
7169 assert "X-Api-Key" not in headers
7270
7371 def test_non_auth_headers_always_present (self ):
7472 """User-Agent, Accept, Accept-Encoding, lang are always present."""
7573 url = "https://example.com/any"
76- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
77- headers = _default_headers (url )
74+ headers = _default_headers (url )
7875 assert "User-Agent" in headers
7976 assert "Accept" in headers
8077 assert "Accept-Encoding" in headers
8178 assert "lang" in headers
8279 # Key should NOT be sent to example.com
8380 assert "X-Api-Key" not in headers
8481
85- def test_authorized_host_constant (self ):
86- """The authorized host constant is correct."""
87- assert _AUTHORIZED_API_KEY_HOST == "api.waterdata.usgs.gov"
88-
8982 def test_generic_ogc_request_excludes_key_for_custom_host (self ):
9083 """A caller-supplied OGC base URL never inherits Water Data auth."""
9184 from dataretrieval .ogc .requests import _construct_api_requests , _ogc_base_url
9285
93- with (
94- mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }),
95- _ogc_base_url ("https://features.example.org/ogcapi" ),
96- ):
86+ with _ogc_base_url ("https://features.example.org/ogcapi" ):
9787 request = _construct_api_requests ("things" )
9888 assert "X-Api-Key" not in request .headers
9989
@@ -107,7 +97,6 @@ def test_rating_download_scopes_headers_to_asset_url(self):
10797 feature = {"id" : "site.rdb" , "assets" : {"data" : {"href" : asset_url }}}
10898 response = mock .Mock (text = "rating body" )
10999 with (
110- mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }),
111100 mock .patch .object (ratings , "_get" , return_value = response ) as get ,
112101 mock .patch .object (ratings , "_raise_for_non_200" ),
113102 mock .patch .object (ratings , "read_rdb" , return_value = pd .DataFrame ()),
@@ -133,13 +122,12 @@ def handler(request: httpx.Request) -> httpx.Response:
133122 return httpx .Response (200 , request = request )
134123
135124 url = "https://api.waterdata.usgs.gov/start"
136- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
137- _get (
138- url ,
139- headers = _default_headers (url ),
140- follow_redirects = True ,
141- transport = httpx .MockTransport (handler ),
142- )
125+ _get (
126+ url ,
127+ headers = _default_headers (url ),
128+ follow_redirects = True ,
129+ transport = httpx .MockTransport (handler ),
130+ )
143131
144132 assert seen [0 ].headers .get ("X-Api-Key" ) == self .FAKE_TOKEN
145133 assert "X-Api-Key" not in seen [1 ].headers
@@ -166,8 +154,7 @@ async def run() -> None:
166154 ) as client :
167155 await client .get (url , headers = _default_headers (url ))
168156
169- with mock .patch .dict (os .environ , {"API_USGS_PAT" : self .FAKE_TOKEN }):
170- asyncio .run (run ())
157+ asyncio .run (run ())
171158
172159 assert seen [0 ].headers .get ("X-Api-Key" ) == self .FAKE_TOKEN
173160 assert "X-Api-Key" not in seen [1 ].headers
0 commit comments