Skip to content

Commit e2707b1

Browse files
committed
test: New tests to validate postgres password autogeneration
1 parent bfad94d commit e2707b1

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Database check tests for model catalog
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import pytest
2+
from kubernetes.dynamic import DynamicClient
3+
from ocp_resources.secret import Secret
4+
from pytest_testconfig import config as py_config
5+
from simple_logger.logger import get_logger
6+
from timeout_sampler import TimeoutSampler
7+
8+
from .utils import extract_secret_values
9+
10+
LOGGER = get_logger(name=__name__)
11+
12+
13+
@pytest.fixture(scope="class")
14+
def model_catalog_postgres_secret(admin_client: DynamicClient) -> Secret:
15+
"""Get the model-catalog-postgres secret from model registry namespace"""
16+
return Secret(
17+
client=admin_client,
18+
name="model-catalog-postgres",
19+
namespace=py_config["model_registry_namespace"],
20+
ensure_exists=True,
21+
)
22+
23+
24+
@pytest.fixture(scope="class")
25+
def model_catalog_postgres_secret_values(model_catalog_postgres_secret: Secret) -> dict[str, str]:
26+
"""Capture current values of model-catalog-postgres secret in model registry namespace"""
27+
return extract_secret_values(secret=model_catalog_postgres_secret)
28+
29+
30+
@pytest.fixture(scope="class")
31+
def recreated_model_catalog_postgres_secret(
32+
admin_client: DynamicClient, model_catalog_postgres_secret: Secret
33+
) -> dict[str, str]:
34+
"""Delete model-catalog-postgres secret and wait for it to be recreated"""
35+
model_registry_namespace = py_config["model_registry_namespace"]
36+
resource_name = "model-catalog-postgres"
37+
38+
LOGGER.info(f"Deleting secret {resource_name} in namespace {model_registry_namespace}")
39+
model_catalog_postgres_secret.delete()
40+
41+
# Wait for the secret to be recreated by the operator
42+
LOGGER.info(f"Waiting for secret {resource_name} to be recreated...")
43+
44+
recreated_secret = None
45+
for secret in TimeoutSampler(
46+
wait_timeout=120,
47+
sleep=10,
48+
func=Secret,
49+
client=admin_client,
50+
name=resource_name,
51+
namespace=model_registry_namespace,
52+
):
53+
if secret.exists:
54+
LOGGER.info(f"Secret {resource_name} has been recreated")
55+
recreated_secret = secret
56+
break
57+
58+
return extract_secret_values(secret=recreated_secret)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import pytest
2+
from kubernetes.dynamic import DynamicClient
3+
from simple_logger.logger import get_logger
4+
5+
from tests.model_registry.model_catalog.utils import get_postgres_pod_in_namespace
6+
from tests.model_registry.utils import (
7+
wait_for_model_catalog_pod_ready_after_deletion,
8+
)
9+
10+
LOGGER = get_logger(name=__name__)
11+
12+
13+
def test_model_catalog_postgres_secret_exists(model_catalog_postgres_secret_values):
14+
"""Test that model-catalog-postgres secret exists and is accessible"""
15+
secret_values = model_catalog_postgres_secret_values
16+
assert secret_values, "model-catalog-postgres secret should exist and be accessible"
17+
18+
# Log the keys (not values) for debugging
19+
LOGGER.info(f"Secret contains keys: {list(secret_values.keys())}")
20+
21+
22+
@pytest.mark.dependency(name="test_model_catalog_postgres_password_recreation")
23+
def test_model_catalog_postgres_password_recreation(
24+
model_catalog_postgres_secret_values, recreated_model_catalog_postgres_secret
25+
):
26+
"""Test that secret recreation generates new password but preserves user/database name"""
27+
# Verify database-name and database-user did NOT change
28+
unchanged_keys = ["database-name", "database-user"]
29+
for key in unchanged_keys:
30+
assert model_catalog_postgres_secret_values[key] == recreated_model_catalog_postgres_secret[key], (
31+
f"{key} should remain the same after secret recreation"
32+
)
33+
34+
# Verify database-password DID change (randomization working)
35+
assert (
36+
model_catalog_postgres_secret_values["database-password"]
37+
!= recreated_model_catalog_postgres_secret["database-password"]
38+
), "database-password should be different after secret recreation (randomized)"
39+
40+
LOGGER.info("Password randomization verified - new password generated on recreation")
41+
42+
43+
@pytest.mark.dependency(depends=["test_model_catalog_postgres_password_recreation"])
44+
def test_model_catalog_pod_ready_after_secret_recreation(admin_client: DynamicClient, model_registry_namespace: str):
45+
"""Test that model catalog pod becomes ready after secret recreation"""
46+
# delete the postgres pod first
47+
get_postgres_pod_in_namespace(admin_client=admin_client).delete()
48+
# Wait for model catalog pod to be ready after the secret deletion/recreation
49+
wait_for_model_catalog_pod_ready_after_deletion(
50+
client=admin_client, model_registry_namespace=model_registry_namespace
51+
)
52+
LOGGER.info("Model catalog pod is ready after secret recreation")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import base64
2+
import binascii
3+
4+
from ocp_resources.secret import Secret
5+
from simple_logger.logger import get_logger
6+
7+
LOGGER = get_logger(name=__name__)
8+
9+
10+
def extract_secret_values(secret: Secret) -> dict[str, str]:
11+
"""Extract and decode secret data values from a Secret object.
12+
13+
Args:
14+
secret: The Secret object to extract values from
15+
16+
Returns:
17+
Dict mapping secret keys to decoded string values
18+
"""
19+
secret_values = {}
20+
if secret.instance.data:
21+
for key, encoded_value in secret.instance.data.items():
22+
try:
23+
decoded_value = base64.b64decode(s=encoded_value).decode(encoding="utf-8")
24+
secret_values[key] = decoded_value
25+
except (binascii.Error, UnicodeDecodeError) as e:
26+
LOGGER.warning(f"Failed to decode secret key '{key}': {e}")
27+
secret_values[key] = encoded_value # Keep encoded if decode fails
28+
29+
LOGGER.info(f"Captured secret with keys: {list(secret_values.keys())}")
30+
return secret_values

0 commit comments

Comments
 (0)