1515from botocore .config import Config
1616from botocore .exceptions import ClientError
1717
18- PREVIEW_URL = os .environ .get ("PREVIEW_URL" , "" )
18+ PREVIEW_URL = os .environ .get ("PREVIEW_URL" , "http://localhost:8787 " )
1919
2020
2121def assume_role (role_arn : str , oidc_token : str ) -> dict :
@@ -60,6 +60,12 @@ def s3_client(creds: dict):
6060 )
6161
6262
63+ requires_oidc = pytest .mark .skipif (
64+ not os .environ .get ("ACTIONS_ID_TOKEN_REQUEST_TOKEN" ),
65+ reason = "ACTIONS_ID_TOKEN_REQUEST_TOKEN not set" ,
66+ )
67+
68+
6369@pytest .fixture (scope = "module" )
6470def oidc_token () -> str :
6571 """Fetch a GitHub Actions OIDC token."""
@@ -85,6 +91,7 @@ def no_access_credentials(oidc_token):
8591 return assume_role ("github-actions-no-access" , oidc_token )
8692
8793
94+ @requires_oidc
8895class TestAssumeRole :
8996 def test_assume_role_returns_credentials (self , actions_credentials ):
9097 assert actions_credentials ["AccessKeyId" ]
@@ -97,6 +104,7 @@ def test_assume_no_access_role_returns_credentials(self, no_access_credentials):
97104 assert no_access_credentials ["SessionToken" ]
98105
99106
107+ @requires_oidc
100108class TestS3Access :
101109 def test_list_bucket_with_access (self , actions_credentials ):
102110 client = s3_client (actions_credentials )
@@ -108,3 +116,43 @@ def test_list_bucket_denied_without_access(self, no_access_credentials):
108116 with pytest .raises (ClientError ) as exc_info :
109117 client .list_objects_v2 (Bucket = "cholmes" , MaxKeys = 5 )
110118 assert exc_info .value .response ["Error" ]["Code" ] == "AccessDenied"
119+
120+
121+ # Public bucket + key used for range request tests.
122+ RANGE_TEST_PATH = "/harvard-lil/gov-data/README.md"
123+
124+
125+ class TestRangeRequests :
126+ """Verify range request headers on GET and HEAD responses."""
127+
128+ def test_get_range_returns_206 (self ):
129+ resp = requests .get (
130+ f"{ PREVIEW_URL } { RANGE_TEST_PATH } " ,
131+ headers = {"Range" : "bytes=0-10" },
132+ )
133+ assert resp .status_code == 206
134+ assert resp .headers .get ("content-range" ) is not None
135+ assert resp .headers ["content-range" ].startswith ("bytes 0-10/" )
136+ assert resp .headers ["content-length" ] == "11"
137+ assert resp .headers .get ("accept-ranges" ) == "bytes"
138+
139+ def test_head_includes_accept_ranges (self ):
140+ resp = requests .head (f"{ PREVIEW_URL } { RANGE_TEST_PATH } " )
141+ assert resp .status_code == 200
142+ assert resp .headers .get ("accept-ranges" ) == "bytes"
143+ assert int (resp .headers ["content-length" ]) > 0
144+
145+ def test_head_range_returns_206 (self ):
146+ resp = requests .head (
147+ f"{ PREVIEW_URL } { RANGE_TEST_PATH } " ,
148+ headers = {"Range" : "bytes=0-10" },
149+ )
150+ assert resp .status_code == 206
151+ assert resp .headers .get ("content-range" ) is not None
152+ assert resp .headers ["content-range" ].startswith ("bytes 0-10/" )
153+ assert resp .headers ["content-length" ] == "11"
154+
155+ def test_get_without_range_returns_200 (self ):
156+ resp = requests .head (f"{ PREVIEW_URL } { RANGE_TEST_PATH } " )
157+ assert resp .status_code == 200
158+ assert "content-range" not in resp .headers
0 commit comments