-
Notifications
You must be signed in to change notification settings - Fork 68
Add negative test for modelServer #1152
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
5 commits
Select commit
Hold shift + click to select a range
a15e33f
Add negative test for modelServer
mwaykole 4516fda
Add negative test for modelServer
mwaykole 81dd19b
Fix UFN001: rename fixtures to avoid name collision with parent conftest
mwaykole 2e59025
Merge branch 'main' into neg12
mwaykole a515a44
Merge branch 'main' into neg12
mwaykole 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
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
86 changes: 86 additions & 0 deletions
86
tests/model_serving/model_server/kserve/negative/test_invalid_model_name.py
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,86 @@ | ||
| """Tests for invalid model name in inference endpoint. | ||
|
|
||
| Jira: RHOAIENG-48282 | ||
| """ | ||
|
|
||
| import json | ||
| from http import HTTPStatus | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
| from kubernetes.dynamic import DynamicClient | ||
| from ocp_resources.inference_service import InferenceService | ||
|
|
||
| from tests.model_serving.model_server.kserve.negative.utils import ( | ||
| VALID_OVMS_INFERENCE_BODY, | ||
| assert_pods_healthy, | ||
| send_inference_request, | ||
| ) | ||
|
|
||
| pytestmark = pytest.mark.usefixtures("valid_aws_config") | ||
|
|
||
| VALID_BODY_RAW = json.dumps(VALID_OVMS_INFERENCE_BODY) | ||
|
|
||
|
|
||
| @pytest.mark.tier1 | ||
| class TestInvalidModelName: | ||
| """Test class for verifying error handling when targeting a non-existent model. | ||
|
|
||
| Preconditions: | ||
| - InferenceService "negative-test-ovms-isvc" deployed and ready | ||
| - No InferenceService with name "nonexistent-model" | ||
|
|
||
| Test Steps: | ||
| 1. Create InferenceService with OVMS runtime | ||
| 2. Wait for InferenceService status = Ready | ||
| 3. Send inference request to /v2/models/nonexistent-model/infer | ||
| 4. Verify error response and existing service health | ||
|
|
||
| Expected Results: | ||
| - HTTP Status Code: 404 Not Found | ||
| - Error message indicates model not found | ||
| - No impact on existing model service | ||
| """ | ||
|
|
||
| def test_nonexistent_model_returns_404( | ||
| self, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| ) -> None: | ||
| """Verify that inference to a non-existent model returns 404 status code. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending a POST request targeting a non-existent model name | ||
| Then the response should have HTTP status code 404 (Not Found) | ||
| """ | ||
| status_code, response_body = send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body=VALID_BODY_RAW, | ||
| model_name="nonexistent-model", | ||
| ) | ||
|
|
||
| assert status_code == HTTPStatus.NOT_FOUND, ( | ||
| f"Expected 404 Not Found for nonexistent model, got {status_code}. Response: {response_body}" | ||
| ) | ||
|
|
||
| def test_existing_service_unaffected_after_invalid_model_request( | ||
| self, | ||
| admin_client: DynamicClient, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| initial_pod_state: dict[str, dict[str, Any]], | ||
| ) -> None: | ||
| """Verify that the existing service remains healthy after invalid model requests. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending a request targeting a non-existent model name | ||
| Then the existing service pods should remain running without restarts | ||
| """ | ||
| send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body=VALID_BODY_RAW, | ||
| model_name="nonexistent-model", | ||
| ) | ||
| assert_pods_healthy( | ||
| admin_client=admin_client, | ||
| isvc=negative_test_ovms_isvc, | ||
| initial_pod_state=initial_pod_state, | ||
| ) | ||
98 changes: 98 additions & 0 deletions
98
tests/model_serving/model_server/kserve/negative/test_malformed_json_payload.py
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,98 @@ | ||
| """Tests for malformed JSON payload handling in inference requests. | ||
|
|
||
| Jira: RHOAIENG-48279 | ||
| """ | ||
|
|
||
| from http import HTTPStatus | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
| from kubernetes.dynamic import DynamicClient | ||
| from ocp_resources.inference_service import InferenceService | ||
|
|
||
| from tests.model_serving.model_server.kserve.negative.utils import ( | ||
| assert_pods_healthy, | ||
| send_inference_request, | ||
| ) | ||
|
|
||
| pytestmark = pytest.mark.usefixtures("valid_aws_config") | ||
|
|
||
| MALFORMED_JSON_EXPECTED_CODES: set[int] = { | ||
| HTTPStatus.BAD_REQUEST, | ||
| HTTPStatus.PRECONDITION_FAILED, | ||
| } | ||
| MISSING_BRACE_BODY = '{"inputs": [{"name": "Input3"' | ||
| TRAILING_COMMA_BODY = '{"inputs": [{"name": "Input3",}]}' | ||
|
|
||
|
|
||
| @pytest.mark.tier1 | ||
| @pytest.mark.rawdeployment | ||
| class TestMalformedJsonPayload: | ||
| """Test class for verifying error handling when receiving malformed JSON payloads. | ||
|
|
||
| Preconditions: | ||
| - InferenceService deployed with OVMS runtime (RawDeployment) | ||
| - Model is ready and serving | ||
|
|
||
| Test Steps: | ||
| 1. Create InferenceService with OVMS runtime | ||
| 2. Wait for InferenceService status = Ready | ||
| 3. Send POST with malformed JSON bodies (missing brace, trailing comma, plain text) | ||
| 4. Verify error responses and pod health | ||
|
|
||
| Expected Results: | ||
| - HTTP Status Code: 400 Bad Request or 412 Precondition Failed | ||
| (OVMS returns 412 for JSON parse errors) | ||
| - Response indicates JSON parse failure | ||
| - No pod crash or restart | ||
| """ | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "malformed_body", | ||
| [ | ||
| pytest.param(MISSING_BRACE_BODY, id="missing_closing_brace"), | ||
| pytest.param(TRAILING_COMMA_BODY, id="trailing_comma"), | ||
| pytest.param("not json at all", id="plain_text"), | ||
| ], | ||
| ) | ||
| def test_malformed_json_returns_error( | ||
| self, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| malformed_body: str, | ||
| ) -> None: | ||
| """Verify that malformed JSON payloads return an error status code. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending a POST request with a malformed JSON body | ||
| Then the response should have HTTP status code 400 or 412 | ||
| """ | ||
| status_code, response_body = send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body=malformed_body, | ||
| ) | ||
|
|
||
| assert status_code in MALFORMED_JSON_EXPECTED_CODES, ( | ||
| f"Expected 400 or 412 for malformed JSON, got {status_code}. Response: {response_body}" | ||
| ) | ||
|
|
||
| def test_model_pod_remains_healthy_after_malformed_json( | ||
| self, | ||
| admin_client: DynamicClient, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| initial_pod_state: dict[str, dict[str, Any]], | ||
| ) -> None: | ||
| """Verify that the model pod remains healthy after receiving malformed JSON. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending requests with malformed JSON payloads | ||
| Then the same pods should still be running without additional restarts | ||
| """ | ||
| send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body=MISSING_BRACE_BODY, | ||
| ) | ||
| assert_pods_healthy( | ||
| admin_client=admin_client, | ||
| isvc=negative_test_ovms_isvc, | ||
| initial_pod_state=initial_pod_state, | ||
| ) |
91 changes: 91 additions & 0 deletions
91
tests/model_serving/model_server/kserve/negative/test_missing_required_fields.py
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,91 @@ | ||
| """Tests for missing required fields in inference requests. | ||
|
|
||
| Jira: RHOAIENG-48281 | ||
| """ | ||
|
|
||
| import json | ||
| from http import HTTPStatus | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
| from kubernetes.dynamic import DynamicClient | ||
| from ocp_resources.inference_service import InferenceService | ||
|
|
||
| from tests.model_serving.model_server.kserve.negative.utils import ( | ||
| assert_pods_healthy, | ||
| send_inference_request, | ||
| ) | ||
|
|
||
| pytestmark = pytest.mark.usefixtures("valid_aws_config") | ||
|
|
||
|
|
||
| @pytest.mark.tier1 | ||
| @pytest.mark.rawdeployment | ||
| class TestMissingRequiredFields: | ||
| """Test class for verifying error handling when required fields are missing. | ||
|
|
||
| Preconditions: | ||
| - InferenceService deployed with OVMS runtime | ||
| - Model is ready and serving | ||
|
|
||
| Test Steps: | ||
| 1. Create InferenceService with OVMS runtime | ||
| 2. Wait for InferenceService status = Ready | ||
| 3. Send POST with empty body {} | ||
| 4. Send POST with body missing "inputs" field | ||
| 5. Verify error responses and pod health | ||
|
|
||
| Expected Results: | ||
| - HTTP Status Code: 400 Bad Request | ||
| - Error message indicates missing required field | ||
| - No server crash | ||
| """ | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "incomplete_body", | ||
| [ | ||
| pytest.param("{}", id="empty_body"), | ||
| pytest.param(json.dumps({"id": "test-123"}), id="missing_inputs_field"), | ||
| ], | ||
| ) | ||
| def test_missing_required_fields_returns_400( | ||
| self, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| incomplete_body: str, | ||
| ) -> None: | ||
| """Verify that requests missing required fields return 400 status code. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending a POST request with missing required fields | ||
| Then the response should have HTTP status code 400 (Bad Request) | ||
| """ | ||
| status_code, response_body = send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body=incomplete_body, | ||
| ) | ||
|
|
||
| assert status_code == HTTPStatus.BAD_REQUEST, ( | ||
| f"Expected 400 Bad Request for incomplete payload, got {status_code}. Response: {response_body}" | ||
| ) | ||
|
|
||
| def test_model_pod_remains_healthy_after_missing_fields( | ||
| self, | ||
| admin_client: DynamicClient, | ||
| negative_test_ovms_isvc: InferenceService, | ||
| initial_pod_state: dict[str, dict[str, Any]], | ||
| ) -> None: | ||
| """Verify that the model pod remains healthy after receiving incomplete requests. | ||
|
|
||
| Given an InferenceService is deployed and ready | ||
| When sending requests with missing required fields | ||
| Then the same pods should still be running without additional restarts | ||
| """ | ||
| send_inference_request( | ||
| inference_service=negative_test_ovms_isvc, | ||
| body="{}", | ||
| ) | ||
| assert_pods_healthy( | ||
| admin_client=admin_client, | ||
| isvc=negative_test_ovms_isvc, | ||
| initial_pod_state=initial_pod_state, | ||
| ) |
Oops, something went wrong.
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.