Skip to content

Commit 0f6a46e

Browse files
authored
Merge branch 'main' into hf_dup_model
2 parents 527dc66 + 5e62a40 commit 0f6a46e

File tree

9 files changed

+334
-107
lines changed

9 files changed

+334
-107
lines changed

CONSTITUTION.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ All code MUST consider security implications.
7979
- Avoid running destructive commands without explicit user confirmation
8080
- Use detect-secrets and gitleaks pre-commit hooks to prevent secret leakage
8181
- Test code MUST NOT introduce vulnerabilities into the tested systems
82+
- JIRA ticket links are allowed in PRs and commit messages (our Jira is public)
83+
- Do NOT reference internal-only resources (Jenkins, Confluence, Slack threads) in code, PRs, or commit messages
84+
- Do NOT link embargoed or security-restricted (RH-employee-only) tickets
8285

83-
**Rationale**: Tests interact with production-like clusters; security lapses can have real consequences.
86+
**Rationale**: Tests interact with production-like clusters; security lapses can have real consequences. This is a public repository — only reference publicly accessible resources.
8487

8588
## Test Development Standards
8689

tests/llama_stack/conftest.py

Lines changed: 27 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77
from _pytest.fixtures import FixtureRequest
88
from kubernetes.dynamic import DynamicClient
9-
from llama_stack_client import LlamaStackClient
9+
from llama_stack_client import APIError, LlamaStackClient
1010
from llama_stack_client.types.vector_store import VectorStore
1111
from ocp_resources.data_science_cluster import DataScienceCluster
1212
from ocp_resources.deployment import Deployment
@@ -73,59 +73,6 @@
7373
distribution_name = generate_random_name(prefix="llama-stack-distribution")
7474

7575

