Skip to content

Commit b7384fc

Browse files
adolfo-abrnetser
andauthored
feat: Add upgrade tests for TrustyAIService (#250)
* feat: Add upgrade tests for TrustyAIService * Move upgrade README.md to docs/UPGRADE.md * fix: reuse kwargs in TrustyAIService fixture * fix: address comments, reuse kwargs, add docstrings --------- Co-authored-by: Ruth Netser <rnetser@redhat.com>
1 parent 015c19b commit b7384fc

File tree

8 files changed

+278
-132
lines changed

8 files changed

+278
-132
lines changed

tests/model_serving/model_server/upgrade/README.md renamed to docs/UPGRADE.md

File renamed without changes.

tests/conftest.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,29 @@ def current_client_token(admin_client: DynamicClient) -> str:
8383
return get_openshift_token()
8484

8585

86+
@pytest.fixture(scope="session")
87+
def teardown_resources(pytestconfig: pytest.Config) -> bool:
88+
if delete_pre_upgrade_resources := pytestconfig.option.delete_pre_upgrade_resources:
89+
LOGGER.warning("Resources will be deleted")
90+
91+
return delete_pre_upgrade_resources
92+
93+
8694
@pytest.fixture(scope="class")
87-
def model_namespace(request: FixtureRequest, admin_client: DynamicClient) -> Generator[Namespace, Any, Any]:
95+
def model_namespace(
96+
request: FixtureRequest, pytestconfig: pytest.Config, admin_client: DynamicClient, teardown_resources: bool
97+
) -> Generator[Namespace, Any, Any]:
8898
if request.param.get("modelmesh-enabled"):
8999
request.getfixturevalue(argname="enabled_modelmesh_in_dsc")
90100

91-
with create_ns(admin_client=admin_client, pytest_request=request) as ns:
101+
ns = Namespace(client=admin_client, name=request.param["name"])
102+
103+
if pytestconfig.option.post_upgrade:
92104
yield ns
105+
ns.clean_up()
106+
else:
107+
with create_ns(admin_client=admin_client, pytest_request=request, teardown=teardown_resources) as ns:
108+
yield ns
93109

94110

95111
@pytest.fixture(scope="session")

tests/model_explainability/trustyai_service/conftest.py

Lines changed: 145 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,30 @@
77
from ocp_resources.cluster_service_version import ClusterServiceVersion
88
from ocp_resources.config_map import ConfigMap
99
from ocp_resources.deployment import Deployment
10+
from ocp_resources.inference_service import InferenceService
1011
from ocp_resources.maria_db import MariaDB
1112
from ocp_resources.mariadb_operator import MariadbOperator
1213
from ocp_resources.namespace import Namespace
14+
from ocp_resources.pod import Pod
1315
from ocp_resources.secret import Secret
16+
from ocp_resources.service import Service
17+
from ocp_resources.serving_runtime import ServingRuntime
1418
from ocp_resources.subscription import Subscription
1519
from ocp_resources.trustyai_service import TrustyAIService
1620
from ocp_utilities.operators import install_operator, uninstall_operator
1721

18-
from tests.model_explainability.trustyai_service.trustyai_service_utils import TRUSTYAI_SERVICE_NAME
22+
from tests.model_explainability.trustyai_service.trustyai_service_utils import (
23+
TRUSTYAI_SERVICE_NAME,
24+
wait_for_isvc_deployment_registered_by_trustyai_service,
25+
)
1926
from tests.model_explainability.trustyai_service.utils import (
2027
get_cluster_service_version,
2128
wait_for_mariadb_operator_deployments,
2229
wait_for_mariadb_pods,
2330
)
2431

25-
from utilities.constants import Timeout
32+
from utilities.constants import Timeout, KServeDeploymentType, ApiGroups, Labels, Ports
33+
from utilities.inference_utils import create_isvc
2634
from utilities.infra import update_configmap_data
2735

2836
OPENSHIFT_OPERATORS: str = "openshift-operators"
@@ -32,28 +40,44 @@
3240
DB_NAME: str = "trustyai_db"
3341
DB_USERNAME: str = "trustyai_user"
3442
DB_PASSWORD: str = "trustyai_password"
43+
MLSERVER: str = "mlserver"
44+
MLSERVER_RUNTIME_NAME: str = f"{MLSERVER}-1.x"
45+
XGBOOST: str = "xgboost"
46+
SKLEARN: str = "sklearn"
47+
LIGHTGBM: str = "lightgbm"
48+
MLFLOW: str = "mlflow"
49+
TIMEOUT_20MIN: int = 20 * Timeout.TIMEOUT_1MIN
3550

3651

3752
@pytest.fixture(scope="class")
3853
def trustyai_service_with_pvc_storage(
54+
pytestconfig: pytest.Config,
3955
admin_client: DynamicClient,
4056
model_namespace: Namespace,
4157
cluster_monitoring_config: ConfigMap,
4258
user_workload_monitoring_config: ConfigMap,
59+
teardown_resources: bool,
4360
) -> Generator[TrustyAIService, Any, Any]:
44-
with TrustyAIService(
45-
client=admin_client,
46-
name=TRUSTYAI_SERVICE_NAME,
47-
namespace=model_namespace.name,
48-
storage={"format": "PVC", "folder": "/inputs", "size": "1Gi"},
49-
data={"filename": "data.csv", "format": "CSV"},
50-
metrics={"schedule": "5s"},
51-
) as trustyai_service:
52-
trustyai_deployment = Deployment(
53-
namespace=model_namespace.name, name=TRUSTYAI_SERVICE_NAME, wait_for_resource=True
54-
)
55-
trustyai_deployment.wait_for_replicas()
61+
trustyai_service_kwargs = {"client": admin_client, "namespace": model_namespace.name, "name": TRUSTYAI_SERVICE_NAME}
62+
trustyai_service = TrustyAIService(**trustyai_service_kwargs)
63+
64+
if pytestconfig.option.post_upgrade:
5665
yield trustyai_service
66+
trustyai_service.clean_up()
67+
68+
else:
69+
with TrustyAIService(
70+
**trustyai_service_kwargs,
71+
storage={"format": "PVC", "folder": "/inputs", "size": "1Gi"},
72+
data={"filename": "data.csv", "format": "CSV"},
73+
metrics={"schedule": "5s"},
74+
teardown=teardown_resources,
75+
) as trustyai_service:
76+
trustyai_deployment = Deployment(
77+
namespace=model_namespace.name, name=TRUSTYAI_SERVICE_NAME, wait_for_resource=True
78+
)
79+
trustyai_deployment.wait_for_replicas()
80+
yield trustyai_service
5781

5882

5983
@pytest.fixture(scope="class")
@@ -216,3 +240,110 @@ def trustyai_db_ca_secret(
216240
data_dict={"ca.crt": mariadb_ca_secret.instance.data["ca.crt"]},
217241
):
218242
yield
243+
244+
245+
@pytest.fixture(scope="class")
246+
def mlserver_runtime(
247+
pytestconfig: pytest.Config,
248+
admin_client: DynamicClient,
249+
minio_data_connection: Secret,
250+
model_namespace: Namespace,
251+
teardown_resources: bool,
252+
) -> Generator[ServingRuntime, Any, Any]:
253+
mlserver_runtime_kwargs = {
254+
"client": admin_client,
255+
"namespace": model_namespace.name,
256+
"name": "kserve-mlserver",
257+
}
258+
259+
serving_runtime = ServingRuntime(**mlserver_runtime_kwargs)
260+
261+
if pytestconfig.option.post_upgrade:
262+
yield serving_runtime
263+
serving_runtime.clean_up()
264+
265+
supported_model_formats = [
266+
{"name": SKLEARN, "version": "0", "autoSelect": True, "priority": 2},
267+
{"name": SKLEARN, "version": "1", "autoSelect": True, "priority": 2},
268+
{"name": XGBOOST, "version": "1", "autoSelect": True, "priority": 2},
269+
{"name": XGBOOST, "version": "2", "autoSelect": True, "priority": 2},
270+
{"name": LIGHTGBM, "version": "3", "autoSelect": True, "priority": 2},
271+
{"name": LIGHTGBM, "version": "4", "autoSelect": True, "priority": 2},
272+
{"name": MLFLOW, "version": "1", "autoSelect": True, "priority": 1},
273+
{"name": MLFLOW, "version": "2", "autoSelect": True, "priority": 1},
274+
]
275+
containers = [
276+
{
277+
"name": "kserve-container",
278+
"image": "quay.io/trustyai_testing/mlserver"
279+
"@sha256:68a4cd74fff40a3c4f29caddbdbdc9e54888aba54bf3c5f78c8ffd577c3a1c89",
280+
"env": [
281+
{"name": "MLSERVER_MODEL_IMPLEMENTATION", "value": "{{.Labels.modelClass}}"},
282+
{"name": "MLSERVER_HTTP_PORT", "value": str(Ports.REST_PORT)},
283+
{"name": "MLSERVER_GRPC_PORT", "value": "9000"},
284+
{"name": "MODELS_DIR", "value": "/mnt/models/"},
285+
],
286+
"resources": {"requests": {"cpu": "1", "memory": "2Gi"}, "limits": {"cpu": "1", "memory": "2Gi"}},
287+
}
288+
]
289+
290+
with ServingRuntime(
291+
containers=containers,
292+
supported_model_formats=supported_model_formats,
293+
protocol_versions=["v2"],
294+
annotations={
295+
f"{ApiGroups.OPENDATAHUB_IO}/accelerator-name": "",
296+
f"{ApiGroups.OPENDATAHUB_IO}/template-display-name": "KServe MLServer",
297+
"prometheus.kserve.io/path": "/metrics",
298+
"prometheus.io/port": str(Ports.REST_PORT),
299+
"openshift.io/display-name": "mlserver-1.x",
300+
},
301+
label={Labels.OpenDataHub.DASHBOARD: "true"},
302+
teardown=teardown_resources,
303+
**mlserver_runtime_kwargs,
304+
) as mlserver:
305+
yield mlserver
306+
307+
308+
@pytest.fixture(scope="class")
309+
def gaussian_credit_model(
310+
pytestconfig: pytest.Config,
311+
admin_client: DynamicClient,
312+
model_namespace: Namespace,
313+
minio_pod: Pod,
314+
minio_service: Service,
315+
minio_data_connection: Secret,
316+
mlserver_runtime: ServingRuntime,
317+
trustyai_service_with_pvc_storage: TrustyAIService,
318+
teardown_resources: bool,
319+
) -> Generator[InferenceService, Any, Any]:
320+
gaussian_credit_model_kwargs = {
321+
"client": admin_client,
322+
"namespace": model_namespace.name,
323+
"name": "gaussian-credit-model",
324+
}
325+
326+
isvc = InferenceService(**gaussian_credit_model_kwargs)
327+
328+
if pytestconfig.option.post_upgrade:
329+
yield isvc
330+
isvc.clean_up()
331+
else:
332+
with create_isvc(
333+
deployment_mode=KServeDeploymentType.SERVERLESS,
334+
model_format=XGBOOST,
335+
runtime=mlserver_runtime.name,
336+
storage_key=minio_data_connection.name,
337+
storage_path="sklearn/gaussian_credit_model/1",
338+
enable_auth=True,
339+
wait_for_predictor_pods=False,
340+
resources={"requests": {"cpu": "1", "memory": "2Gi"}, "limits": {"cpu": "1", "memory": "2Gi"}},
341+
teardown=teardown_resources,
342+
**gaussian_credit_model_kwargs,
343+
) as isvc:
344+
wait_for_isvc_deployment_registered_by_trustyai_service(
345+
client=admin_client,
346+
isvc=isvc,
347+
runtime_name=mlserver_runtime.name,
348+
)
349+
yield isvc
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DRIFT_BASE_DATA_PATH: str = "./tests/model_explainability/trustyai_service/drift/model_data"

tests/model_explainability/trustyai_service/drift/conftest.py

Lines changed: 0 additions & 104 deletions
This file was deleted.

tests/model_explainability/trustyai_service/drift/test_drift.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
from tests.model_explainability.trustyai_service.constants import DRIFT_BASE_DATA_PATH
34
from tests.model_explainability.trustyai_service.trustyai_service_utils import (
45
send_inferences_and_verify_trustyai_service_registered,
56
verify_upload_data_to_trustyai_service,
@@ -11,8 +12,6 @@
1112
from utilities.constants import MinIo
1213
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
1314

14-
BASE_DATA_PATH: str = "./tests/model_explainability/trustyai_service/drift/model_data"
15-
1615

1716
@pytest.mark.parametrize(
1817
"model_namespace, minio_pod, minio_data_connection",
@@ -48,7 +47,7 @@ def test_drift_send_inference_and_verify_trustyai_service(
4847
send_inferences_and_verify_trustyai_service_registered(
4948
client=admin_client,
5049
token=current_client_token,
51-
data_path=f"{BASE_DATA_PATH}/data_batches",
50+
data_path=f"{DRIFT_BASE_DATA_PATH}/data_batches",
5251
trustyai_service=trustyai_service_with_pvc_storage,
5352
inference_service=gaussian_credit_model,
5453
inference_config=OPENVINO_KSERVE_INFERENCE_CONFIG,
@@ -65,7 +64,7 @@ def test_upload_data_to_trustyai_service(
6564
client=admin_client,
6665
trustyai_service=trustyai_service_with_pvc_storage,
6766
token=current_client_token,
68-
data_path=f"{BASE_DATA_PATH}/training_data.json",
67+
data_path=f"{DRIFT_BASE_DATA_PATH}/training_data.json",
6968
)
7069

7170
def test_drift_metric_meanshift(

0 commit comments

Comments
 (0)