From 621882fe14549b22d6a9b68878fd8a87a945d799 Mon Sep 17 00:00:00 2001 From: Fiete Ostkamp Date: Mon, 9 Feb 2026 15:27:49 +0100 Subject: [PATCH] Make SDNC healthcheck in tests backwards compatible - expect 204 No Content response or - 200 response with content Issue-ID: INT-2351 Change-Id: Ib22f323a163f081d29d7d2e2fb5a5759b6226acc Signed-off-by: Fiete Ostkamp --- src/onaptests/steps/instantiate/sdnc_service.py | 7 + tests/test_sdnc_health_check.py | 182 ++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 tests/test_sdnc_health_check.py diff --git a/src/onaptests/steps/instantiate/sdnc_service.py b/src/onaptests/steps/instantiate/sdnc_service.py index 58d20ea..d3e03a1 100644 --- a/src/onaptests/steps/instantiate/sdnc_service.py +++ b/src/onaptests/steps/instantiate/sdnc_service.py @@ -279,8 +279,15 @@ class CheckSdncHealthStep(BaseSdncStep, SdncElement): "SDNC SLI API Healthcheck", f"{self.base_url}/rests/operations/SLI-API:healthcheck", ) + # Newer versions of SDNC return 204 No Content for healthy response if response and response.status_code == 204: return + # Older versions of SDNC return 200 OK with JSON body for healthy response + if response and response.status_code == 200: + result = response.json() + if result and result["SLI-API:output"]: + if result["SLI-API:output"]["response-code"] == "200": + return raise OnapTestException( "SDNC is not healthy. Status code %s" % response.status_code ) diff --git a/tests/test_sdnc_health_check.py b/tests/test_sdnc_health_check.py new file mode 100644 index 0000000..9535998 --- /dev/null +++ b/tests/test_sdnc_health_check.py @@ -0,0 +1,182 @@ +"""Simplified test module for SDNC health check functionality.""" + +import sys +from unittest import mock +import pytest +from onaptests.utils.exceptions import OnapTestException +from onaptests.steps.instantiate.sdnc_service import CheckSdncHealthStep + +# Mock ExceptionGroup for Python < 3.11 +if sys.version_info < (3, 11): + import builtins + + builtins.ExceptionGroup = type("ExceptionGroup", (Exception,), {}) + +# Mock modules before any imports to avoid dependency issues +sys.modules["opentelemetry"] = mock.MagicMock() +sys.modules["opentelemetry.trace"] = mock.MagicMock() +sys.modules["opentelemetry.sdk"] = mock.MagicMock() +sys.modules["opentelemetry.sdk.trace"] = mock.MagicMock() +sys.modules["opentelemetry.sdk.resources"] = mock.MagicMock() +sys.modules["onaptests.utils.kubernetes"] = mock.MagicMock() +sys.modules["kubernetes"] = mock.MagicMock() +sys.modules["kubernetes.client"] = mock.MagicMock() +sys.modules["kubernetes.config"] = mock.MagicMock() +sys.modules["mysql"] = mock.MagicMock() +sys.modules["mysql.connector"] = mock.MagicMock() +sys.modules["mysql.connector.errors"] = mock.MagicMock() +sys.modules["xtesting"] = mock.MagicMock() +sys.modules["xtesting.core"] = mock.MagicMock() +sys.modules["xtesting.core.testcase"] = mock.MagicMock() + +# Mock onapsdk before importing - create a proper mock with settings +mock_settings = mock.MagicMock() +mock_settings.LOG_CONFIG = {"version": 1} # Minimal valid logging config + + +# Create a real exception class for SDKException +class MockSDKException(Exception): + """Mock SDK Exception.""" + + pass + + +# Create mock SdncElement with proper metaclass +mock_sdnc_element_module = mock.MagicMock() + + +# Create a simple base class to avoid metaclass conflicts +class MockSdncElement: + """Mock SDNC Element for testing.""" + + headers = {} # Add headers attribute needed by CheckSdncHealthStep + base_url = "http://mock-sdnc" # Add base_url attribute + + def send_message(self, method, description, url, **kwargs): + """Mock send_message method.""" + pass + + +mock_sdnc_element_module.SdncElement = MockSdncElement + +sys.modules["onapsdk"] = mock.MagicMock() +sys.modules["onapsdk.aai"] = mock.MagicMock() +sys.modules["onapsdk.aai.business"] = mock.MagicMock() +sys.modules["onapsdk.aai.cloud_infrastructure"] = mock.MagicMock() +sys.modules["onapsdk.aai.service_design_and_creation"] = mock.MagicMock() +sys.modules["onapsdk.configuration"] = mock.MagicMock(settings=mock_settings) +sys.modules["onapsdk.exceptions"] = mock.MagicMock(SDKException=MockSDKException) +sys.modules["onapsdk.sdc"] = mock.MagicMock() +sys.modules["onapsdk.sdc.service"] = mock.MagicMock() +sys.modules["onapsdk.sdnc"] = mock.MagicMock() +sys.modules["onapsdk.sdnc.preload"] = mock.MagicMock() +sys.modules["onapsdk.sdnc.sdnc_element"] = mock_sdnc_element_module +sys.modules["onapsdk.sdnc.services"] = mock.MagicMock() +sys.modules["onapsdk.so"] = mock.MagicMock() +sys.modules["onapsdk.so.instantiation"] = mock.MagicMock() +sys.modules["onapsdk.utils"] = mock.MagicMock() +sys.modules["onapsdk.utils.headers_creator"] = mock.MagicMock() + +# Now we can import safely +sys.path.insert(0, "src") + + +def test_sdnc_health_check_204_no_content(): + """Test SDNC health check with 204 No Content (new version).""" + mock_response = mock.MagicMock() + mock_response.status_code = 204 + + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=mock_response): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + # Should execute without exception + step.execute() + + +def test_sdnc_health_check_200_with_valid_json(): + """Test SDNC health check with 200 and valid JSON (old version).""" + mock_response = mock.MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = {"SLI-API:output": {"response-code": "200"}} + + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=mock_response): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + # Should execute without exception + step.execute() + + +def test_sdnc_health_check_200_with_error_response_code(): + """Test SDNC health check with 200 but error response code.""" + mock_response = mock.MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = {"SLI-API:output": {"response-code": "500"}} + + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=mock_response): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + with pytest.raises(OnapTestException, match="not healthy"): + step.execute() + + +def test_sdnc_health_check_500_error(): + """Test SDNC health check with 500 error.""" + mock_response = mock.MagicMock() + mock_response.status_code = 500 + + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=mock_response): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + with pytest.raises(OnapTestException, match="not healthy.*500"): + step.execute() + + +def test_sdnc_health_check_503_unavailable(): + """Test SDNC health check with 503 Service Unavailable.""" + mock_response = mock.MagicMock() + mock_response.status_code = 503 + + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=mock_response): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + with pytest.raises(OnapTestException, match="not healthy.*503"): + step.execute() + + +def test_sdnc_health_check_no_response(): + """Test SDNC health check with no response.""" + step = CheckSdncHealthStep() + step._is_validation_only = False + + with mock.patch.object(step, "send_message", return_value=None): + with mock.patch.object(step, "check_preconditions", return_value=True): + with mock.patch.object(step, "_execute_substeps", return_value=None): + with pytest.raises((OnapTestException, AttributeError)): + step.execute() + + +def test_sdnc_health_check_step_description(): + """Test CheckSdncHealthStep description property.""" + step = CheckSdncHealthStep() + assert step.description == "Check SDNC Health API response." + + +def test_sdnc_health_check_step_component(): + """Test CheckSdncHealthStep component property.""" + step = CheckSdncHealthStep() + assert step.component == "SDNC" -- 2.16.6