diff --git a/.coverage b/.coverage index ba766307e0278a19bffe62b2ae4dc47fc924e6c5..1862db14a5396d8631739e7cbc31d7fd5032d8f6 100644 Binary files a/.coverage and b/.coverage differ diff --git a/coverage.xml b/coverage.xml index 017aa010d5e2ed740c2984013533687d6b421d4b..c75f163eba717f8708e8fa4219c7fb6f608f2300 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,5 +1,5 @@ - + @@ -61,7 +61,7 @@ - + @@ -210,51 +210,86 @@ - - - - - + + + + + + - - - - - + + + + - + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -463,29 +498,27 @@ - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -499,11 +532,11 @@ + - - + @@ -517,11 +550,11 @@ + - - + @@ -536,11 +569,11 @@ + - - + @@ -554,17 +587,99 @@ + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/edge_cloud_management_api/controllers/federation_manager_controller.py b/edge_cloud_management_api/controllers/federation_manager_controller.py index b7d0fbde28a78b0395f244f7962501296054c3c2..6e872c82fd829b53ecd59f33469b6c0e4fac3e30 100644 --- a/edge_cloud_management_api/controllers/federation_manager_controller.py +++ b/edge_cloud_management_api/controllers/federation_manager_controller.py @@ -1,8 +1,6 @@ from flask import request, jsonify from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory -factory = FederationManagerClientFactory() -federation_client = factory.create_federation_client() def create_federation(): """ @@ -10,6 +8,8 @@ def create_federation(): Forwards the federation creation request to Federation Manager. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() body = request.get_json() result = federation_client.post_partner(body) return jsonify(result), 200 if "error" not in result else 502 @@ -23,6 +23,8 @@ def get_federation(federationContextId): Forwards the GET federation info request. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() result = federation_client.get_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: @@ -35,6 +37,8 @@ def delete_federation(federationContextId): Forwards the DELETE federation request. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() result = federation_client.delete_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: @@ -47,45 +51,53 @@ def get_federation_context_ids(): Forwards the request to fetch federation context IDs. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() result = federation_client.get_federation_context_ids() return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 - - - - + + def onboard_application_to_partner(federationContextId): """ POST /{federationContextId}/application/onboarding Forwards the onboarding request to the Federation Manager. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() body = request.get_json() result = federation_client.onboard_application(federationContextId, body) return jsonify(result), 202 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 - + + def get_onboarded_app(federationContextId, appId): """ GET /{federationContextId}/application/onboarding/app/{appId} Retrieves onboarding info of a federated app from a partner OP. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() result = federation_client.get_onboarded_app(federationContextId, appId) if "error" in result: return jsonify(result), result.get("status_code", 502) return jsonify(result), 200 except Exception as e: return jsonify({"error": str(e)}), 500 - + + def delete_onboarded_app(federationContextId, appId): """ DELETE /{federationContextId}/application/onboarding/app/{appId} Deboards the application and deletes it from the partner OP. """ try: + factory = FederationManagerClientFactory() + federation_client = factory.create_federation_client() result = federation_client.delete_onboarded_app(federationContextId, appId) if "error" in result: return jsonify(result), result.get("status_code", 502) diff --git a/results.txt b/results.txt new file mode 100644 index 0000000000000000000000000000000000000000..7208eea3b558a7030bc6f30497379606cba80906 --- /dev/null +++ b/results.txt @@ -0,0 +1,170 @@ +lint: commands[0]> ruff check edge_cloud_management_api tests +All checks passed! +lint: OK ✔ in 0.1 seconds +type: commands[0]> mypy edge_cloud_management_api tests +edge_cloud_management_api/managers/db_manager.py:32: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked] +Success: no issues found in 28 source files +type: OK ✔ in 0.7 seconds +.pkg: _optional_hooks> python /home/gpapathan/Desktop/etsi/open-exposure-gateway/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True hatchling.build +.pkg: get_requires_for_build_wheel> python /home/gpapathan/Desktop/etsi/open-exposure-gateway/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True hatchling.build +.pkg: build_wheel> python /home/gpapathan/Desktop/etsi/open-exposure-gateway/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True hatchling.build +3.12: install_package> python -I -m pip install --force-reinstall --no-deps /home/gpapathan/Desktop/etsi/open-exposure-gateway/.tox/.tmp/package/24/edge_cloud_management_api-0.1.0-py3-none-any.whl +3.12: commands[0]> pytest --cov=edge_cloud_management_api --cov-report=xml --cov-report=term-missing tests/ +============================= test session starts ============================== +platform linux -- Python 3.12.10, pytest-8.4.1, pluggy-1.6.0 +cachedir: .tox/3.12/.pytest_cache +rootdir: /home/gpapathan/Desktop/etsi/open-exposure-gateway +configfile: pyproject.toml +plugins: cov-6.2.1, anyio-4.9.0 +collected 15 items + +tests/component/controllers/test_app_controllers.py .... [ 26%] +tests/unit/controllers/test_edge_cloud_controller.py ....... [ 73%] +tests/unit/controllers/test_federation_manager_controller.py FFFF [100%] + +=================================== FAILURES =================================== +____________________________ test_create_federation ____________________________ + +mock_factory_class = +test_app = + + @pytest.mark.component + @patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") + def test_create_federation(mock_factory_class, test_app: Flask): + """Test create_federation returns federation data""" + body = { + "origOPFederationId": "orig-123", + "initialDate": "2024-01-01T00:00:00Z", + "partnerStatusLink": "https://callback.example.com/status" + } + + mock_client = MagicMock() + mock_client.post_partner.return_value = {"federationContextId": "abc", "partnerOPFederationId": "partner-xyz"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(json=body): + response, status = federation_manager_controller.create_federation() + +> assert status == 200 +E assert 502 == 200 + +tests/unit/controllers/test_federation_manager_controller.py:32: AssertionError +------------------------------ Captured log call ------------------------------- +ERROR Edge Cloud Management API:federation_services.py:30 POST /partner connection error +_____________________________ test_get_federation ______________________________ + +mock_factory_class = +test_app = + + @pytest.mark.component + @patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") + def test_get_federation(mock_factory_class, test_app: Flask): + federation_context_id = "abc" + + mock_client = MagicMock() + mock_client.get_partner.return_value = {"some": "data"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.get_federation(federation_context_id) + +> assert status == 200 +E assert 502 == 200 + +tests/unit/controllers/test_federation_manager_controller.py:50: AssertionError +------------------------------ Captured log call ------------------------------- +ERROR Edge Cloud Management API:federation_services.py:49 GET /{id}/partner connection error +____________________________ test_delete_federation ____________________________ + +mock_factory_class = +test_app = + + @pytest.mark.component + @patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") + def test_delete_federation(mock_factory_class, test_app: Flask): + federation_context_id = "abc" + + mock_client = MagicMock() + mock_client.delete_partner.return_value = {"result": "Deleted"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.delete_federation(federation_context_id) + +> assert status == 200 +E assert 502 == 200 + +tests/unit/controllers/test_federation_manager_controller.py:66: AssertionError +------------------------------ Captured log call ------------------------------- +ERROR Edge Cloud Management API:federation_services.py:69 DELETE /{id}/partner connection error +_______________________ test_get_federation_context_ids ________________________ + +mock_factory_class = +test_app = + + @pytest.mark.component + @patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") + def test_get_federation_context_ids(mock_factory_class, test_app: Flask): + mock_client = MagicMock() + mock_client.get_federation_context_ids.return_value = {"FederationContextId": "ctx-123"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.get_federation_context_ids() + +> assert status == 200 +E assert 502 == 200 + +tests/unit/controllers/test_federation_manager_controller.py:80: AssertionError +------------------------------ Captured log call ------------------------------- +ERROR Edge Cloud Management API:federation_services.py:88 GET /fed-context-id connection error +=============================== warnings summary =============================== +.tox/3.12/lib/python3.12/site-packages/connexion/json_schema.py:16 +.tox/3.12/lib/python3.12/site-packages/connexion/json_schema.py:16 + /home/gpapathan/Desktop/etsi/open-exposure-gateway/.tox/3.12/lib/python3.12/site-packages/connexion/json_schema.py:16: DeprecationWarning: jsonschema.RefResolver is deprecated as of v4.18.0, in favor of the https://github.com/python-jsonschema/referencing library, which provides more compliant referencing behavior as well as more flexible APIs for customization. A future release will remove RefResolver. Please file a feature request (on referencing) if you are missing an API for the kind of customization you need. + from jsonschema import Draft4Validator, RefResolver + +.tox/3.12/lib/python3.12/site-packages/connexion/json_schema.py:17 + /home/gpapathan/Desktop/etsi/open-exposure-gateway/.tox/3.12/lib/python3.12/site-packages/connexion/json_schema.py:17: DeprecationWarning: jsonschema.exceptions.RefResolutionError is deprecated as of version 4.18.0. If you wish to catch potential reference resolution errors, directly catch referencing.exceptions.Unresolvable. + from jsonschema.exceptions import RefResolutionError, ValidationError # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.12.10-final-0 _______________ + +Name Stmts Miss Cover Missing +------------------------------------------------------------------------------------------------------ +edge_cloud_management_api/__main__.py 4 4 0% 1-5 +edge_cloud_management_api/app.py 12 2 83% 19-20 +edge_cloud_management_api/configs/__init__.py 0 0 100% +edge_cloud_management_api/configs/env_config.py 12 0 100% +edge_cloud_management_api/controllers/__init__.py 0 0 100% +edge_cloud_management_api/controllers/app_controllers.py 99 47 53% 16-26, 34-40, 48-61, 75-82, 101, 118-119, 126-128, 134-139, 155, 163-165, 180-181 +edge_cloud_management_api/controllers/edge_cloud_controller.py 47 20 57% 35-49, 54, 62-67, 93, 97, 108-114 +edge_cloud_management_api/controllers/federation_manager_controller.py 52 28 46% 16-17, 28-29, 40-41, 52-53, 63-68, 75-81, 88-94 +edge_cloud_management_api/managers/__init__.py 0 0 100% +edge_cloud_management_api/managers/db_manager.py 33 33 0% 1-83 +edge_cloud_management_api/managers/log_manager.py 7 0 100% +edge_cloud_management_api/models/__init__.py 0 0 100% +edge_cloud_management_api/models/application_models.py 62 62 0% 8-92 +edge_cloud_management_api/models/edge_cloud_models.py 13 13 0% 1-17 +edge_cloud_management_api/models/error_models.py 5 5 0% 1-7 +edge_cloud_management_api/models/federation_manager_models.py 38 38 0% 1-52 +edge_cloud_management_api/services/__init__.py 0 0 100% +edge_cloud_management_api/services/federation_services.py 173 119 31% 24-25, 27-28, 32-37, 43-44, 46-47, 51-56, 62-64, 66-67, 71-76, 82-83, 85-86, 90-95, 98-114, 118-134, 137-153, 166-210, 214-218 +edge_cloud_management_api/services/pi_edge_services.py 155 133 14% 15-18, 23-25, 32-50, 60, 69-95, 102-115, 124-137, 146-164, 170-188, 195-207, 217-229, 239-247, 274-276, 290-297, 301-305 +------------------------------------------------------------------------------------------------------ +TOTAL 712 504 29% +Coverage XML written to file coverage.xml +=========================== short test summary info ============================ +FAILED tests/unit/controllers/test_federation_manager_controller.py::test_create_federation +FAILED tests/unit/controllers/test_federation_manager_controller.py::test_get_federation +FAILED tests/unit/controllers/test_federation_manager_controller.py::test_delete_federation +FAILED tests/unit/controllers/test_federation_manager_controller.py::test_get_federation_context_ids +=================== 4 failed, 11 passed, 3 warnings in 5.47s =================== +3.12: exit 1 (6.25 seconds) /home/gpapathan/Desktop/etsi/open-exposure-gateway> pytest --cov=edge_cloud_management_api --cov-report=xml --cov-report=term-missing tests/ pid=42931 +.pkg: _exit> python /home/gpapathan/Desktop/etsi/open-exposure-gateway/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True hatchling.build + lint: OK (0.09=setup[0.07]+cmd[0.02] seconds) + type: OK (0.70=setup[0.02]+cmd[0.68] seconds) + 3.12: FAIL code 1 (7.48=setup[1.23]+cmd[6.25] seconds) + evaluation failed :( (8.38 seconds) diff --git a/tests/unit/controllers/test_federation_manager_controller.py b/tests/unit/controllers/test_federation_manager_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..cac78b3752b24faa025779396cd2f527a8ba4628 --- /dev/null +++ b/tests/unit/controllers/test_federation_manager_controller.py @@ -0,0 +1,81 @@ +import pytest +from unittest.mock import patch, MagicMock +from flask import Flask +from edge_cloud_management_api.controllers import federation_manager_controller + + +@pytest.fixture +def test_app(): + app = Flask(__name__) + app.config["TESTING"] = True + with app.app_context(): + yield app + + +@pytest.mark.component +@patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") +def test_create_federation(mock_factory_class, test_app: Flask): + """Test create_federation returns federation data""" + body = { + "origOPFederationId": "orig-123", + "initialDate": "2024-01-01T00:00:00Z", + "partnerStatusLink": "https://callback.example.com/status" + } + + mock_client = MagicMock() + mock_client.post_partner.return_value = {"federationContextId": "abc", "partnerOPFederationId": "partner-xyz"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(json=body): + response, status = federation_manager_controller.create_federation() + + assert status == 200 + data = response.get_json() + assert "federationContextId" in data + assert data["federationContextId"] == "abc" + + +@pytest.mark.component +@patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") +def test_get_federation(mock_factory_class, test_app: Flask): + federation_context_id = "abc" + + mock_client = MagicMock() + mock_client.get_partner.return_value = {"some": "data"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.get_federation(federation_context_id) + + assert status == 200 + assert response.get_json() == {"some": "data"} + + +@pytest.mark.component +@patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") +def test_delete_federation(mock_factory_class, test_app: Flask): + federation_context_id = "abc" + + mock_client = MagicMock() + mock_client.delete_partner.return_value = {"result": "Deleted"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.delete_federation(federation_context_id) + + assert status == 200 + assert response.get_json() == {"result": "Deleted"} + + +@pytest.mark.component +@patch("edge_cloud_management_api.controllers.federation_manager_controller.FederationManagerClientFactory") +def test_get_federation_context_ids(mock_factory_class, test_app: Flask): + mock_client = MagicMock() + mock_client.get_federation_context_ids.return_value = {"FederationContextId": "ctx-123"} + mock_factory_class.return_value.create_federation_client.return_value = mock_client + + with test_app.test_request_context(): + response, status = federation_manager_controller.get_federation_context_ids() + + assert status == 200 + assert response.get_json() == {"FederationContextId": "ctx-123"}