11"""Tests for OpenAPI spec handling."""
22
3+ import pytest
34from fastapi import FastAPI
45from fastapi .testclient import TestClient
56from utils import AppFactory
@@ -40,7 +41,6 @@ def test_no_private_endpoints(source_api_server: str):
4041 assert "info" in openapi
4142 assert "openapi" in openapi
4243 assert "paths" in openapi
43- # assert "oidcAuth" not in openapi.get("components", {}).get("securitySchemes", {})
4444
4545
4646def test_oidc_in_openapi_spec (source_api : FastAPI , source_api_server : str ):
@@ -59,37 +59,95 @@ def test_oidc_in_openapi_spec(source_api: FastAPI, source_api_server: str):
5959 assert "oidcAuth" in openapi .get ("components" , {}).get ("securitySchemes" , {})
6060
6161
62+ @pytest .mark .parametrize ("compression_type" , ["gzip" , "br" , "deflate" ])
63+ def test_oidc_in_openapi_spec_compressed (
64+ source_api : FastAPI , source_api_server : str , compression_type : str
65+ ):
66+ """When OpenAPI spec endpoint is set, the proxied OpenAPI spec is augmented with oidc details."""
67+ app = app_factory (
68+ upstream_url = source_api_server ,
69+ openapi_spec_endpoint = source_api .openapi_url ,
70+ )
71+ client = TestClient (app )
72+
73+ # Test with gzip acceptance
74+ response = client .get (
75+ source_api .openapi_url , headers = {"Accept-Encoding" : compression_type }
76+ )
77+ assert response .status_code == 200
78+ assert response .headers .get ("content-encoding" ) == compression_type
79+ assert response .headers .get ("content-type" ) == "application/json"
80+ assert response .json ()
81+
82+
6283def test_oidc_in_openapi_spec_private_endpoints (
6384 source_api : FastAPI , source_api_server : str
6485):
6586 """When OpenAPI spec endpoint is set & endpoints are marked private, those endpoints are marked private in the spec."""
6687 private_endpoints = {
6788 # https://github.com/stac-api-extensions/collection-transaction/blob/v1.0.0-beta.1/README.md#methods
89+ r"^/collections$" : ["POST" ],
90+ r"^/collections/([^/]+)$" : ["PUT" , "PATCH" , "DELETE" ],
91+ # https://github.com/stac-api-extensions/transaction/blob/v1.0.0-rc.3/README.md#methods
92+ r"^/collections/([^/]+)/items$" : ["POST" ],
93+ r"^/collections/([^/]+)/items/([^/]+)$" : ["PUT" , "PATCH" , "DELETE" ],
94+ # https://stac-utils.github.io/stac-fastapi/api/stac_fastapi/extensions/third_party/bulk_transactions/#bulktransactionextension
95+ r"^/collections/([^/]+)/bulk_items$" : ["POST" ],
96+ }
97+ app = app_factory (
98+ upstream_url = source_api_server ,
99+ openapi_spec_endpoint = source_api .openapi_url ,
100+ default_public = True ,
101+ private_endpoints = private_endpoints ,
102+ )
103+ client = TestClient (app )
104+
105+ openapi = client .get (source_api .openapi_url ).raise_for_status ().json ()
106+
107+ expected_auth = {
68108 "/collections" : ["POST" ],
69109 "/collections/{collection_id}" : ["PUT" , "PATCH" , "DELETE" ],
70- # https://github.com/stac-api-extensions/transaction/blob/v1.0.0-rc.3/README.md#methods
71110 "/collections/{collection_id}/items" : ["POST" ],
72111 "/collections/{collection_id}/items/{item_id}" : ["PUT" , "PATCH" , "DELETE" ],
73- # https://stac-utils.github.io/stac-fastapi/api/stac_fastapi/extensions/third_party/bulk_transactions/#bulktransactionextension
74112 "/collections/{collection_id}/bulk_items" : ["POST" ],
75113 }
114+ for path , method_config in openapi ["paths" ].items ():
115+ for method , config in method_config .items ():
116+ security = config .get ("security" )
117+ path_in_expected_auth = path in expected_auth
118+ method_in_expected_auth = any (
119+ method .casefold () == m .casefold () for m in expected_auth .get (path , [])
120+ )
121+ if security :
122+ assert path_in_expected_auth
123+ assert method_in_expected_auth
124+ else :
125+ assert not all ([path_in_expected_auth , method_in_expected_auth ])
126+
127+
128+ def test_oidc_in_openapi_spec_public_endpoints (
129+ source_api : FastAPI , source_api_server : str
130+ ):
131+ """When OpenAPI spec endpoint is set & endpoints are marked public, those endpoints are not marked private in the spec."""
132+ public = {r"^/queryables$" : ["GET" ], r"^/api" : ["GET" ]}
76133 app = app_factory (
77134 upstream_url = source_api_server ,
78135 openapi_spec_endpoint = source_api .openapi_url ,
79- private_endpoints = private_endpoints ,
136+ default_public = False ,
137+ public_endpoints = public ,
80138 )
81139 client = TestClient (app )
140+
82141 openapi = client .get (source_api .openapi_url ).raise_for_status ().json ()
83- for path , methods in private_endpoints .items ():
84- for method in methods :
85- openapi_path = openapi ["paths" ].get (path )
86- assert openapi_path , f"Path { path } not found in OpenAPI spec"
87- openapi_path_method = openapi_path .get (method .lower ())
88- assert (
89- openapi_path_method
90- ), f"Method { method .lower ()!r} not found for path { path !r} in OpenAPI spec for path { path } "
91- security = openapi_path_method .get ("security" )
92- assert security , f"Security not found for { path !r} { method .lower ()!r} "
93- assert any (
94- "oidcAuth" in s for s in security
95- ), f'No "oidcAuth" in security for { path !r} { method .lower ()!r} '
142+
143+ expected_auth = {"/queryables" : ["GET" ]}
144+ for path , method_config in openapi ["paths" ].items ():
145+ for method , config in method_config .items ():
146+ security = config .get ("security" )
147+ if security :
148+ assert path not in expected_auth
149+ else :
150+ assert path in expected_auth
151+ assert any (
152+ method .casefold () == m .casefold () for m in expected_auth [path ]
153+ )
0 commit comments