Skip to content

Commit 6fe4677

Browse files
SB159pre-commit-ci[bot]dbasunag
authored
tests(maas): add multiple auth policy and cascade deletion tests (#1220)
* tests(maas): add multiple auth policy and cascade deletion 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 Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> * tests(maas): fix address coderabit review comments Signed-off-by: Swati Mukund Bagal <sbagal@redhat.com> * 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>
1 parent 59e57c4 commit 6fe4677

File tree

3 files changed

+389
-0
lines changed

3 files changed

+389
-0
lines changed

tests/model_serving/maas_billing/maas_subscription/conftest.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
MAAS_DB_NAMESPACE,
2626
MAAS_SUBSCRIPTION_NAMESPACE,
2727
create_api_key,
28+
create_maas_subscription,
2829
get_maas_postgres_resources,
2930
patch_llmisvc_with_maas_router_and_tiers,
3031
wait_for_postgres_connection_log,
@@ -447,3 +448,111 @@ def maas_subscription_namespace(unprivileged_client, admin_client):
447448
admin_client=admin_client,
448449
) as ns:
449450
yield ns
451+
452+
453+
@pytest.fixture(scope="function")
454+
def temporary_system_authenticated_subscription(
455+
admin_client: DynamicClient,
456+
maas_subscription_tinyllama_free: MaaSSubscription,
457+
maas_model_tinyllama_free: MaaSModelRef,
458+
) -> Generator[MaaSSubscription, Any, Any]:
459+
"""
460+
Creates a temporary subscription owned by system:authenticated.
461+
Used for cascade deletion tests.
462+
"""
463+
464+
subscription_name = f"e2e-temp-sub-{generate_random_name()}"
465+
466+
with create_maas_subscription(
467+
admin_client=admin_client,
468+
subscription_namespace=maas_subscription_tinyllama_free.namespace,
469+
subscription_name=subscription_name,
470+
owner_group_name="system:authenticated",
471+
model_name=maas_model_tinyllama_free.name,
472+
model_namespace=maas_model_tinyllama_free.namespace,
473+
tokens_per_minute=50,
474+
window="1m",
475+
priority=0,
476+
teardown=False,
477+
wait_for_resource=True,
478+
) as temporary_subscription:
479+
temporary_subscription.wait_for_condition(
480+
condition="Ready",
481+
status="True",
482+
timeout=300,
483+
)
484+
485+
LOGGER.info(
486+
f"Created temporary subscription {temporary_subscription.name} for model {maas_model_tinyllama_free.name}"
487+
)
488+
489+
yield temporary_subscription
490+
491+
LOGGER.info(f"Fixture teardown: ensuring subscription {temporary_subscription.name} is removed")
492+
temporary_subscription.clean_up(wait=True)
493+
494+
495+
@pytest.fixture(scope="function")
496+
def premium_system_authenticated_access(
497+
admin_client: DynamicClient,
498+
maas_model_tinyllama_premium: MaaSModelRef,
499+
maas_subscription_tinyllama_premium: MaaSSubscription,
500+
) -> Generator[dict[str, Any], Any, Any]:
501+
"""
502+
Creates an extra AuthPolicy and matching subscription for system:authenticated
503+
on the premium model.
504+
"""
505+
506+
auth_policy_name = f"e2e-premium-system-auth-{generate_random_name()}"
507+
subscription_name = f"e2e-premium-system-auth-sub-{generate_random_name()}"
508+
509+
with (
510+
MaaSAuthPolicy(
511+
client=admin_client,
512+
name=auth_policy_name,
513+
namespace=maas_subscription_tinyllama_premium.namespace,
514+
model_refs=[
515+
{
516+
"name": maas_model_tinyllama_premium.name,
517+
"namespace": maas_model_tinyllama_premium.namespace,
518+
}
519+
],
520+
subjects={"groups": [{"name": "system:authenticated"}]},
521+
teardown=False,
522+
wait_for_resource=True,
523+
) as extra_auth_policy,
524+
create_maas_subscription(
525+
admin_client=admin_client,
526+
subscription_namespace=maas_subscription_tinyllama_premium.namespace,
527+
subscription_name=subscription_name,
528+
owner_group_name="system:authenticated",
529+
model_name=maas_model_tinyllama_premium.name,
530+
model_namespace=maas_model_tinyllama_premium.namespace,
531+
tokens_per_minute=100,
532+
window="1m",
533+
priority=0,
534+
teardown=True,
535+
wait_for_resource=True,
536+
) as system_authenticated_subscription,
537+
):
538+
extra_auth_policy.wait_for_condition(condition="Ready", status="True", timeout=300)
539+
system_authenticated_subscription.wait_for_condition(
540+
condition="Ready",
541+
status="True",
542+
timeout=300,
543+
)
544+
545+
LOGGER.info(
546+
f"Created extra AuthPolicy {extra_auth_policy.name} and subscription "
547+
f"{system_authenticated_subscription.name} for premium model "
548+
f"{maas_model_tinyllama_premium.name}"
549+
)
550+
551+
yield {
552+
"auth_policy": extra_auth_policy,
553+
"subscription": system_authenticated_subscription,
554+
}
555+
556+
if extra_auth_policy.exists:
557+
LOGGER.info(f"Fixture teardown: ensuring AuthPolicy {extra_auth_policy.name} is removed")
558+
extra_auth_policy.clean_up(wait=True)
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
import requests
5+
from kubernetes.dynamic import DynamicClient
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+
from utilities.resources.maa_s_subscription import MaaSSubscription
13+
14+
LOGGER = get_logger(name=__name__)
15+
16+
17+
@pytest.mark.usefixtures(
18+
"maas_unprivileged_model_namespace",
19+
"maas_subscription_controller_enabled_latest",
20+
"maas_gateway_api",
21+
"maas_api_gateway_reachable",
22+
"maas_inference_service_tinyllama_free",
23+
"maas_model_tinyllama_free",
24+
"maas_auth_policy_tinyllama_free",
25+
"maas_subscription_tinyllama_free",
26+
)
27+
class TestCascadeDeletion:
28+
"""
29+
Tests that deleting MaaSSubscription CRs triggers proper cleanup/rebuild behavior.
30+
"""
31+
32+
@pytest.mark.tier1
33+
@pytest.mark.parametrize("ocp_token_for_actor", [{"type": "free"}], indirect=True)
34+
def test_delete_subscription_rebuilds_trlp(
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+
temporary_system_authenticated_subscription: MaaSSubscription,
40+
) -> None:
41+
"""
42+
Add a second subscription for the same model, then delete it.
43+
Verify the original subscription still allows access (HTTP 200).
44+
"""
45+
46+
LOGGER.info(f"Deleting temporary subscription {temporary_system_authenticated_subscription.name}")
47+
48+
temporary_system_authenticated_subscription.clean_up(wait=True)
49+
50+
payload = chat_payload_for_url(model_url=model_url_tinyllama_free)
51+
52+
response = poll_expected_status(
53+
request_session_http=request_session_http,
54+
model_url=model_url_tinyllama_free,
55+
headers=maas_headers_for_actor_api_key,
56+
payload=payload,
57+
expected_statuses={200},
58+
wait_timeout=240,
59+
sleep=5,
60+
request_timeout=60,
61+
)
62+
63+
assert response.status_code == 200, (
64+
f"Expected HTTP 200 after deleting temporary subscription and rebuilding policies, "
65+
f"but received {response.status_code}: {(response.text or '')[:200]}"
66+
)
67+
68+
@pytest.mark.tier1
69+
@pytest.mark.parametrize("ocp_token_for_actor", [{"type": "free"}], indirect=True)
70+
def test_delete_last_subscription_denies_access(
71+
self,
72+
request_session_http: requests.Session,
73+
admin_client: DynamicClient,
74+
maas_free_group: str,
75+
maas_model_tinyllama_free,
76+
model_url_tinyllama_free: str,
77+
maas_headers_for_actor_api_key: dict[str, str],
78+
maas_subscription_tinyllama_free: MaaSSubscription,
79+
) -> None:
80+
"""
81+
Delete the only/original subscription for the model.
82+
Verify access is denied with 403 or 429.
83+
84+
Expected behavior:
85+
- 403 if auth policy denies because no valid subscription exists
86+
- 429 if default deny token rate limit policy applies first
87+
88+
Both mean: no subscription => no access.
89+
"""
90+
91+
original_name = maas_subscription_tinyllama_free.name
92+
original_priority = getattr(maas_subscription_tinyllama_free, "priority", 0)
93+
94+
LOGGER.info("Deleting original subscription %s", original_name)
95+
maas_subscription_tinyllama_free.clean_up(wait=True)
96+
97+
payload = chat_payload_for_url(model_url=model_url_tinyllama_free)
98+
99+
try:
100+
response = poll_expected_status(
101+
request_session_http=request_session_http,
102+
model_url=model_url_tinyllama_free,
103+
headers=maas_headers_for_actor_api_key,
104+
payload=payload,
105+
expected_statuses={403, 429},
106+
wait_timeout=120,
107+
sleep=5,
108+
request_timeout=60,
109+
)
110+
111+
LOGGER.info(
112+
"No subscription present for model %s -> received %s as expected",
113+
maas_model_tinyllama_free.name,
114+
response.status_code,
115+
)
116+
117+
assert response.status_code in {403, 429}, (
118+
"Expected 403 or 429 after deleting the last subscription, "
119+
f"got {response.status_code}: {(response.text or '')[:200]}"
120+
)
121+
finally:
122+
restored_subscription = MaaSSubscription(
123+
client=admin_client,
124+
name=original_name,
125+
namespace=maas_subscription_tinyllama_free.namespace,
126+
owner={
127+
"groups": [{"name": maas_free_group}],
128+
},
129+
model_refs=[
130+
{
131+
"name": maas_model_tinyllama_free.name,
132+
"namespace": maas_model_tinyllama_free.namespace,
133+
"tokenRateLimits": [{"limit": 100, "window": "1m"}],
134+
}
135+
],
136+
priority=original_priority,
137+
teardown=False,
138+
wait_for_resource=True,
139+
)
140+
141+
restored_subscription.deploy(wait=True)
142+
143+
restored_subscription.wait_for_condition(
144+
condition="Ready",
145+
status="True",
146+
timeout=300,
147+
)
148+
149+
LOGGER.info("Restored original subscription %s", restored_subscription.name)

0 commit comments

Comments
 (0)