From 0df92e953f6a1f544a9558b8408367882a9353f6 Mon Sep 17 00:00:00 2001 From: Swati Mukund Bagal Date: Fri, 27 Mar 2026 07:26:13 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20update=20MaaS=20tests=20for=20subscripti?= =?UTF-8?q?on=20binding=20and=20fix=20gateway=20500=20e=E2=80=A6=20(#1303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: update MaaS tests for subscription binding and fix gateway 500 error Signed-off-by: Swati Mukund Bagal * address review comment Signed-off-by: Swati Mukund Bagal --------- Signed-off-by: Swati Mukund Bagal --- .../maas_subscription/conftest.py | 58 +++++++++++++++++++ .../test_maas_auth_enforcement.py | 18 +++--- .../test_maas_sub_enforcement.py | 13 +++-- .../maas_billing/maas_subscription/utils.py | 24 +++++++- 4 files changed, 99 insertions(+), 14 deletions(-) diff --git a/tests/model_serving/maas_billing/maas_subscription/conftest.py b/tests/model_serving/maas_billing/maas_subscription/conftest.py index a050ebfe7..994febe0d 100644 --- a/tests/model_serving/maas_billing/maas_subscription/conftest.py +++ b/tests/model_serving/maas_billing/maas_subscription/conftest.py @@ -203,6 +203,64 @@ def maas_headers_for_actor_api_key(maas_api_key_for_actor: str) -> dict[str, str return build_maas_headers(token=maas_api_key_for_actor) +@pytest.fixture(scope="class") +def api_key_bound_to_free_subscription( + request_session_http: requests.Session, + base_url: str, + ocp_token_for_actor: str, + maas_subscription_tinyllama_free: MaaSSubscription, + maas_subscription_controller_enabled_latest: None, + maas_gateway_api: None, + maas_api_gateway_reachable: None, +) -> Generator[str, Any, Any]: + """ + API key bound to the free subscription at mint time. Revoked on teardown. + """ + _, body = create_api_key( + base_url=base_url, + ocp_user_token=ocp_token_for_actor, + request_session_http=request_session_http, + api_key_name=f"e2e-auth-enforce-{generate_random_name()}", + subscription=maas_subscription_tinyllama_free.name, + ) + yield body["key"] + revoke_api_key( + request_session_http=request_session_http, + base_url=base_url, + key_id=body["id"], + ocp_user_token=ocp_token_for_actor, + ) + + +@pytest.fixture(scope="class") +def api_key_bound_to_premium_subscription( + request_session_http: requests.Session, + base_url: str, + ocp_token_for_actor: str, + maas_subscription_tinyllama_premium: MaaSSubscription, + maas_subscription_controller_enabled_latest: None, + maas_gateway_api: None, + maas_api_gateway_reachable: None, +) -> Generator[str, Any, Any]: + """ + API key bound to the premium subscription at mint time. Revoked on teardown. + """ + _, body = create_api_key( + base_url=base_url, + ocp_user_token=ocp_token_for_actor, + request_session_http=request_session_http, + api_key_name=f"e2e-sub-enforce-{generate_random_name()}", + subscription=maas_subscription_tinyllama_premium.name, + ) + yield body["key"] + revoke_api_key( + request_session_http=request_session_http, + base_url=base_url, + key_id=body["id"], + ocp_user_token=ocp_token_for_actor, + ) + + @pytest.fixture(scope="class") def maas_wrong_group_service_account_token( maas_api_server_url: str, diff --git a/tests/model_serving/maas_billing/maas_subscription/test_maas_auth_enforcement.py b/tests/model_serving/maas_billing/maas_subscription/test_maas_auth_enforcement.py index fdb67649d..dbcd72fbc 100644 --- a/tests/model_serving/maas_billing/maas_subscription/test_maas_auth_enforcement.py +++ b/tests/model_serving/maas_billing/maas_subscription/test_maas_auth_enforcement.py @@ -33,18 +33,18 @@ def test_authorized_user_gets_200( self, request_session_http: requests.Session, model_url_tinyllama_free: str, - maas_headers_for_actor_api_key: dict[str, str], + api_key_bound_to_free_subscription: str, ) -> None: - payload = chat_payload_for_url(model_url=model_url_tinyllama_free) - + """ + Verify a free user with a subscription-bound API key can access the free model. + """ resp = poll_expected_status( request_session_http=request_session_http, model_url=model_url_tinyllama_free, - headers=maas_headers_for_actor_api_key, - payload=payload, + headers=build_maas_headers(token=api_key_bound_to_free_subscription), + payload=chat_payload_for_url(model_url=model_url_tinyllama_free), expected_statuses={200}, ) - LOGGER.info(f"test_authorized_user_gets_200 -> POST {model_url_tinyllama_free} returned {resp.status_code}") assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text[:200]}" @@ -99,10 +99,12 @@ def test_wrong_group_sa_denied_on_premium_model( model_url=model_url_tinyllama_premium, headers=maas_headers_for_wrong_group_sa, payload=payload, - expected_statuses={403}, + expected_statuses={401}, ) LOGGER.info( "test_wrong_group_sa_denied_on_premium_model -> " f"POST {model_url_tinyllama_premium} returned {resp.status_code}" ) - assert resp.status_code == 403, f"Expected 403, got {resp.status_code}: {resp.text[:200]}" + assert resp.status_code == 401, ( + f"Expected 401 (SA token not authenticated as MaaS user), got {resp.status_code}: {resp.text[:200]}" + ) diff --git a/tests/model_serving/maas_billing/maas_subscription/test_maas_sub_enforcement.py b/tests/model_serving/maas_billing/maas_subscription/test_maas_sub_enforcement.py index 025c4a4c0..a48590e66 100644 --- a/tests/model_serving/maas_billing/maas_subscription/test_maas_sub_enforcement.py +++ b/tests/model_serving/maas_billing/maas_subscription/test_maas_sub_enforcement.py @@ -4,7 +4,10 @@ import requests from simple_logger.logger import get_logger -from tests.model_serving.maas_billing.maas_subscription.utils import chat_payload_for_url +from tests.model_serving.maas_billing.maas_subscription.utils import ( + chat_payload_for_url, +) +from tests.model_serving.maas_billing.utils import build_maas_headers LOGGER = get_logger(name=__name__) @@ -31,18 +34,20 @@ def test_subscribed_user_gets_200( self, request_session_http: requests.Session, model_url_tinyllama_premium: str, - maas_headers_for_actor_api_key: dict[str, str], + api_key_bound_to_premium_subscription: str, ) -> None: + """ + Verify a premium user with a subscription-bound API key can access the premium model. + """ resp = request_session_http.post( url=model_url_tinyllama_premium, - headers=maas_headers_for_actor_api_key, + headers=build_maas_headers(token=api_key_bound_to_premium_subscription), json=chat_payload_for_url(model_url=model_url_tinyllama_premium), timeout=60, ) LOGGER.info(f"test_subscribed_user_gets_200 -> {resp.status_code}") assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text[:200]}" - @pytest.mark.tier1 @pytest.mark.parametrize("ocp_token_for_actor", [{"type": "premium"}], indirect=True) def test_explicit_subscription_header_works( self, diff --git a/tests/model_serving/maas_billing/maas_subscription/utils.py b/tests/model_serving/maas_billing/maas_subscription/utils.py index 33bcab56d..e2221a265 100644 --- a/tests/model_serving/maas_billing/maas_subscription/utils.py +++ b/tests/model_serving/maas_billing/maas_subscription/utils.py @@ -185,28 +185,48 @@ def create_api_key( request_session_http: requests.Session, api_key_name: str, request_timeout_seconds: int = 60, + expires_in: str | None = None, + raise_on_error: bool = True, + subscription: str | None = None, ) -> tuple[Response, dict[str, Any]]: """ Create an API key via MaaS API and return (response, parsed_body). Uses ocp_user_token for auth against maas-api. Expects plaintext key in body["key"] (sk-...). + + Args: + expires_in: Optional expiration duration string (e.g. "24h", "720h"). + When None, no expiresIn field is sent and the key does not expire. + raise_on_error: When True (default), raises AssertionError for non-200/201 + responses. Set to False when testing error cases (e.g. 400 rejection). + subscription: Optional MaaSSubscription name to bind at mint time. + When provided, the key is bound to this subscription for inference. + When None, the API auto-selects the highest-priority subscription. """ api_keys_url = f"{base_url}/v1/api-keys" + payload: dict[str, Any] = {"name": api_key_name} + if expires_in is not None: + payload["expiresIn"] = expires_in + if subscription is not None: + payload["subscription"] = subscription + response = request_session_http.post( url=api_keys_url, headers={ "Authorization": f"Bearer {ocp_user_token}", "Content-Type": "application/json", }, - json={"name": api_key_name}, + json=payload, timeout=request_timeout_seconds, ) LOGGER.info(f"create_api_key: url={api_keys_url} status={response.status_code}") if response.status_code not in (200, 201): - raise AssertionError(f"api-key create failed: status={response.status_code}") + if raise_on_error: + raise AssertionError(f"api-key create failed: status={response.status_code}") + return response, {} try: parsed_body: dict[str, Any] = json.loads(response.text)