Skip to content

Commit 0df92e9

Browse files
committed
fix: update MaaS tests for subscription binding and fix gateway 500 e… (opendatahub-io#1303)
* fix: update MaaS tests for subscription binding and fix gateway 500 error Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> * address review comment Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> --------- Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com>
1 parent 2e24559 commit 0df92e9

File tree

4 files changed

+99
-14
lines changed

4 files changed

+99
-14
lines changed

tests/model_serving/maas_billing/maas_subscription/conftest.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,64 @@ def maas_headers_for_actor_api_key(maas_api_key_for_actor: str) -> dict[str, str
203203
return build_maas_headers(token=maas_api_key_for_actor)
204204

205205

206+
@pytest.fixture(scope="class")
207+
def api_key_bound_to_free_subscription(
208+
request_session_http: requests.Session,
209+
base_url: str,
210+
ocp_token_for_actor: str,
211+
maas_subscription_tinyllama_free: MaaSSubscription,
212+
maas_subscription_controller_enabled_latest: None,
213+
maas_gateway_api: None,
214+
maas_api_gateway_reachable: None,
215+
) -> Generator[str, Any, Any]:
216+
"""
217+
API key bound to the free subscription at mint time. Revoked on teardown.
218+
"""
219+
_, body = create_api_key(
220+
base_url=base_url,
221+
ocp_user_token=ocp_token_for_actor,
222+
request_session_http=request_session_http,
223+
api_key_name=f"e2e-auth-enforce-{generate_random_name()}",
224+
subscription=maas_subscription_tinyllama_free.name,
225+
)
226+
yield body["key"]
227+
revoke_api_key(
228+
request_session_http=request_session_http,
229+
base_url=base_url,
230+
key_id=body["id"],
231+
ocp_user_token=ocp_token_for_actor,
232+
)
233+
234+
235+
@pytest.fixture(scope="class")
236+
def api_key_bound_to_premium_subscription(
237+
request_session_http: requests.Session,
238+
base_url: str,
239+
ocp_token_for_actor: str,
240+
maas_subscription_tinyllama_premium: MaaSSubscription,
241+
maas_subscription_controller_enabled_latest: None,
242+
maas_gateway_api: None,
243+
maas_api_gateway_reachable: None,
244+
) -> Generator[str, Any, Any]:
245+
"""
246+
API key bound to the premium subscription at mint time. Revoked on teardown.
247+
"""
248+
_, body = create_api_key(
249+
base_url=base_url,
250+
ocp_user_token=ocp_token_for_actor,
251+
request_session_http=request_session_http,
252+
api_key_name=f"e2e-sub-enforce-{generate_random_name()}",
253+
subscription=maas_subscription_tinyllama_premium.name,
254+
)
255+
yield body["key"]
256+
revoke_api_key(
257+
request_session_http=request_session_http,
258+
base_url=base_url,
259+
key_id=body["id"],
260+
ocp_user_token=ocp_token_for_actor,
261+
)
262+
263+
206264
@pytest.fixture(scope="class")
207265
def maas_wrong_group_service_account_token(
208266
maas_api_server_url: str,

tests/model_serving/maas_billing/maas_subscription/test_maas_auth_enforcement.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@ def test_authorized_user_gets_200(
3333
self,
3434
request_session_http: requests.Session,
3535
model_url_tinyllama_free: str,
36-
maas_headers_for_actor_api_key: dict[str, str],
36+
api_key_bound_to_free_subscription: str,
3737
) -> None:
38-
payload = chat_payload_for_url(model_url=model_url_tinyllama_free)
39-
38+
"""
39+
Verify a free user with a subscription-bound API key can access the free model.
40+
"""
4041
resp = poll_expected_status(
4142
request_session_http=request_session_http,
4243
model_url=model_url_tinyllama_free,
43-
headers=maas_headers_for_actor_api_key,
44-
payload=payload,
44+
headers=build_maas_headers(token=api_key_bound_to_free_subscription),
45+
payload=chat_payload_for_url(model_url=model_url_tinyllama_free),
4546
expected_statuses={200},
4647
)
47-
4848
LOGGER.info(f"test_authorized_user_gets_200 -> POST {model_url_tinyllama_free} returned {resp.status_code}")
4949
assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text[:200]}"
5050

@@ -99,10 +99,12 @@ def test_wrong_group_sa_denied_on_premium_model(
9999
model_url=model_url_tinyllama_premium,
100100
headers=maas_headers_for_wrong_group_sa,
101101
payload=payload,
102-
expected_statuses={403},
102+
expected_statuses={401},
103103
)
104104
LOGGER.info(
105105
"test_wrong_group_sa_denied_on_premium_model -> "
106106
f"POST {model_url_tinyllama_premium} returned {resp.status_code}"
107107
)
108-
assert resp.status_code == 403, f"Expected 403, got {resp.status_code}: {resp.text[:200]}"
108+
assert resp.status_code == 401, (
109+
f"Expected 401 (SA token not authenticated as MaaS user), got {resp.status_code}: {resp.text[:200]}"
110+
)

tests/model_serving/maas_billing/maas_subscription/test_maas_sub_enforcement.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import requests
55
from simple_logger.logger import get_logger
66

7-
from tests.model_serving.maas_billing.maas_subscription.utils import chat_payload_for_url
7+
from tests.model_serving.maas_billing.maas_subscription.utils import (
8+
chat_payload_for_url,
9+
)
10+
from tests.model_serving.maas_billing.utils import build_maas_headers
811

912
LOGGER = get_logger(name=__name__)
1013

@@ -31,18 +34,20 @@ def test_subscribed_user_gets_200(
3134
self,
3235
request_session_http: requests.Session,
3336
model_url_tinyllama_premium: str,
34-
maas_headers_for_actor_api_key: dict[str, str],
37+
api_key_bound_to_premium_subscription: str,
3538
) -> None:
39+
"""
40+
Verify a premium user with a subscription-bound API key can access the premium model.
41+
"""
3642
resp = request_session_http.post(
3743
url=model_url_tinyllama_premium,
38-
headers=maas_headers_for_actor_api_key,
44+
headers=build_maas_headers(token=api_key_bound_to_premium_subscription),
3945
json=chat_payload_for_url(model_url=model_url_tinyllama_premium),
4046
timeout=60,
4147
)
4248
LOGGER.info(f"test_subscribed_user_gets_200 -> {resp.status_code}")
4349
assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text[:200]}"
4450

45-
@pytest.mark.tier1
4651
@pytest.mark.parametrize("ocp_token_for_actor", [{"type": "premium"}], indirect=True)
4752
def test_explicit_subscription_header_works(
4853
self,

tests/model_serving/maas_billing/maas_subscription/utils.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,28 +185,48 @@ def create_api_key(
185185
request_session_http: requests.Session,
186186
api_key_name: str,
187187
request_timeout_seconds: int = 60,
188+
expires_in: str | None = None,
189+
raise_on_error: bool = True,
190+
subscription: str | None = None,
188191
) -> tuple[Response, dict[str, Any]]:
189192
"""
190193
Create an API key via MaaS API and return (response, parsed_body).
191194
192195
Uses ocp_user_token for auth against maas-api.
193196
Expects plaintext key in body["key"] (sk-...).
197+
198+
Args:
199+
expires_in: Optional expiration duration string (e.g. "24h", "720h").
200+
When None, no expiresIn field is sent and the key does not expire.
201+
raise_on_error: When True (default), raises AssertionError for non-200/201
202+
responses. Set to False when testing error cases (e.g. 400 rejection).
203+
subscription: Optional MaaSSubscription name to bind at mint time.
204+
When provided, the key is bound to this subscription for inference.
205+
When None, the API auto-selects the highest-priority subscription.
194206
"""
195207
api_keys_url = f"{base_url}/v1/api-keys"
196208

209+
payload: dict[str, Any] = {"name": api_key_name}
210+
if expires_in is not None:
211+
payload["expiresIn"] = expires_in
212+
if subscription is not None:
213+
payload["subscription"] = subscription
214+
197215
response = request_session_http.post(
198216
url=api_keys_url,
199217
headers={
200218
"Authorization": f"Bearer {ocp_user_token}",
201219
"Content-Type": "application/json",
202220
},
203-
json={"name": api_key_name},
221+
json=payload,
204222
timeout=request_timeout_seconds,
205223
)
206224

207225
LOGGER.info(f"create_api_key: url={api_keys_url} status={response.status_code}")
208226
if response.status_code not in (200, 201):
209-
raise AssertionError(f"api-key create failed: status={response.status_code}")
227+
if raise_on_error:
228+
raise AssertionError(f"api-key create failed: status={response.status_code}")
229+
return response, {}
210230

211231
try:
212232
parsed_body: dict[str, Any] = json.loads(response.text)

0 commit comments

Comments
 (0)