Skip to content

Commit a65d342

Browse files
committed
Use exitStack to support multiple resource creations
1 parent e8db035 commit a65d342

13 files changed

Lines changed: 381 additions & 241 deletions

tests/model_registry/conftest.py

Lines changed: 129 additions & 155 deletions
Large diffs are not rendered by default.

tests/model_registry/constants.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any
22
from ocp_resources.resource import Resource
3-
from utilities.constants import ModelFormat, Annotations
3+
from utilities.constants import ModelFormat
44

55

66
class ModelRegistryEndpoints:
@@ -25,7 +25,8 @@ class ModelRegistryEndpoints:
2525
"str_key": "str_value",
2626
},
2727
}
28-
MR_INSTANCE_NAME: str = "model-registry"
28+
MR_INSTANCE_BASE_NAME: str = "model-registry"
29+
MR_INSTANCE_NAME: str = f"{MR_INSTANCE_BASE_NAME}0"
2930
SECURE_MR_NAME: str = "secure-db-mr"
3031
ISTIO_CONFIG_DICT: dict[str, Any] = {
3132
"gateway": {"grpc": {"tls": {}}, "rest": {"tls": {}}},
@@ -35,7 +36,8 @@ class ModelRegistryEndpoints:
3536
"routePort": 443,
3637
"serviceRoute": "enabled",
3738
}
38-
DB_RESOURCES_NAME: str = "db-model-registry"
39+
DB_BASE_RESOURCES_NAME: str = "db-model-registry"
40+
DB_RESOURCE_NAME: str = f"{DB_BASE_RESOURCES_NAME}0"
3941
MR_DB_IMAGE_DIGEST: str = (
4042
"public.ecr.aws/docker/library/mysql@sha256:9de9d54fecee6253130e65154b930978b1fcc336bcc86dfd06e89b72a2588ebe"
4143
)
@@ -53,10 +55,3 @@ class ModelRegistryEndpoints:
5355
CA_CONFIGMAP_NAME = "odh-trusted-ca-bundle"
5456
CA_MOUNT_PATH = "/etc/pki/ca-trust/extracted/pem"
5557
CA_FILE_PATH = f"{CA_MOUNT_PATH}/ca-bundle.crt"
56-
57-
MODEL_REGISTRY_STANDARD_LABELS = {
58-
Annotations.KubernetesIo.NAME: MR_INSTANCE_NAME,
59-
Annotations.KubernetesIo.INSTANCE: MR_INSTANCE_NAME,
60-
Annotations.KubernetesIo.PART_OF: MR_OPERATOR_NAME,
61-
Annotations.KubernetesIo.CREATED_BY: MR_OPERATOR_NAME,
62-
}

tests/model_registry/image_validation/test_verify_rhoai_images.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from utilities.general import (
99
validate_container_images,
1010
)
11-
from ocp_resources.model_registry_modelregistry_opendatahub_io import ModelRegistry
1211
from ocp_resources.pod import Pod
1312

