Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions tests/model_serving/maas_billing/maas_subscription/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]}"

Expand Down Expand Up @@ -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]}"
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import requests
import structlog

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 = structlog.get_logger(name=__name__)

Expand All @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions tests/model_serving/maas_billing/maas_subscription/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ def create_api_key(
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).
Expand All @@ -199,12 +200,17 @@ def create_api_key(
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,
Expand Down
Loading