Skip to content

Commit b71c371

Browse files
Add Python Test Suite (#437)
* Add Python Test Suite * Fix coderabbitai suggestions --------- Co-authored-by: Vaibhav Jain <vajain@redhat.com>
1 parent f4ec852 commit b71c371

8 files changed

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"id": "1",
3+
"modelName": "python",
4+
"modelVersion": "1",
5+
"outputs": [
6+
{
7+
"datatype": "FP32",
8+
"name": "OUTPUT0",
9+
"shape": [
10+
"4"
11+
]
12+
},
13+
{
14+
"datatype": "FP32",
15+
"name": "OUTPUT1",
16+
"shape": [
17+
"4"
18+
]
19+
}
20+
],
21+
"rawOutputContents": [
22+
"AgAAAAAAAAAAAAAAAAAAAA==",
23+
"AAQAAAAAAAAAAAAAAAAAAA=="
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"model_name": "python",
3+
"model_version": "1",
4+
"outputs": [
5+
{
6+
"data": [
7+
0.921442985534668,
8+
0.6223347187042236,
9+
0.8059385418891907,
10+
1.2578542232513428
11+
],
12+
"datatype": "FP32",
13+
"name": "OUTPUT0",
14+
"shape": [
15+
4
16+
]
17+
},
18+
{
19+
"data": [
20+
0.49091365933418274,
21+
-0.027157962322235107,
22+
-0.5641784071922302,
23+
0.6906309723854065
24+
],
25+
"datatype": "FP32",
26+
"name": "OUTPUT1",
27+
"shape": [
28+
4
29+
]
30+
}
31+
]
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"id": "1",
3+
"modelName": "python",
4+
"modelVersion": "1",
5+
"outputs": [
6+
{
7+
"datatype": "FP32",
8+
"name": "OUTPUT0",
9+
"shape": [
10+
"4"
11+
]
12+
},
13+
{
14+
"datatype": "FP32",
15+
"name": "OUTPUT1",
16+
"shape": [
17+
"4"
18+
]
19+
}
20+
],
21+
"rawOutputContents": [
22+
"AgAAAAAAAAAAAAAAAAAAAA==",
23+
"AAQAAAAAAAAAAAAAAAAAAA=="
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"model_name": "python",
3+
"model_version": "1",
4+
"outputs": [
5+
{
6+
"data": [
7+
0.921442985534668,
8+
0.6223347187042236,
9+
0.8059385418891907,
10+
1.2578542232513428
11+
],
12+
"datatype": "FP32",
13+
"name": "OUTPUT0",
14+
"shape": [
15+
4
16+
]
17+
},
18+
{
19+
"data": [
20+
0.49091365933418274,
21+
-0.027157962322235107,
22+
-0.5641784071922302,
23+
0.6906309723854065
24+
],
25+
"datatype": "FP32",
26+
"name": "OUTPUT1",
27+
"shape": [
28+
4
29+
]
30+
}
31+
]
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"1","model_name":"python","model_version":"1","inputs":[{"name":"INPUT0","shape":[4],"datatype":"FP32"},{"name":"INPUT1","shape":[4],"datatype":"FP32"}],"outputs":[{"name":"OUTPUT0"},{"name":"OUTPUT1"}],"raw_input_contents":["AQIAAAAAAAAAAAAAAAAAAA==","/wEAgAAAAAAAAAAAAAAAAA=="]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"inputs":[{"name":"INPUT0","shape":[4],"datatype":"FP32","data":[0.7061783075332642,0.29758837819099426,0.12088008970022202,0.974242627620697]},{"name":"INPUT1","shape":[4],"datatype":"FP32","data":[0.21526464819908142,0.32474634051322937,0.6850584745407104,0.2836116552352905]}]}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""
2+
Test module for Python model served by Triton via KServe.
3+
4+
Validates inference using REST and gRPC protocols with both raw and serverless deployment modes.
5+
"""
6+
7+
from typing import Any
8+
9+
import pytest
10+
from ocp_resources.inference_service import InferenceService
11+
from ocp_resources.pod import Pod
12+
from simple_logger.logger import get_logger
13+
14+
from utilities.constants import Protocols
15+
from tests.model_serving.model_runtime.triton.basic_model_deployment.utils import validate_inference_request, load_json
16+
from tests.model_serving.model_runtime.triton.constant import (
17+
BASE_RAW_DEPLOYMENT_CONFIG,
18+
BASE_SERVERLESS_DEPLOYMENT_CONFIG,
19+
MODEL_PATH_PREFIX,
20+
TRITON_GRPC_PYTHON_INPUT_PATH,
21+
TRITON_REST_PYTHON_INPUT_PATH,
22+
)
23+
24+
LOGGER = get_logger(name=__name__)
25+
26+
PYTHON_MODEL_NAME = "python"
27+
28+
MODEL_STORAGE_URI_DICT = {"model-dir": f"{MODEL_PATH_PREFIX}"}
29+
30+
pytestmark = pytest.mark.usefixtures(
31+
"root_dir", "valid_aws_config", "triton_rest_serving_runtime_template", "triton_grpc_serving_runtime_template"
32+
)
33+
34+
35+
@pytest.mark.parametrize(
36+
("protocol", "model_namespace", "s3_models_storage_uri", "triton_serving_runtime", "triton_inference_service"),
37+
[
38+
pytest.param(
39+
{"protocol_type": Protocols.REST},
40+
{"name": "python-raw"},
41+
MODEL_STORAGE_URI_DICT,
42+
{**BASE_RAW_DEPLOYMENT_CONFIG},
43+
{
44+
"name": "python-raw-rest",
45+
**BASE_RAW_DEPLOYMENT_CONFIG,
46+
},
47+
id="python-raw-rest-deployment",
48+
),
49+
pytest.param(
50+
{"protocol_type": Protocols.GRPC},
51+
{"name": "python-raw"},
52+
MODEL_STORAGE_URI_DICT,
53+
{**BASE_RAW_DEPLOYMENT_CONFIG},
54+
{
55+
"name": "python-raw-grpc",
56+
**BASE_RAW_DEPLOYMENT_CONFIG,
57+
},
58+
id="python-raw-grpc-deployment",
59+
),
60+
pytest.param(
61+
{"protocol_type": Protocols.REST},
62+
{"name": "python-serverless"},
63+
MODEL_STORAGE_URI_DICT,
64+
{**BASE_SERVERLESS_DEPLOYMENT_CONFIG},
65+
{
66+
"name": "python-serverless-rest",
67+
**BASE_SERVERLESS_DEPLOYMENT_CONFIG,
68+
},
69+
id="python-serverless-rest-deployment",
70+
),
71+
pytest.param(
72+
{"protocol_type": Protocols.GRPC},
73+
{"name": "python-serverless"},
74+
MODEL_STORAGE_URI_DICT,
75+
{**BASE_SERVERLESS_DEPLOYMENT_CONFIG},
76+
{
77+
"name": "python-serverless-grpc",
78+
**BASE_SERVERLESS_DEPLOYMENT_CONFIG,
79+
},
80+
id="python-serverless-grpc-deployment",
81+
),
82+
],
83+
indirect=True,
84+
)
85+
class TestPythonModel:
86+
"""
87+
Test class for python inference using Triton on KServe.
88+
89+
Covers:
90+
- REST and gRPC protocols
91+
- Raw and serverless modes
92+
- Snapshot validation of inference results
93+
"""
94+
95+
def test_python_inference(
96+
self,
97+
triton_inference_service: InferenceService,
98+
triton_pod_resource: Pod,
99+
triton_response_snapshot: Any,
100+
protocol: str,
101+
root_dir: str,
102+
) -> None:
103+
"""
104+
Run inference and validate against snapshot.
105+
106+
Args:
107+
triton_inference_service: The deployed InferenceService object
108+
triton_pod_resource: The pod running the model server
109+
triton_response_snapshot: Expected response snapshot
110+
protocol: REST or gRPC
111+
root_dir: Root directory for test execution
112+
"""
113+
input_path = TRITON_GRPC_PYTHON_INPUT_PATH if protocol == Protocols.GRPC else TRITON_REST_PYTHON_INPUT_PATH
114+
input_query = load_json(path=input_path)
115+
116+
validate_inference_request(
117+
pod_name=triton_pod_resource.name,
118+
isvc=triton_inference_service,
119+
response_snapshot=triton_response_snapshot,
120+
input_query=input_query,
121+
model_name=PYTHON_MODEL_NAME,
122+
protocol=protocol,
123+
root_dir=root_dir,
124+
)

tests/model_serving/model_runtime/triton/constant.py

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

1313
TRITON_REST_ONNX_INPUT_PATH = os.path.join(TRITON_INPUT_BASE_PATH, "kserve-triton-onnx-rest-input.json")
1414
TRITON_GRPC_ONNX_INPUT_PATH = os.path.join(TRITON_INPUT_BASE_PATH, "kserve-triton-onnx-gRPC-input.json")
15+
TRITON_REST_PYTHON_INPUT_PATH = os.path.join(TRITON_INPUT_BASE_PATH, "kserve-triton-python-rest-input.json")
16+
TRITON_GRPC_PYTHON_INPUT_PATH = os.path.join(TRITON_INPUT_BASE_PATH, "kserve-triton-python-gRPC-input.json")
1517

1618
LOCAL_HOST_URL: str = "http://localhost"
1719
TRITON_REST_PORT: int = 8080

0 commit comments

Comments
 (0)