76-
def _cleanup_s3_files(
77-
bucket_name: str,
78-
endpoint_url: str,
79-
region: str,
80-
access_key_id: str,
81-
secret_access_key: str,
82-
) -> None:
83-
"""
84-
Clean up files from S3 bucket that were uploaded during tests.
85-
86-
Args:
87-
bucket_name: S3 bucket name
88-
endpoint_url: S3 endpoint URL
89-
region: S3 region
90-
access_key_id: AWS access key ID
91-
secret_access_key: AWS secret access key
92-
"""
93-
94-
try:
95-
import boto3
96-
from botocore.exceptions import ClientError
97-
98-
s3_client = boto3.client(
99-
service_name="s3",
100-
endpoint_url=endpoint_url,
101-
aws_access_key_id=access_key_id,
102-
aws_secret_access_key=secret_access_key,
103-
region_name=region,
104-
)
105-
106-
response = s3_client.list_objects_v2(Bucket=bucket_name)
107-
108-
if "Contents" not in response:
109-
LOGGER.info("No files found to clean up from S3")
110-
return
111-
112-
# We only want to delete files that start with "file-"
113-
for obj in response["Contents"]:
114-
key = obj["Key"]
115-
if key.startswith("file-"):
116-
s3_client.delete_object(Bucket=bucket_name, Key=key)
117-
LOGGER.debug(f"Deleted file from S3: {key}")
118-
119-
response = s3_client.list_objects_v2(Bucket=bucket_name)
120-
121-
if "Contents" not in response:
122-
LOGGER.info("No files found to clean up from S3")
123-
return
124-
125-
except ClientError as e:
126-
LOGGER.warning(f"Failed to clean up S3 files: {e}")
127-
128-
12976
@pytest.fixture(scope="class")
13077
def enabled_llama_stack_operator(dsc_resource: DataScienceCluster) -> Generator[DataScienceCluster, Any, Any]:
13178
with update_components_in_dsc(
@@ -385,11 +332,6 @@ def unprivileged_llama_stack_distribution(
385332
enabled_llama_stack_operator: DataScienceCluster,
386333
request: FixtureRequest,
387334
llama_stack_server_config: dict[str, Any],
388-
ci_s3_bucket_name: str,
389-
ci_s3_bucket_endpoint: str,
390-
ci_s3_bucket_region: str,
391-
aws_access_key_id: str,
392-
aws_secret_access_key: str,
393335
unprivileged_llama_stack_distribution_secret: Secret,
394336
unprivileged_postgres_deployment: Deployment,
395337
unprivileged_postgres_service: Service,
@@ -406,25 +348,6 @@ def unprivileged_llama_stack_distribution(
406348
lls_dist.wait_for_status(status=LlamaStackDistribution.Status.READY, timeout=600)
407349
yield lls_dist
408350

409-
try:
410-
env_vars = llama_stack_server_config.get("containerSpec", {}).get("env", [])
411-
enable_s3 = any(env.get("name") == "ENABLE_S3" and env.get("value") == "s3" for env in env_vars)
412-
413-
if enable_s3:
414-
try:
415-
_cleanup_s3_files(
416-
bucket_name=ci_s3_bucket_name,
417-
endpoint_url=ci_s3_bucket_endpoint,
418-
region=ci_s3_bucket_region,
419-
access_key_id=aws_access_key_id,
420-
secret_access_key=aws_secret_access_key,
421-
)
422-
except Exception as e: # noqa: BLE001
423-
LOGGER.warning(f"Failed to clean up S3 files: {e}")
424-
425-
except Exception as e: # noqa: BLE001
426-
LOGGER.warning(f"Failed to clean up S3 files: {e}")
427-
428351

429352
@pytest.fixture(scope="class")
430353
def llama_stack_distribution(
@@ -433,11 +356,6 @@ def llama_stack_distribution(
433356
enabled_llama_stack_operator: DataScienceCluster,
434357
request: FixtureRequest,
435358
llama_stack_server_config: dict[str, Any],
436-
ci_s3_bucket_name: str,
437-
ci_s3_bucket_endpoint: str,
438-
ci_s3_bucket_region: str,
439-
aws_access_key_id: str,
440-
aws_secret_access_key: str,
441359
llama_stack_distribution_secret: Secret,
442360
postgres_deployment: Deployment,
443361
postgres_service: Service,
@@ -453,25 +371,6 @@ def llama_stack_distribution(
453371
lls_dist.wait_for_status(status=LlamaStackDistribution.Status.READY, timeout=600)
454372
yield lls_dist
455373

456-
try:
457-
env_vars = llama_stack_server_config.get("containerSpec", {}).get("env", [])
458-
enable_s3 = any(env.get("name") == "ENABLE_S3" and env.get("value") == "s3" for env in env_vars)
459-
460-
if enable_s3:
461-
try:
462-
_cleanup_s3_files(
463-
bucket_name=ci_s3_bucket_name,
464-
endpoint_url=ci_s3_bucket_endpoint,
465-
region=ci_s3_bucket_region,
466-
access_key_id=aws_access_key_id,
467-
secret_access_key=aws_secret_access_key,
468-
)
469-
except Exception as e: # noqa: BLE001
470-
LOGGER.warning(f"Failed to clean up S3 files: {e}")
471-
472-
except Exception as e: # noqa: BLE001
473-
LOGGER.warning(f"Failed to clean up S3 files: {e}")
474-
475374

476375
def _get_llama_stack_distribution_deployment(
477376
client: DynamicClient,
@@ -642,11 +541,37 @@ def _create_llama_stack_client(
642541
http_client=http_client,
643542
)
644543
wait_for_llama_stack_client_ready(client=client)
544+
existing_file_ids = {f.id for f in client.files.list().data}
545+
645546
yield client
547+
548+
_cleanup_files(client=client, existing_file_ids=existing_file_ids)
646549
finally:
647550
http_client.close()
648551

649552

553+
def _cleanup_files(client: LlamaStackClient, existing_file_ids: set[str]) -> None:
554+
"""Delete files created during test execution via the LlamaStack files API.
555+
556+
Only deletes files whose IDs were not present before the test ran,
557+
avoiding interference with other test sessions.
558+
559+
Args:
560+
client: The LlamaStackClient used during the test
561+
existing_file_ids: File IDs that existed before the test started
562+
"""
563+
try:
564+
for file in client.files.list().data:
565+
if file.id not in existing_file_ids:
566+
try:
567+
client.files.delete(file_id=file.id)
568+
LOGGER.debug(f"Deleted file: {file.id}")
569+
except APIError as e:
570+
LOGGER.warning(f"Failed to delete file {file.id}: {e}")
571+
except APIError as e:
572+
LOGGER.warning(f"Failed to clean up files: {e}")
573+
574+
650575
@pytest.fixture(scope="class")
651576
def unprivileged_llama_stack_client(
652577
unprivileged_llama_stack_test_route: Route,

tests/model_registry/mcp_servers/search/test_filtering.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class TestMCPServerFiltering:
2424
id="by_provider",
2525
),
2626
pytest.param("tags='math'", 1, CALCULATOR_SERVER_NAME, None, id="by_tags"),
27+
pytest.param("license='BSD 3-Clause'", 1, "file-manager", ("license", "BSD 3-Clause"), id="by_license"),
2728
],
2829
)
2930
def test_filter_by_field(
@@ -35,7 +36,7 @@ def test_filter_by_field(
3536
expected_name: str,
3637
field_check: tuple[str, str] | None,
3738
):
38-
"""TC-API-003, TC-API-005: Test filtering MCP servers by provider and tags."""
39+
"""TC-API-003, TC-API-005, TC-API-009: Test filtering MCP servers by provider, tags, and license."""
3940
response = execute_get_command(
4041
url=f"{mcp_catalog_rest_urls[0]}mcp_servers",
4142
headers=model_registry_rest_headers,

tests/model_registry/mcp_servers/search/test_ordering.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
class TestMCPServerOrdering:
1313
"""RHOAIENG-51584: Tests for MCP server ordering functionality."""
1414

15-
@pytest.mark.xfail(reason="RHOAIENG-52448: sortOrder/orderBy not working, fix in PR #2367")
1615
@pytest.mark.parametrize(
1716
"sort_order",
1817
[

tests/model_serving/model_server/llmd/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ def _create_llmisvc_from_config(
247247
namespace: str,
248248
client: DynamicClient,
249249
service_account: str | None = None,
250+
teardown: bool = True,
250251
) -> Generator[LLMInferenceService, Any]:
251252
"""Create an LLMInferenceService from a config class."""
252253
LOGGER.info(f"\n{config_cls.describe(namespace=namespace)}")
@@ -283,7 +284,7 @@ def _create_llmisvc_from_config(
283284
"namespace": namespace,
284285
"annotations": config_cls.annotations(),
285286
"label": config_cls.labels(),
286-
"teardown": True,
287+
"teardown": teardown,
287288
"model": model,
288289
"replicas": config_cls.replicas,
289290
"router": config_cls.router_config(),

tests/model_serving/model_server/llmd/llmd_configs/config_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class LLMISvcConfig:
1818
container_image = None
1919
template_config_ref = "kserve-config-llm-template"
2020
enable_auth = False
21-
wait_timeout = 180
21+
wait_timeout = 240
2222

2323
@classmethod
2424
def container_resources(cls):

tests/model_serving/model_server/upgrade/conftest.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import yaml
66
from kubernetes.dynamic import DynamicClient
77
from ocp_resources.config_map import ConfigMap
8+
from ocp_resources.gateway import Gateway
89
from ocp_resources.inference_service import InferenceService
10+
from ocp_resources.llm_inference_service import LLMInferenceService
911
from ocp_resources.namespace import Namespace
1012
from ocp_resources.role import Role
1113
from ocp_resources.role_binding import RoleBinding
@@ -23,6 +25,7 @@
2325
ModelVersion,
2426
Protocols,
2527
RuntimeTemplates,
28+
Timeout,
2629
)
2730
from utilities.inference_utils import create_isvc
2831
from utilities.infra import (
@@ -32,6 +35,8 @@
3235
s3_endpoint_secret,
3336
update_configmap_data,
3437
)
38+
from utilities.llmd_constants import KServeGateway, LLMDGateway
39+
from utilities.llmd_utils import create_llmd_gateway
3540
from utilities.logger import RedactedString
3641
from utilities.serving_runtime import ServingRuntimeFromTemplate
3742

@@ -42,6 +47,7 @@
4247
MODEL_CAR_UPGRADE_NAMESPACE = "upgrade-model-car"
4348
METRICS_UPGRADE_NAMESPACE = "upgrade-metrics"
4449
PRIVATE_ENDPOINT_UPGRADE_NAMESPACE = "upgrade-private-endpoint"
50+
LLMD_UPGRADE_NAMESPACE = "upgrade-llmd"
4551
S3_CONNECTION = "upgrade-connection"
4652

4753

@@ -765,3 +771,88 @@ def private_endpoint_inference_service_fixture(
765771
**isvc_kwargs,
766772
) as isvc:
767773
yield isvc
774+
775+
776+
# LLMD Upgrade Fixtures
777+
@pytest.fixture(scope="session")
778+
def llmd_namespace_fixture(
779+
pytestconfig: pytest.Config,
780+
admin_client: DynamicClient,
781+
teardown_resources: bool,
782+
) -> Generator[Namespace, Any, Any]:
783+
"""Namespace for LLMD upgrade tests."""
784+
ns = Namespace(client=admin_client, name=LLMD_UPGRADE_NAMESPACE)
785+
786+
if pytestconfig.option.post_upgrade:
787+
yield ns
788+
ns.clean_up()
789+
else:
790+
with create_ns(
791+
admin_client=admin_client,
792+
name=LLMD_UPGRADE_NAMESPACE,
793+
model_mesh_enabled=False,
794+
add_dashboard_label=True,
795+
teardown=teardown_resources,
796+
) as ns:
797+
yield ns
798+
799+
800+
@pytest.fixture(scope="session")
801+
def llmd_gateway_fixture(
802+
pytestconfig: pytest.Config,
803+
admin_client: DynamicClient,
804+
teardown_resources: bool,
805+
) -> Generator[Gateway, Any, Any]:
806+
"""Shared LLMD Gateway for upgrade tests."""
807+
gateway = Gateway(
808+
client=admin_client,
809+
name=LLMDGateway.DEFAULT_NAME,
810+
namespace=LLMDGateway.DEFAULT_NAMESPACE,
811+
api_group=KServeGateway.API_GROUP,
812+
)
813+
814+
if pytestconfig.option.post_upgrade:
815+
yield gateway
816+
gateway.clean_up()
817+
else:
818+
with create_llmd_gateway(
819+
client=admin_client,
820+
namespace=LLMDGateway.DEFAULT_NAMESPACE,
821+
gateway_class_name=LLMDGateway.DEFAULT_CLASS,
822+
wait_for_condition=True,
823+
timeout=Timeout.TIMEOUT_1MIN,
824+
teardown=teardown_resources,
825+
) as gateway:
826+
yield gateway
827+
828+
829+
@pytest.fixture(scope="session")
830+
def llmd_inference_service_fixture(
831+
pytestconfig: pytest.Config,
832+
admin_client: DynamicClient,
833+
llmd_namespace_fixture: Namespace,
834+
llmd_gateway_fixture: Gateway,
835+
teardown_resources: bool,
836+
) -> Generator[LLMInferenceService, Any, Any]:
837+
"""LLMInferenceService using TinyLlama OCI for upgrade tests."""
838+
from tests.model_serving.model_server.llmd.conftest import _create_llmisvc_from_config
839+
from tests.model_serving.model_server.llmd.llmd_configs import TinyLlamaOciConfig
840+
841+
config_cls = TinyLlamaOciConfig
842+
llmisvc = LLMInferenceService(
843+
client=admin_client,
844+
name=config_cls.name,
845+
namespace=llmd_namespace_fixture.name,
846+
)
847+
848+
if pytestconfig.option.post_upgrade:
849+
yield llmisvc
850+
llmisvc.clean_up()
851+
else:
852+
with _create_llmisvc_from_config(
853+
config_cls=config_cls,
854+
namespace=llmd_namespace_fixture.name,
855+
client=admin_client,
856+
teardown=teardown_resources,
857+
) as llmisvc:
858+
yield llmisvc

0 commit comments

Comments
 (0)