Make SDNC healthcheck in tests backwards compatible 40/143140/3
authorFiete Ostkamp <fiete.ostkamp@telekom.de>
Mon, 9 Feb 2026 14:27:49 +0000 (15:27 +0100)
committerFiete Ostkamp <fiete.ostkamp@telekom.de>
Mon, 9 Feb 2026 14:51:48 +0000 (15:51 +0100)
- expect 204 No Content response or
- 200 response with content

Issue-ID: INT-2351
Change-Id: Ib22f323a163f081d29d7d2e2fb5a5759b6226acc
Signed-off-by: Fiete Ostkamp <fiete.ostkamp@telekom.de>
src/onaptests/steps/instantiate/sdnc_service.py
tests/test_sdnc_health_check.py [new file with mode: 0644]

index 58d20ea..d3e03a1 100644 (file)
@@ -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 (file)
index 0000000..9535998
--- /dev/null
@@ -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"