-
Notifications
You must be signed in to change notification settings - Fork 68
feat(evalhub): add EvalHub service health check tests #1145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
103d085
feat(evalhub): add EvalHub service health check tests
ruivieira f9aaaca
Merge branch 'main' into evalhub
kpunwatk 8130eeb
fix: EvalHub resource generated from CRD
ruivieira 9bdae4c
Merge remote-tracking branch 'origin/evalhub' into evalhub
ruivieira d99681d
Merge branch 'main' into evalhub
dbasunag 38b85c7
Merge branch 'main' into evalhub
ruivieira File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| from collections.abc import Generator | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
| from kubernetes.dynamic import DynamicClient | ||
| from ocp_resources.deployment import Deployment | ||
| from ocp_resources.namespace import Namespace | ||
| from ocp_resources.route import Route | ||
| from simple_logger.logger import get_logger | ||
|
|
||
| from utilities.certificates_utils import create_ca_bundle_file | ||
| from utilities.constants import Timeout | ||
| from utilities.resources.evalhub import EvalHub | ||
|
|
||
| LOGGER = get_logger(name=__name__) | ||
|
|
||
|
|
||
| @pytest.fixture(scope="class") | ||
| def evalhub_cr( | ||
| admin_client: DynamicClient, | ||
| model_namespace: Namespace, | ||
| ) -> Generator[EvalHub, Any, Any]: | ||
| """Create an EvalHub custom resource and wait for it to be ready.""" | ||
| with EvalHub( | ||
| client=admin_client, | ||
| name="evalhub", | ||
| namespace=model_namespace.name, | ||
| wait_for_resource=True, | ||
| ) as evalhub: | ||
| yield evalhub | ||
|
|
||
|
|
||
| @pytest.fixture(scope="class") | ||
| def evalhub_deployment( | ||
| admin_client: DynamicClient, | ||
| model_namespace: Namespace, | ||
| evalhub_cr: EvalHub, | ||
| ) -> Deployment: | ||
| """Wait for the EvalHub deployment to become available.""" | ||
| deployment = Deployment( | ||
| client=admin_client, | ||
| name=evalhub_cr.name, | ||
| namespace=model_namespace.name, | ||
| ) | ||
| deployment.wait_for_replicas(timeout=Timeout.TIMEOUT_5MIN) | ||
| return deployment | ||
|
|
||
|
|
||
| @pytest.fixture(scope="class") | ||
| def evalhub_route( | ||
| admin_client: DynamicClient, | ||
| model_namespace: Namespace, | ||
| evalhub_deployment: Deployment, | ||
| ) -> Route: | ||
| """Get the Route created by the operator for the EvalHub service.""" | ||
| return Route( | ||
| client=admin_client, | ||
| name=evalhub_deployment.name, | ||
| namespace=model_namespace.name, | ||
| ensure_exists=True, | ||
| ) | ||
|
|
||
|
|
||
| @pytest.fixture(scope="class") | ||
| def evalhub_ca_bundle_file( | ||
| admin_client: DynamicClient, | ||
| ) -> str: | ||
| """Create a CA bundle file for verifying the EvalHub route TLS certificate.""" | ||
| return create_ca_bundle_file(client=admin_client, ca_type="openshift") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| EVALHUB_SERVICE_NAME: str = "evalhub" | ||
| EVALHUB_SERVICE_PORT: int = 8443 | ||
| EVALHUB_CONTAINER_PORT: int = 8080 | ||
| EVALHUB_HEALTH_PATH: str = "/api/v1/health" | ||
| EVALHUB_PROVIDERS_PATH: str = "/api/v1/evaluations/providers" | ||
| EVALHUB_HEALTH_STATUS_HEALTHY: str = "healthy" | ||
|
|
||
| EVALHUB_APP_LABEL: str = "eval-hub" | ||
|
|
||
| # CRD details | ||
| EVALHUB_API_GROUP: str = "trustyai.opendatahub.io" | ||
| EVALHUB_API_VERSION: str = "v1alpha1" | ||
| EVALHUB_KIND: str = "EvalHub" | ||
| EVALHUB_PLURAL: str = "evalhubs" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import pytest | ||
| from ocp_resources.route import Route | ||
|
|
||
| from tests.model_explainability.evalhub.utils import validate_evalhub_health | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "model_namespace", | ||
| [ | ||
| pytest.param( | ||
| {"name": "test-evalhub-health"}, | ||
| ), | ||
| ], | ||
| indirect=True, | ||
| ) | ||
| @pytest.mark.smoke | ||
| @pytest.mark.model_explainability | ||
| class TestEvalHubHealth: | ||
| """Tests for basic EvalHub service health and availability.""" | ||
|
|
||
| def test_evalhub_health_endpoint( | ||
| self, | ||
| current_client_token: str, | ||
| evalhub_ca_bundle_file: str, | ||
| evalhub_route: Route, | ||
| ) -> None: | ||
| """Verify the EvalHub service responds with healthy status via kube-rbac-proxy.""" | ||
| validate_evalhub_health( | ||
| host=evalhub_route.host, | ||
| token=current_client_token, | ||
| ca_bundle_file=evalhub_ca_bundle_file, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import requests | ||
| from simple_logger.logger import get_logger | ||
|
|
||
| from tests.model_explainability.evalhub.constants import ( | ||
| EVALHUB_HEALTH_PATH, | ||
| EVALHUB_HEALTH_STATUS_HEALTHY, | ||
| ) | ||
| from utilities.guardrails import get_auth_headers | ||
|
|
||
| LOGGER = get_logger(name=__name__) | ||
|
|
||
|
|
||
| def validate_evalhub_health( | ||
| host: str, | ||
| token: str, | ||
| ca_bundle_file: str, | ||
| ) -> None: | ||
| """Validate that the EvalHub service health endpoint returns healthy status. | ||
|
|
||
| Args: | ||
| host: Route host for the EvalHub service. | ||
| token: Bearer token for authentication. | ||
| ca_bundle_file: Path to CA bundle for TLS verification. | ||
|
|
||
| Raises: | ||
| AssertionError: If the health check fails. | ||
| requests.HTTPError: If the request fails. | ||
| """ | ||
| url = f"https://{host}{EVALHUB_HEALTH_PATH}" | ||
| LOGGER.info(f"Checking EvalHub health at {url}") | ||
|
|
||
| response = requests.get( | ||
| url=url, | ||
| headers=get_auth_headers(token=token), | ||
| verify=ca_bundle_file, | ||
| timeout=10, | ||
| ) | ||
| response.raise_for_status() | ||
|
|
||
| data = response.json() | ||
| LOGGER.info(f"EvalHub health response: {data}") | ||
|
|
||
| assert "status" in data, "Health response missing 'status' field" | ||
| assert data["status"] == EVALHUB_HEALTH_STATUS_HEALTHY, ( | ||
| f"Expected status '{EVALHUB_HEALTH_STATUS_HEALTHY}', got '{data['status']}'" | ||
| ) | ||
| assert "timestamp" in data, "Health response missing 'timestamp' field" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # Generated using https://github.com/RedHatQE/openshift-python-wrapper/blob/main/scripts/resource/README.md | ||
|
|
||
|
|
||
| from typing import Any | ||
|
|
||
| from ocp_resources.resource import NamespacedResource | ||
|
|
||
|
|
||
| class EvalHub(NamespacedResource): | ||
| """ | ||
| EvalHub is the Schema for the evalhubs API | ||
| """ | ||
|
|
||
|
ruivieira marked this conversation as resolved.
|
||
| api_group: str = NamespacedResource.ApiGroup.TRUSTYAI_OPENDATAHUB_IO | ||
|
|
||
| def __init__( | ||
| self, | ||
| env: list[Any] | None = None, | ||
| replicas: int | None = None, | ||
| **kwargs: Any, | ||
| ) -> None: | ||
| r""" | ||
| Args: | ||
| env (list[Any]): Environment variables for the eval-hub container | ||
|
|
||
| replicas (int): Number of replicas for the eval-hub deployment | ||
|
|
||
| """ | ||
| super().__init__(**kwargs) | ||
|
|
||
| self.env = env | ||
| self.replicas = replicas | ||
|
|
||
| def to_dict(self) -> None: | ||
|
|
||
| super().to_dict() | ||
|
|
||
| if not self.kind_dict and not self.yaml_file: | ||
| self.res["spec"] = {} | ||
| _spec = self.res["spec"] | ||
|
dbasunag marked this conversation as resolved.
|
||
|
|
||
| if self.env is not None: | ||
| _spec["env"] = self.env | ||
|
|
||
| if self.replicas is not None: | ||
| _spec["replicas"] = self.replicas | ||
|
|
||
| # End of generated code | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.