Loading src/api/handlers/restconf_handler.py +9 −2 Changes for src/api/handlers/restconf_handler.py: 9 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -1038,9 +1038,16 @@ class RestconfHandler: if not existing_slice: raise ValueError(f"There is no slice with id '{slice_id}' registered") template_id = safe_get( existing_slice, ["network-slice-services", "slice-service", slice_id, "slo-sle-template"] # slice-service is a list after normalize_libyang_data, so look the slice up by id slice_list = safe_get(existing_slice, ["network-slice-services", "slice-service"]) or [] slice_item = next( (item for item in slice_list if isinstance(item, dict) and item.get("id") == slice_id), None ) template_id = slice_item.get("slo-sle-template") if slice_item else None if not template_id: raise ValueError(f"Slice '{slice_id}' has no SLO/SLE template assigned") logger.debug("Using SLO/SLE template '%s' for slice '%s'", template_id, slice_id) slo_sle_template = self.get_slo_sle_templates(template_id)[0] slo_sle_template = safe_get( slo_sle_template, ["network-slice-services", "slo-sle-templates", "slo-sle-template"] Loading src/tests/test_api.py +34 −5 Changes for src/tests/test_api.py: 34 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -514,9 +514,14 @@ class TestTelemetryStreams: res, code = api.get_telemetry("nonexistent-slice") assert code == 404 # More than 2 SDPs error # Malformed slice data without a template -> 404 with patch("src.api.main.get_data_store", return_value=[1, 2, 3]): res, code = api.get_telemetry("slice-many-sdps") res, code = api.get_telemetry("slice-malformed") assert code == 404 # Unexpected datastore error -> 500 with patch("src.api.main.get_data_store", side_effect=RuntimeError("sysrepo down")): res, code = api.get_telemetry("slice-error") assert code == 500 def test_get_telemetry_history(self, controller_with_mocked_db): Loading Loading @@ -1332,9 +1337,9 @@ class TestApiRequestedMethodsCoverage: api = Api(controller_with_mocked_db) # Single slice telemetry success existing_slice = {"network-slice-services": {"slice-service": {"s1": {"slo-sle-template": "tmpl-1"}}}} existing_slice = {"network-slice-services": {"slice-service": [{"id": "s1", "slo-sle-template": "tmpl-1"}]}} tmpl_data = [ {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": {"tmpl-1": {"id": "tmpl-1"}}}}} {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": [{"id": "tmpl-1"}]}}} ] with ( patch("src.api.main.get_data_store", return_value=existing_slice), Loading @@ -1350,8 +1355,14 @@ class TestApiRequestedMethodsCoverage: res_no_slice, code_no_slice = api.get_telemetry("s1") assert code_no_slice == 404 # Single slice telemetry - slice without template -> 404 no_tmpl_slice = {"network-slice-services": {"slice-service": [{"id": "s1"}]}} with patch("src.api.main.get_data_store", return_value=no_tmpl_slice): _, code_unassigned = api.get_telemetry("s1") assert code_unassigned == 404 # Single slice telemetry - template not found -> 404 empty_tmpl_data = [{"network-slice-services": {"slo-sle-templates": {"slo-sle-template": {}}}}] empty_tmpl_data = [{"network-slice-services": {"slo-sle-templates": {"slo-sle-template": []}}}] with ( patch("src.api.main.get_data_store", return_value=existing_slice), patch.object(api, "get_slo_sle_templates", return_value=empty_tmpl_data), Loading @@ -1372,6 +1383,24 @@ class TestApiRequestedMethodsCoverage: assert code_all == 200 assert "s1" in res_all def test_get_single_slice_telemetry_uses_slice_template(self, controller_with_mocked_db): """The slice's own template is used, not the first one stored in sysrepo.""" api = Api(controller_with_mocked_db) existing_slice = {"network-slice-services": {"slice-service": [{"id": "s1", "slo-sle-template": "gold"}]}} gold = {"id": "gold", "slo-policy": {"metric-bound": [{"metric-type": "two-way-delay-maximum", "bound": 5}]}} gold_data = {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": [gold]}}} with ( patch("src.api.main.get_data_store", return_value=existing_slice), patch.object(api, "get_slo_sle_templates", return_value=(gold_data, 200)) as mock_templates, patch.object(api.slice_service, "monitoring", return_value={"ok": True}) as mock_monitoring, ): _, code = api.get_telemetry("s1") assert code == 200 mock_templates.assert_called_once_with("gold") mock_monitoring.assert_called_once_with("s1", gold) def test_sync_stream_and_streams_coverage(self, controller_with_mocked_db): api = Api(controller_with_mocked_db) Loading Loading
src/api/handlers/restconf_handler.py +9 −2 Changes for src/api/handlers/restconf_handler.py: 9 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -1038,9 +1038,16 @@ class RestconfHandler: if not existing_slice: raise ValueError(f"There is no slice with id '{slice_id}' registered") template_id = safe_get( existing_slice, ["network-slice-services", "slice-service", slice_id, "slo-sle-template"] # slice-service is a list after normalize_libyang_data, so look the slice up by id slice_list = safe_get(existing_slice, ["network-slice-services", "slice-service"]) or [] slice_item = next( (item for item in slice_list if isinstance(item, dict) and item.get("id") == slice_id), None ) template_id = slice_item.get("slo-sle-template") if slice_item else None if not template_id: raise ValueError(f"Slice '{slice_id}' has no SLO/SLE template assigned") logger.debug("Using SLO/SLE template '%s' for slice '%s'", template_id, slice_id) slo_sle_template = self.get_slo_sle_templates(template_id)[0] slo_sle_template = safe_get( slo_sle_template, ["network-slice-services", "slo-sle-templates", "slo-sle-template"] Loading
src/tests/test_api.py +34 −5 Changes for src/tests/test_api.py: 34 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -514,9 +514,14 @@ class TestTelemetryStreams: res, code = api.get_telemetry("nonexistent-slice") assert code == 404 # More than 2 SDPs error # Malformed slice data without a template -> 404 with patch("src.api.main.get_data_store", return_value=[1, 2, 3]): res, code = api.get_telemetry("slice-many-sdps") res, code = api.get_telemetry("slice-malformed") assert code == 404 # Unexpected datastore error -> 500 with patch("src.api.main.get_data_store", side_effect=RuntimeError("sysrepo down")): res, code = api.get_telemetry("slice-error") assert code == 500 def test_get_telemetry_history(self, controller_with_mocked_db): Loading Loading @@ -1332,9 +1337,9 @@ class TestApiRequestedMethodsCoverage: api = Api(controller_with_mocked_db) # Single slice telemetry success existing_slice = {"network-slice-services": {"slice-service": {"s1": {"slo-sle-template": "tmpl-1"}}}} existing_slice = {"network-slice-services": {"slice-service": [{"id": "s1", "slo-sle-template": "tmpl-1"}]}} tmpl_data = [ {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": {"tmpl-1": {"id": "tmpl-1"}}}}} {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": [{"id": "tmpl-1"}]}}} ] with ( patch("src.api.main.get_data_store", return_value=existing_slice), Loading @@ -1350,8 +1355,14 @@ class TestApiRequestedMethodsCoverage: res_no_slice, code_no_slice = api.get_telemetry("s1") assert code_no_slice == 404 # Single slice telemetry - slice without template -> 404 no_tmpl_slice = {"network-slice-services": {"slice-service": [{"id": "s1"}]}} with patch("src.api.main.get_data_store", return_value=no_tmpl_slice): _, code_unassigned = api.get_telemetry("s1") assert code_unassigned == 404 # Single slice telemetry - template not found -> 404 empty_tmpl_data = [{"network-slice-services": {"slo-sle-templates": {"slo-sle-template": {}}}}] empty_tmpl_data = [{"network-slice-services": {"slo-sle-templates": {"slo-sle-template": []}}}] with ( patch("src.api.main.get_data_store", return_value=existing_slice), patch.object(api, "get_slo_sle_templates", return_value=empty_tmpl_data), Loading @@ -1372,6 +1383,24 @@ class TestApiRequestedMethodsCoverage: assert code_all == 200 assert "s1" in res_all def test_get_single_slice_telemetry_uses_slice_template(self, controller_with_mocked_db): """The slice's own template is used, not the first one stored in sysrepo.""" api = Api(controller_with_mocked_db) existing_slice = {"network-slice-services": {"slice-service": [{"id": "s1", "slo-sle-template": "gold"}]}} gold = {"id": "gold", "slo-policy": {"metric-bound": [{"metric-type": "two-way-delay-maximum", "bound": 5}]}} gold_data = {"network-slice-services": {"slo-sle-templates": {"slo-sle-template": [gold]}}} with ( patch("src.api.main.get_data_store", return_value=existing_slice), patch.object(api, "get_slo_sle_templates", return_value=(gold_data, 200)) as mock_templates, patch.object(api.slice_service, "monitoring", return_value={"ok": True}) as mock_monitoring, ): _, code = api.get_telemetry("s1") assert code == 200 mock_templates.assert_called_once_with("gold") mock_monitoring.assert_called_once_with("s1", gold) def test_sync_stream_and_streams_coverage(self, controller_with_mocked_db): api = Api(controller_with_mocked_db) Loading