Skip to content

Commit 7ea07f0

Browse files
SB159pre-commit-ci[bot]dbasunag
authored andcommitted
test: add MaaS subscription tests (opendatahub-io#1238)
* test: add MaaS subscription tests Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * address review comments Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> * address review comments Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> --------- Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Debarati Basu-Nag <dbasunag@redhat.com> Signed-off-by: Shehan Saleem <ssaleem@redhat.com>
1 parent 0d7232c commit 7ea07f0

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

tests/model_serving/maas_billing/maas_subscription/conftest.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,67 @@ def premium_system_authenticated_access(
556556
if extra_auth_policy.exists:
557557
LOGGER.info(f"Fixture teardown: ensuring AuthPolicy {extra_auth_policy.name} is removed")
558558
extra_auth_policy.clean_up(wait=True)
559+
560+
561+
@pytest.fixture(scope="function")
562+
def second_free_subscription(
563+
admin_client: DynamicClient,
564+
maas_free_group: str,
565+
maas_model_tinyllama_free: MaaSModelRef,
566+
maas_subscription_tinyllama_free: MaaSSubscription,
567+
) -> Generator[MaaSSubscription, Any, Any]:
568+
"""
569+
Creates a second subscription for maas_free_group on the free model.
570+
Used to simulate an ambiguous subscription selection (two qualifying subscriptions,
571+
no x-maas-subscription header).
572+
"""
573+
with create_maas_subscription(
574+
admin_client=admin_client,
575+
subscription_namespace=maas_subscription_tinyllama_free.namespace,
576+
subscription_name="e2e-second-free-subscription",
577+
owner_group_name=maas_free_group,
578+
model_name=maas_model_tinyllama_free.name,
579+
model_namespace=maas_model_tinyllama_free.namespace,
580+
tokens_per_minute=500,
581+
window="1m",
582+
priority=5,
583+
teardown=True,
584+
wait_for_resource=True,
585+
) as second_subscription:
586+
second_subscription.wait_for_condition(condition="Ready", status="True", timeout=300)
587+
LOGGER.info(
588+
f"Created second free subscription {second_subscription.name} for model {maas_model_tinyllama_free.name}"
589+
)
590+
yield second_subscription
591+
592+
593+
@pytest.fixture(scope="function")
594+
def free_actor_premium_subscription(
595+
admin_client: DynamicClient,
596+
maas_model_tinyllama_premium: MaaSModelRef,
597+
maas_subscription_tinyllama_premium: MaaSSubscription,
598+
) -> Generator[MaaSSubscription, Any, Any]:
599+
"""
600+
Creates a subscription for system:authenticated on the premium model.
601+
Used to verify that having a subscription alone is not sufficient —
602+
the actor must also be listed in the model's MaaSAuthPolicy.
603+
"""
604+
with create_maas_subscription(
605+
admin_client=admin_client,
606+
subscription_namespace=maas_subscription_tinyllama_premium.namespace,
607+
subscription_name="e2e-free-actor-premium-sub",
608+
owner_group_name="system:authenticated",
609+
model_name=maas_model_tinyllama_premium.name,
610+
model_namespace=maas_model_tinyllama_premium.namespace,
611+
tokens_per_minute=100,
612+
window="1m",
613+
priority=0,
614+
teardown=True,
615+
wait_for_resource=True,
616+
) as sub_for_free_actor:
617+
sub_for_free_actor.wait_for_condition(condition="Ready", status="True", timeout=300)
618+
LOGGER.info(
619+
f"Created subscription {sub_for_free_actor.name} for system:authenticated "
620+
f"on premium model {maas_model_tinyllama_premium.name}"
621+
)
622+
yield sub_for_free_actor
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
import requests
5+
from ocp_resources.maas_subscription import MaaSSubscription
6+
from simple_logger.logger import get_logger
7+
8+
from tests.model_serving.maas_billing.maas_subscription.utils import (
9+
chat_payload_for_url,
10+
poll_expected_status,
11+
)
12+
13+
LOGGER = get_logger(name=__name__)
14+
15+
16+
@pytest.mark.usefixtures(
17+
"maas_unprivileged_model_namespace",
18+
"maas_subscription_controller_enabled_latest",
19+
"maas_gateway_api",
20+
"maas_api_gateway_reachable",
21+
"maas_inference_service_tinyllama_free",
22+
"maas_model_tinyllama_free",
23+
"maas_auth_policy_tinyllama_free",
24+
"maas_subscription_tinyllama_free",
25+
)
26+
class TestMultipleSubscriptionsNoHeader:
27+
"""
28+
Validates that a token qualifying for multiple subscriptions on the same model
29+
is denied when no x-maas-subscription header is provided to disambiguate.
30+
"""
31+
32+
@pytest.mark.tier1
33+
@pytest.mark.parametrize("ocp_token_for_actor", [{"type": "free"}], indirect=True)
34+
def test_multiple_matching_subscriptions_no_header_gets_403(
35+
self,
36+
request_session_http: requests.Session,
37+
model_url_tinyllama_free: str,
38+
maas_headers_for_actor_api_key: dict[str, str],
39+
second_free_subscription: MaaSSubscription,
40+
) -> None:
41+
"""
42+
Verify that a token qualifying for multiple subscriptions receives 403
43+
when no x-maas-subscription header is provided.
44+
45+
Given two subscriptions for the same model that the free actor qualifies for,
46+
when the actor sends a request without the x-maas-subscription header,
47+
then the request should be denied with 403 because the subscription
48+
selection is ambiguous.
49+
"""
50+
LOGGER.info(
51+
f"Testing: free actor has two subscriptions including '{second_free_subscription.name}' "
52+
f"with no x-maas-subscription header — expecting 403"
53+
)
54+
55+
payload = chat_payload_for_url(model_url=model_url_tinyllama_free)
56+
57+
response = poll_expected_status(
58+
request_session_http=request_session_http,
59+
model_url=model_url_tinyllama_free,
60+
headers=maas_headers_for_actor_api_key,
61+
payload=payload,
62+
expected_statuses={403},
63+
)
64+
65+
assert response.status_code == 403, (
66+
f"Expected 403 when multiple subscriptions exist and no header is provided, "
67+
f"got {response.status_code}: {(response.text or '')[:200]}"
68+
)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
import requests
5+
from ocp_resources.maas_subscription import MaaSSubscription
6+
from simple_logger.logger import get_logger
7+
8+
from tests.model_serving.maas_billing.maas_subscription.utils import (
9+
chat_payload_for_url,
10+
poll_expected_status,
11+
)
12+
13+
LOGGER = get_logger(name=__name__)
14+
15+
MAAS_SUBSCRIPTION_HEADER = "x-maas-subscription"
16+
17+
18+
@pytest.mark.usefixtures(
19+
"maas_unprivileged_model_namespace",
20+
"maas_subscription_controller_enabled_latest",
21+
"maas_gateway_api",
22+
"maas_api_gateway_reachable",
23+
"maas_inference_service_tinyllama_premium",
24+
"maas_model_tinyllama_premium",
25+
"maas_auth_policy_tinyllama_premium",
26+
"maas_subscription_tinyllama_premium",
27+
)
28+
class TestSubscriptionWithoutAuthPolicy:
29+
"""
30+
Validates that holding a subscription is not sufficient for model access;
31+
the token must also be listed in a MaaSAuthPolicy for the model.
32+
"""
33+
34+
@pytest.mark.tier1
35+
@pytest.mark.parametrize("ocp_token_for_actor", [{"type": "free"}], indirect=True)
36+
def test_subscription_without_auth_policy_gets_403(
37+
self,
38+
request_session_http: requests.Session,
39+
model_url_tinyllama_premium: str,
40+
maas_headers_for_actor_api_key: dict[str, str],
41+
free_actor_premium_subscription: MaaSSubscription,
42+
) -> None:
43+
"""
44+
Verify that a user with a subscription but without AuthPolicy access
45+
to the model gets 403.
46+
47+
A free user is given a subscription for the premium model,
48+
but since the user is not allowed by the model's MaaSAuthPolicy,
49+
the request should be denied with 403.
50+
"""
51+
LOGGER.info(
52+
f"Testing: free actor has subscription '{free_actor_premium_subscription.name}' "
53+
f"but is NOT in premium MaaSAuthPolicy — expecting 403"
54+
)
55+
56+
headers = dict(maas_headers_for_actor_api_key)
57+
headers[MAAS_SUBSCRIPTION_HEADER] = free_actor_premium_subscription.name
58+
59+
payload = chat_payload_for_url(model_url=model_url_tinyllama_premium)
60+
61+
response = poll_expected_status(
62+
request_session_http=request_session_http,
63+
model_url=model_url_tinyllama_premium,
64+
headers=headers,
65+
payload=payload,
66+
expected_statuses={403},
67+
)
68+
69+
assert response.status_code == 403, (
70+
f"Expected 403 for token with subscription but not in MaaSAuthPolicy, "
71+
f"got {response.status_code}: {(response.text or '')[:200]}"
72+
)

0 commit comments

Comments
 (0)