1413
LOGGER = get_logger(name=__name__)
@@ -48,7 +47,6 @@ class TestModelRegistryImages:
4847
def test_verify_model_registry_images(
4948
self: Self,
5049
admin_client: DynamicClient,
51-
model_registry_instance_mysql: ModelRegistry,
5250
model_registry_operator_pod: Pod,
5351
model_registry_instance_pod: Pod,
5452
related_images_refs: Set[str],

tests/model_registry/negative_tests/test_model_registry_creation_negative.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from tests.model_registry.constants import (
1313
MR_OPERATOR_NAME,
1414
MR_INSTANCE_NAME,
15-
DB_RESOURCES_NAME,
15+
DB_RESOURCE_NAME,
1616
OAUTH_PROXY_CONFIG_DICT,
1717
)
1818
from kubernetes.dynamic.exceptions import ForbiddenError
@@ -71,7 +71,7 @@ def test_registering_model_negative(
7171
"host": f"{model_registry_db_deployment_negative_test.name}."
7272
f"{model_registry_db_deployment_negative_test.namespace}.svc.cluster.local",
7373
"database": model_registry_db_secret_negative_test.string_data["database-name"],
74-
"passwordSecret": {"key": "database-password", "name": DB_RESOURCES_NAME},
74+
"passwordSecret": {"key": "database-password", "name": DB_RESOURCE_NAME},
7575
"port": 3306,
7676
"skipDBCreation": False,
7777
"username": model_registry_db_secret_negative_test.string_data["database-user"],

tests/model_registry/python_client/test_model_registry_creation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ class TestModelRegistryCreation:
6262
@pytest.mark.smoke
6363
def test_registering_model(
6464
self: Self,
65-
model_registry_client: ModelRegistryClient,
65+
model_registry_client: list[ModelRegistryClient],
6666
registered_model: RegisteredModel,
6767
):
68-
model = model_registry_client.get_registered_model(name=MODEL_NAME)
68+
model = model_registry_client[0].get_registered_model(name=MODEL_NAME)
6969
expected_attrs = {
7070
"id": registered_model.id,
7171
"name": registered_model.name,
@@ -130,7 +130,7 @@ def test_model_registry_pod_log_mlmd_removal(
130130
],
131131
)
132132
def test_model_registry_endpoint_response(
133-
self, model_registry_rest_url: str, model_registry_rest_headers: dict[str, str], endpoint: str
133+
self, model_registry_rest_url: list[str], model_registry_rest_headers: dict[str, str], endpoint: str
134134
):
135135
"""
136136
RHOAIENG-26239: Test to ensure model registry endpoints are responsive
@@ -140,6 +140,6 @@ def test_model_registry_endpoint_response(
140140
Ensure endpoint is responsive via get call
141141
"""
142142
output = execute_model_registry_get_command(
143-
url=f"{model_registry_rest_url}/{endpoint}", headers=model_registry_rest_headers, json_output=False
143+
url=f"{model_registry_rest_url[0]}/{endpoint}", headers=model_registry_rest_headers, json_output=False
144144
)
145145
assert output["raw_output"].lower() == "OK".lower()

tests/model_registry/rbac/test_mr_rbac.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ class TestUserPermission:
5353
def test_user_permission_non_admin_user(
5454
self: Self,
5555
test_idp_user,
56-
model_registry_instance_rest_endpoint: str,
56+
model_registry_instance_rest_endpoint: list[str],
5757
login_as_test_user: None,
5858
):
5959
"""
6060
This test verifies that non-admin users cannot access the Model Registry (403 Forbidden)
6161
"""
6262
client_args = build_mr_client_args(
63-
rest_endpoint=model_registry_instance_rest_endpoint, token=get_openshift_token()
63+
rest_endpoint=model_registry_instance_rest_endpoint[0], token=get_openshift_token()
6464
)
6565
with pytest.raises(ForbiddenException) as exc_info:
6666
ModelRegistryClient(**client_args)
@@ -70,7 +70,7 @@ def test_user_permission_non_admin_user(
7070
@pytest.mark.sanity
7171
def test_user_added_to_group(
7272
self: Self,
73-
model_registry_instance_rest_endpoint: str,
73+
model_registry_instance_rest_endpoint: list[str],
7474
test_idp_user: UserTestSession,
7575
model_registry_group_with_user: Group,
7676
login_as_test_user: Generator[UserTestSession, None, None],
@@ -84,7 +84,7 @@ def test_user_added_to_group(
8484
wait_timeout=240,
8585
sleep=5,
8686
func=assert_positive_mr_registry,
87-
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint,
87+
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint[0],
8888
token=get_openshift_token(),
8989
)
9090
for _ in sampler:
@@ -95,7 +95,7 @@ def test_user_added_to_group(
9595
def test_create_group(
9696
self: Self,
9797
test_idp_user: UserTestSession,
98-
model_registry_instance_rest_endpoint: str,
98+
model_registry_instance_rest_endpoint: list[str],
9999
created_role_binding_group: RoleBinding,
100100
login_as_test_user: None,
101101
):
@@ -108,14 +108,14 @@ def test_create_group(
108108
3. Users in the group can access the Model Registry
109109
"""
110110
assert_positive_mr_registry(
111-
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint,
111+
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint[0],
112112
)
113113

114114
@pytest.mark.sanity
115115
def test_add_single_user_role_binding(
116116
self: Self,
117117
test_idp_user: UserTestSession,
118-
model_registry_instance_rest_endpoint: str,
118+
model_registry_instance_rest_endpoint: list[str],
119119
created_role_binding_user: RoleBinding,
120120
login_as_test_user: None,
121121
):
@@ -127,5 +127,5 @@ def test_add_single_user_role_binding(
127127
2. The user can access the Model Registry after being granted access
128128
"""
129129
assert_positive_mr_registry(
130-
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint,
130+
model_registry_instance_rest_endpoint=model_registry_instance_rest_endpoint[0],
131131
)

tests/model_registry/rbac/test_mr_rbac_sa.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class TestModelRegistryRBAC:
4242
@pytest.mark.usefixtures("sa_namespace", "service_account")
4343
def test_service_account_access_denied(
4444
self: Self,
45-
model_registry_instance_rest_endpoint: str,
45+
model_registry_instance_rest_endpoint: list[str],
4646
sa_token: str,
4747
):
4848
"""
@@ -54,7 +54,7 @@ def test_service_account_access_denied(
5454
LOGGER.info("Expecting initial access DENIAL (403 Forbidden)")
5555

5656
client_args = build_mr_client_args(
57-
rest_endpoint=model_registry_instance_rest_endpoint, token=sa_token, author="rbac-test-denied"
57+
rest_endpoint=model_registry_instance_rest_endpoint[0], token=sa_token, author="rbac-test-denied"
5858
)
5959
LOGGER.debug(f"Attempting client connection with args: {client_args}")
6060

@@ -74,18 +74,18 @@ def test_service_account_access_denied(
7474
def test_service_account_access_granted(
7575
self: Self,
7676
sa_token: str,
77-
model_registry_instance_rest_endpoint: str,
77+
model_registry_instance_rest_endpoint: list[str],
7878
):
7979
"""
8080
Verifies SA access is GRANTED via REST after applying Role and RoleBinding fixtures.
8181
"""
8282
LOGGER.info("--- Starting RBAC Test: Access Granted ---")
83-
LOGGER.info(f"Targeting Model Registry REST endpoint: {model_registry_instance_rest_endpoint}")
83+
LOGGER.info(f"Targeting Model Registry REST endpoint: {model_registry_instance_rest_endpoint[0]}")
8484
LOGGER.info("Applied RBAC Role/Binding via fixtures. Expecting access GRANT.")
8585

8686
try:
8787
client_args = build_mr_client_args(
88-
rest_endpoint=model_registry_instance_rest_endpoint, token=sa_token, author="rbac-test-granted"
88+
rest_endpoint=model_registry_instance_rest_endpoint[0], token=sa_token, author="rbac-test-granted"
8989
)
9090
LOGGER.debug(f"Attempting client connection with args: {client_args}")
9191
mr_client_success = ModelRegistryClient(**client_args)

tests/model_registry/rest_api/conftest.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
apply_mysql_args_and_volume_mounts,
1717
add_mysql_certs_volumes_to_deployment,
1818
wait_for_pods_running,
19+
get_mr_standard_labels,
20+
get_mysql_config,
1921
)
2022

2123
from tests.model_registry.constants import (
22-
DB_RESOURCES_NAME,
24+
DB_RESOURCE_NAME,
2325
CA_MOUNT_PATH,
2426
CA_FILE_PATH,
2527
CA_CONFIGMAP_NAME,
2628
OAUTH_PROXY_CONFIG_DICT,
27-
MODEL_REGISTRY_STANDARD_LABELS,
2829
SECURE_MR_NAME,
2930
)
3031
from ocp_resources.resource import ResourceEditor
@@ -45,11 +46,11 @@
4546
def registered_model_rest_api(
4647
request: pytest.FixtureRequest,
4748
is_model_registry_oauth: bool,
48-
model_registry_rest_url: str,
49+
model_registry_rest_url: list[str],
4950
model_registry_rest_headers: dict[str, str],
5051
) -> dict[str, Any]:
5152
return register_model_rest_api(
52-
model_registry_rest_url=model_registry_rest_url,
53+
model_registry_rest_url=model_registry_rest_url[0],
5354
model_registry_rest_headers=model_registry_rest_headers,
5455
data_dict=request.param,
5556
)
@@ -58,7 +59,7 @@ def registered_model_rest_api(
5859
@pytest.fixture()
5960
def updated_model_registry_resource(
6061
request: pytest.FixtureRequest,
61-
model_registry_rest_url: str,
62+
model_registry_rest_url: list[str],
6263
model_registry_rest_headers: dict[str, str],
6364
registered_model_rest_api: dict[str, Any],
6465
) -> dict[str, Any]:
@@ -80,7 +81,7 @@ def updated_model_registry_resource(
8081
resource_id = registered_model_rest_api[resource_name]["id"]
8182
assert resource_id, f"Resource id not found: {registered_model_rest_api[resource_name]}"
8283
return execute_model_registry_patch_command(
83-
url=f"{model_registry_rest_url}{MODEL_REGISTRY_BASE_URI}{api_name}/{resource_id}",
84+
url=f"{model_registry_rest_url[0]}{MODEL_REGISTRY_BASE_URI}{api_name}/{resource_id}",
8485
headers=model_registry_rest_headers,
8586
data_json=request.param["data"],
8687
)
@@ -119,7 +120,7 @@ def patch_invalid_ca(
119120

120121

121122
@pytest.fixture(scope="class")
122-
def mysql_template_with_ca(model_registry_db_secret: Secret) -> dict[str, Any]:
123+
def mysql_template_with_ca(model_registry_db_secret: list[Secret]) -> dict[str, Any]:
123124
"""
124125
Patches the MySQL template with the CA file path and volume mount.
125126
@@ -130,8 +131,8 @@ def mysql_template_with_ca(model_registry_db_secret: Secret) -> dict[str, Any]:
130131
dict[str, Any]: The patched MySQL template
131132
"""
132133
mysql_template = get_model_registry_deployment_template_dict(
133-
secret_name=model_registry_db_secret.name,
134-
resource_name=DB_RESOURCES_NAME,
134+
secret_name=model_registry_db_secret[0].name,
135+
resource_name=DB_RESOURCE_NAME,
135136
)
136137
mysql_template["spec"]["containers"][0]["args"].append(f"--ssl-ca={CA_FILE_PATH}")
137138
mysql_template["spec"]["containers"][0]["volumeMounts"].append({
@@ -145,33 +146,29 @@ def mysql_template_with_ca(model_registry_db_secret: Secret) -> dict[str, Any]:
145146

146147
@pytest.fixture(scope="class")
147148
def deploy_secure_mysql_and_mr(
149+
request: pytest.FixtureRequest,
148150
admin_client: DynamicClient,
149151
model_registry_namespace: str,
150-
model_registry_mysql_metadata_db: Deployment,
151-
model_registry_mysql_config: dict[str, Any],
152+
model_registry_mysql_metadata_db: list[Deployment],
152153
mysql_template_with_ca: dict[str, Any],
153154
patch_mysql_deployment_with_ssl_ca: Deployment,
154155
) -> Generator[ModelRegistry, None, None]:
155156
"""
156157
Deploy a secure MySQL and Model Registry instance.
157-
158-
Args:
159-
model_registry_namespace: The namespace of the model registry
160-
model_registry_db_secret: The secret for the model registry's MySQL database
161-
model_registry_db_deployment: The deployment for the model registry's MySQL database
162-
model_registry_mysql_config: The MySQL config dictionary
163-
mysql_template_with_ca: The MySQL template with the CA file path and volume mount
164-
patch_mysql_deployment_with_ssl_ca: The MySQL deployment with the CA file path and volume mount
165158
"""
159+
param = getattr(request, "param", {})
160+
mysql = get_mysql_config(base_name=DB_RESOURCE_NAME, namespace=model_registry_namespace)
161+
if "sslRootCertificateConfigMap" in param:
162+
mysql["sslRootCertificateConfigMap"] = param["sslRootCertificateConfigMap"]
166163
with ModelRegistry(
167164
name=SECURE_MR_NAME,
168165
namespace=model_registry_namespace,
169-
label=MODEL_REGISTRY_STANDARD_LABELS,
166+
label=get_mr_standard_labels(resource_name=SECURE_MR_NAME),
170167
grpc={},
171168
rest={},
172169
istio=None,
173170
oauth_proxy=OAUTH_PROXY_CONFIG_DICT,
174-
mysql=model_registry_mysql_config,
171+
mysql=mysql,
175172
wait_for_resource=True,
176173
) as mr:
177174
mr.wait_for_condition(condition="Available", status="True")
@@ -216,7 +213,7 @@ def ca_configmap_for_test(
216213
Args:
217214
admin_client: The admin client to create the ConfigMap
218215
model_registry_namespace: The namespace of the model registry
219-
mysql_ssl_secrets: The artifacts and secrets for the MySQL SSL connection
216+
mysql_ssl_artifact_paths: The artifacts and secrets for the MySQL SSL connection
220217
221218
Returns:
222219
Generator[ConfigMap, None, None]: A generator that yields the ConfigMap instance.
@@ -241,7 +238,7 @@ def patch_mysql_deployment_with_ssl_ca(
241238
request: pytest.FixtureRequest,
242239
admin_client: DynamicClient,
243240
model_registry_namespace: str,
244-
model_registry_db_deployment: Deployment,
241+
model_registry_db_deployment: list[Deployment],
245242
mysql_ssl_secrets: dict[str, Any],
246243
) -> Generator[Deployment, Any, Any]:
247244
"""
@@ -251,11 +248,11 @@ def patch_mysql_deployment_with_ssl_ca(
251248

252249
if request.param.get("ca_configmap_for_test"):
253250
LOGGER.info("Invoking ca_configmap_for_test fixture")
254-
request.getfixturevalue("ca_configmap_for_test") # noqa: FCN001
251+
request.getfixturevalue(argname="ca_configmap_for_test")
255252
CA_CONFIGMAP_NAME = request.param.get("ca_configmap_name", "mysql-ca-configmap")
256253
CA_MOUNT_PATH = request.param.get("ca_mount_path", "/etc/mysql/ssl")
257254

258-
deployment = model_registry_db_deployment.instance.to_dict()
255+
deployment = model_registry_db_deployment[0].instance.to_dict()
259256
spec = deployment["spec"]["template"]["spec"]
260257
my_sql_container = next(container for container in spec["containers"] if container["name"] == "mysql")
261258
assert my_sql_container is not None, "Mysql container not found"
@@ -266,9 +263,9 @@ def patch_mysql_deployment_with_ssl_ca(
266263
volumes = add_mysql_certs_volumes_to_deployment(spec=spec, ca_configmap_name=CA_CONFIGMAP_NAME)
267264

268265
patch = {"spec": {"template": {"spec": {"volumes": volumes, "containers": [my_sql_container]}}}}
269-
with ResourceEditor(patches={model_registry_db_deployment: patch}):
270-
model_registry_db_deployment.wait_for_condition(condition="Available", status="True")
271-
yield model_registry_db_deployment
266+
with ResourceEditor(patches={model_registry_db_deployment[0]: patch}):
267+
model_registry_db_deployment[0].wait_for_condition(condition="Available", status="True")
268+
yield model_registry_db_deployment[0]
272269

273270

274271
@pytest.fixture(scope="class")

tests/model_registry/rest_api/mariadb/conftest.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
from ocp_resources.maria_db import MariaDB
66
from ocp_resources.mariadb_operator import MariadbOperator
77
from tests.model_registry.rest_api.mariadb.utils import get_mariadb_dict
8-
from tests.model_registry.utils import wait_for_pods_running
8+
from tests.model_registry.utils import wait_for_pods_running, get_mr_standard_labels
99
from utilities.constants import OPENSHIFT_OPERATORS, MARIADB
1010
from utilities.general import generate_random_name
1111

1212
from tests.model_registry.constants import (
1313
OAUTH_PROXY_CONFIG_DICT,
14-
MODEL_REGISTRY_STANDARD_LABELS,
1514
MR_INSTANCE_NAME,
1615
)
1716
from ocp_resources.secret import Secret
@@ -68,7 +67,7 @@ def model_registry_with_mariadb(
6867
with ModelRegistry(
6968
name=MR_INSTANCE_NAME,
7069
namespace=model_registry_namespace,
71-
label=MODEL_REGISTRY_STANDARD_LABELS,
70+
label=get_mr_standard_labels(resource_name=MR_INSTANCE_NAME),
7271
grpc={},
7372
rest={},
7473
oauth_proxy=OAUTH_PROXY_CONFIG_DICT,

0 commit comments

Comments
 (0)