Skip to content

Commit a4e7d67

Browse files
committed
[wip] llamastack tests refactor
evals tests work on lamastack evals tests improve lmeval provider tests guardrails tests [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci wip guardrails move rag tests to llama_stack/ fix guardrails tests add more logging to guardrails tests
1 parent 2f70659 commit a4e7d67

26 files changed

+1685
-1582
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ dependencies = [
7171
"fire",
7272
"llama_stack_client==0.2.17",
7373
"pytest-xdist==3.8.0",
74+
"curlify>=3.0.0",
7475
]
7576

7677
[project.urls]

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161

6262
LOGGER = get_logger(name=__name__)
6363

64+
pytest_plugins = ["tests.fixtures.inference", "tests.fixtures.guardrails", "tests.fixtures.evals"]
65+
6466

6567
@pytest.fixture(scope="session")
6668
def admin_client() -> DynamicClient:

tests/fixtures/evals.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from typing import Generator, Any
2+
3+
import pytest
4+
from kubernetes.dynamic import DynamicClient
5+
from ocp_resources.config_map import ConfigMap
6+
from ocp_resources.deployment import Deployment
7+
from ocp_resources.resource import ResourceEditor
8+
from pytest_testconfig import py_config
9+
10+
from utilities.constants import Annotations
11+
12+
13+
@pytest.fixture(scope="function")
14+
def patched_trustyai_operator_configmap_allow_online(admin_client: DynamicClient) -> Generator[ConfigMap, Any, Any]:
15+
namespace: str = py_config["applications_namespace"]
16+
trustyai_service_operator: str = "trustyai-service-operator"
17+
18+
configmap: ConfigMap = ConfigMap(
19+
client=admin_client, name=f"{trustyai_service_operator}-config", namespace=namespace, ensure_exists=True
20+
)
21+
with ResourceEditor(
22+
patches={
23+
configmap: {
24+
"metadata": {"annotations": {Annotations.OpenDataHubIo.MANAGED: "false"}},
25+
"data": {
26+
"lmes-allow-online": "true",
27+
"lmes-allow-code-execution": "true",
28+
},
29+
}
30+
}
31+
):
32+
deployment: Deployment = Deployment(
33+
client=admin_client,
34+
name=f"{trustyai_service_operator}-controller-manager",
35+
namespace=namespace,
36+
ensure_exists=True,
37+
)
38+
num_replicas: int = deployment.replicas
39+
deployment.scale_replicas(replica_count=0)
40+
deployment.scale_replicas(replica_count=num_replicas)
41+
deployment.wait_for_replicas()
42+
yield configmap

tests/fixtures/guardrails.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from typing import Generator, Any
2+
3+
import pytest
4+
from _pytest.fixtures import FixtureRequest
5+
from kubernetes.dynamic import DynamicClient
6+
from ocp_resources.config_map import ConfigMap
7+
from ocp_resources.deployment import Deployment
8+
from ocp_resources.guardrails_orchestrator import GuardrailsOrchestrator
9+
from ocp_resources.namespace import Namespace
10+
from ocp_resources.pod import Pod
11+
from ocp_resources.route import Route
12+
13+
from utilities.constants import Labels
14+
15+
16+
GUARDRAILS_ORCHESTRATOR_NAME: str = "guardrails-orchestrator"
17+
18+
19+
@pytest.fixture(scope="class")
20+
def guardrails_orchestrator(
21+
request: FixtureRequest,
22+
admin_client: DynamicClient,
23+
model_namespace: Namespace,
24+
orchestrator_config: ConfigMap,
25+
) -> Generator[GuardrailsOrchestrator, Any, Any]:
26+
gorch_kwargs = {
27+
"client": admin_client,
28+
"name": GUARDRAILS_ORCHESTRATOR_NAME,
29+
"namespace": model_namespace.name,
30+
"orchestrator_config": orchestrator_config.name,
31+
"replicas": 1,
32+
"wait_for_resource": True,
33+
}
34+
35+
if enable_built_in_detectors := request.param.get("enable_built_in_detectors"):
36+
gorch_kwargs["enable_built_in_detectors"] = enable_built_in_detectors
37+
38+
if request.param.get("enable_guardrails_gateway"):
39+
guardrails_gateway_config = request.getfixturevalue(argname="guardrails_gateway_config")
40+
gorch_kwargs["enable_guardrails_gateway"] = True
41+
gorch_kwargs["guardrails_gateway_config"] = guardrails_gateway_config.name
42+
43+
with GuardrailsOrchestrator(**gorch_kwargs) as gorch:
44+
gorch_deployment = Deployment(name=gorch.name, namespace=gorch.namespace, wait_for_resource=True)
45+
gorch_deployment.wait_for_replicas()
46+
yield gorch
47+
48+
49+
@pytest.fixture(scope="class")
50+
def orchestrator_config(
51+
request: FixtureRequest, admin_client: DynamicClient, model_namespace: Namespace
52+
) -> Generator[ConfigMap, Any, Any]:
53+
with ConfigMap(
54+
client=admin_client,
55+
name="fms-orchestr8-config-nlp",
56+
namespace=model_namespace.name,
57+
data=request.param["orchestrator_config_data"],
58+
) as cm:
59+
yield cm
60+
61+
62+
@pytest.fixture(scope="class")
63+
def guardrails_gateway_config(
64+
request: FixtureRequest, admin_client: DynamicClient, model_namespace: Namespace
65+
) -> Generator[ConfigMap, Any, Any]:
66+
with ConfigMap(
67+
client=admin_client,
68+
name="fms-orchestr8-config-gateway",
69+
namespace=model_namespace.name,
70+
label={Labels.Openshift.APP: "fmstack-nlp"},
71+
data=request.param["guardrails_gateway_config_data"],
72+
) as cm:
73+
yield cm
74+
75+
76+
@pytest.fixture(scope="class")
77+
def guardrails_orchestrator_pod(
78+
admin_client: DynamicClient,
79+
model_namespace: Namespace,
80+
guardrails_orchestrator: GuardrailsOrchestrator,
81+
) -> Pod:
82+
return list(
83+
Pod.get(
84+
namespace=model_namespace.name, label_selector=f"app.kubernetes.io/instance={GUARDRAILS_ORCHESTRATOR_NAME}"
85+
)
86+
)[0]
87+
88+
89+
@pytest.fixture(scope="class")
90+
def guardrails_orchestrator_route(
91+
admin_client: DynamicClient,
92+
model_namespace: Namespace,
93+
guardrails_orchestrator: GuardrailsOrchestrator,
94+
) -> Generator[Route, Any, Any]:
95+
yield Route(
96+
name=f"{guardrails_orchestrator.name}",
97+
namespace=guardrails_orchestrator.namespace,
98+
wait_for_resource=True,
99+
)
100+
101+
102+
@pytest.fixture(scope="class")
103+
def guardrails_orchestrator_url(
104+
guardrails_orchestrator_route: Route,
105+
) -> str:
106+
return f"https://{guardrails_orchestrator_route.host}"
107+
108+
109+
@pytest.fixture(scope="class")
110+
def guardrails_orchestrator_health_route(
111+
admin_client: DynamicClient,
112+
model_namespace: Namespace,
113+
guardrails_orchestrator: GuardrailsOrchestrator,
114+
) -> Generator[Route, Any, Any]:
115+
yield Route(
116+
name=f"{guardrails_orchestrator.name}-health",
117+
namespace=guardrails_orchestrator.namespace,
118+
wait_for_resource=True,
119+
)

tests/fixtures/inference.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from typing import Generator, Any
2+
3+
import pytest
4+
from kubernetes.dynamic import DynamicClient
5+
from ocp_resources.inference_service import InferenceService
6+
from ocp_resources.namespace import Namespace
7+
from ocp_resources.pod import Pod
8+
from ocp_resources.secret import Secret
9+
from ocp_resources.service import Service
10+
from ocp_resources.serving_runtime import ServingRuntime
11+
12+
from utilities.constants import RuntimeTemplates, KServeDeploymentType
13+
from utilities.inference_utils import create_isvc
14+
from utilities.serving_runtime import ServingRuntimeFromTemplate
15+
16+
17+
@pytest.fixture(scope="class")
18+
def vllm_cpu_runtime(
19+
admin_client: DynamicClient,
20+
model_namespace: Namespace,
21+
minio_pod: Pod,
22+
minio_service: Service,
23+
minio_data_connection: Secret,
24+
) -> Generator[ServingRuntime, Any, Any]:
25+
with ServingRuntimeFromTemplate(
26+
client=admin_client,
27+
name="vllm-runtime-cpu-fp16",
28+
namespace=model_namespace.name,
29+
template_name=RuntimeTemplates.VLLM_CUDA,
30+
deployment_type=KServeDeploymentType.RAW_DEPLOYMENT,
31+
runtime_image="quay.io/rh-aiservices-bu/vllm-cpu-openai-ubi9"
32+
"@sha256:ada6b3ba98829eb81ae4f89364d9b431c0222671eafb9a04aa16f31628536af2",
33+
containers={
34+
"kserve-container": {
35+
"args": [
36+
f"--port={str(8032)}",
37+
"--model=/mnt/models",
38+
],
39+
"ports": [{"containerPort": 8032, "protocol": "TCP"}],
40+
"volumeMounts": [{"mountPath": "/dev/shm", "name": "shm"}],
41+
}
42+
},
43+
volumes=[{"emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}, "name": "shm"}],
44+
) as serving_runtime:
45+
yield serving_runtime
46+
47+
48+
@pytest.fixture(scope="class")
49+
def qwen_isvc(
50+
admin_client: DynamicClient,
51+
model_namespace: Namespace,
52+
minio_pod: Pod,
53+
minio_service: Service,
54+
minio_data_connection: Secret,
55+
vllm_cpu_runtime: ServingRuntime,
56+
) -> Generator[InferenceService, Any, Any]:
57+
with create_isvc(
58+
client=admin_client,
59+
name="qwen-isvc",
60+
namespace=model_namespace.name,
61+
deployment_mode=KServeDeploymentType.RAW_DEPLOYMENT,
62+
model_format="vLLM",
63+
runtime=vllm_cpu_runtime.name,
64+
storage_key=minio_data_connection.name,
65+
storage_path="Qwen2.5-0.5B-Instruct",
66+
wait_for_predictor_pods=False,
67+
resources={
68+
"requests": {"cpu": "1", "memory": "8Gi"},
69+
"limits": {"cpu": "2", "memory": "10Gi"},
70+
},
71+
) as isvc:
72+
yield isvc
73+
74+
75+
@pytest.fixture(scope="class")
76+
def qwen_isvc_url(qwen_isvc: InferenceService) -> str:
77+
return f"http://{qwen_isvc.name}-predictor.{qwen_isvc.namespace}.svc.cluster.local:8032/v1"

0 commit comments

Comments
 (0)