From 3dd6395ae17f2b1e99d90f79ea46ec66f3468cf4 Mon Sep 17 00:00:00 2001 From: Rusiru Erandaka Date: Thu, 9 Jul 2026 09:14:25 +0530 Subject: [PATCH 1/4] validate president ID before fetching active portfolio list --- src/services/organisation_service.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/services/organisation_service.py b/src/services/organisation_service.py index 35db10a..ba50fe0 100644 --- a/src/services/organisation_service.py +++ b/src/services/organisation_service.py @@ -199,6 +199,13 @@ async def active_portfolio_list(self, president_id: str, selected_date: str): raise BadRequestError("Selected date is required") try: + president_node_data = await self.opengin_service.get_entities( + entity=Entity(id=president_id) + ) + + if not president_node_data: + raise NotFoundError("President not found for the given ID") + # First retrieve the relation list of the active portfolios under given president and given date relation = Relation(name=RelationNameEnum.AS_MINISTER.value,activeAt=Util.normalize_timestamp(selected_date),direction=RelationDirectionEnum.OUTGOING.value) activePortfolioList = await self.opengin_service.fetch_relation( From 291074e603b3b10997ef6b3109b67abd103948cc Mon Sep 17 00:00:00 2001 From: Rusiru Erandaka Date: Thu, 9 Jul 2026 09:14:41 +0530 Subject: [PATCH 2/4] add tests for invalid president ID validation --- test/test_organisation_service.py | 93 ++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/test/test_organisation_service.py b/test/test_organisation_service.py index ae33c7e..fe3e993 100644 --- a/test/test_organisation_service.py +++ b/test/test_organisation_service.py @@ -1,7 +1,7 @@ import pytest from unittest.mock import AsyncMock, patch, MagicMock from src.enums import EntityIdEnum, RelationDirectionEnum, RelationNameEnum -from src.exception import BadRequestError, InternalServerError +from src.exception import BadRequestError, InternalServerError, NotFoundError from src.models import Entity, Relation from src.utils import Util @@ -196,6 +196,97 @@ async def test_enrich_department_item_not_new( ) +@pytest.mark.asyncio +async def test_active_portfolio_list_invalid_president_id( + organisation_service, mock_opengin_service +): + president_id = "invalid_president_123" + selected_date = "2021-10-27" + + mock_opengin_service.get_entities.return_value = [] + + with pytest.raises(NotFoundError): + await organisation_service.active_portfolio_list( + president_id=president_id, selected_date=selected_date + ) + + mock_opengin_service.get_entities.assert_called_once_with( + entity=Entity(id=president_id) + ) + + +@pytest.mark.asyncio +async def test_active_portfolio_list_valid_president_id( + organisation_service, mock_opengin_service +): + president_id = "president_123" + selected_date = "2021-10-27" + + mock_opengin_service.get_entities.return_value = [ + Entity(id=president_id, name="mocked_protobuf_name") + ] + mock_opengin_service.fetch_relation.return_value = [ + Relation( + id="portfolio_relation_123", + relatedEntityId="portfolio_123", + name=RelationNameEnum.AS_MINISTER.value, + startTime="2020-08-09T00:00:00Z", + endTime="2022-03-08T00:00:00Z", + direction=RelationDirectionEnum.OUTGOING.value, + ) + ] + + with patch( + "src.services.organisation_service.OrganisationService.process_portfolio_item", + new_callable=AsyncMock, + ) as mock_process_portfolio_item: + mock_process_portfolio_item.return_value = { + "id": "portfolio_123", + "name": "Portfolio X", + "type": "cabinetMinister", + "isNew": False, + "ministers": [], + } + + result = await organisation_service.active_portfolio_list( + president_id=president_id, selected_date=selected_date + ) + + assert result == { + "NoOfCabinetMinistries": 1, + "NoOfStateMinistries": 0, + "newMinistries": 0, + "newMinisters": 0, + "ministriesUnderPresident": 0, + "portfolioList": [ + { + "id": "portfolio_123", + "name": "Portfolio X", + "type": "cabinetMinister", + "isNew": False, + "ministers": [], + } + ], + } + + mock_opengin_service.get_entities.assert_called_once_with( + entity=Entity(id=president_id) + ) + mock_opengin_service.fetch_relation.assert_called_once_with( + entityId=president_id, + relation=Relation( + name=RelationNameEnum.AS_MINISTER.value, + activeAt=f"{selected_date}T00:00:00Z", + direction=RelationDirectionEnum.OUTGOING.value, + ), + ) + mock_process_portfolio_item.assert_called_once_with( + mock_opengin_service.fetch_relation.return_value[0], + president_id, + selected_date, + ) + + @pytest.mark.asyncio async def test_departments_by_portfolio_id_success( organisation_service, mock_opengin_service From e3834ae0ca29af6201f58a9971b522d8b7cc6067 Mon Sep 17 00:00:00 2001 From: Rusiru Erandaka <124586352+rusiru-erandaka@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:48:14 +0530 Subject: [PATCH 3/4] use try/except for president validation per review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- test/test_organisation_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_organisation_service.py b/test/test_organisation_service.py index fe3e993..2e1c68f 100644 --- a/test/test_organisation_service.py +++ b/test/test_organisation_service.py @@ -203,7 +203,7 @@ async def test_active_portfolio_list_invalid_president_id( president_id = "invalid_president_123" selected_date = "2021-10-27" - mock_opengin_service.get_entities.return_value = [] + mock_opengin_service.get_entities.side_effect = NotFoundError("President not found") with pytest.raises(NotFoundError): await organisation_service.active_portfolio_list( From 22d1803eaa18d16967390463bb825da0e0e3fd3a Mon Sep 17 00:00:00 2001 From: Rusiru Erandaka <124586352+rusiru-erandaka@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:50:34 +0530 Subject: [PATCH 4/4] Added try-except block to catch NotFoundError Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/services/organisation_service.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/organisation_service.py b/src/services/organisation_service.py index ba50fe0..2e18a4b 100644 --- a/src/services/organisation_service.py +++ b/src/services/organisation_service.py @@ -199,12 +199,12 @@ async def active_portfolio_list(self, president_id: str, selected_date: str): raise BadRequestError("Selected date is required") try: - president_node_data = await self.opengin_service.get_entities( - entity=Entity(id=president_id) - ) - - if not president_node_data: - raise NotFoundError("President not found for the given ID") + try: + await self.opengin_service.get_entities( + entity=Entity(id=president_id) + ) + except NotFoundError as e: + raise NotFoundError("President not found for the given ID") from e # First retrieve the relation list of the active portfolios under given president and given date relation = Relation(name=RelationNameEnum.AS_MINISTER.value,activeAt=Util.normalize_timestamp(selected_date),direction=RelationDirectionEnum.OUTGOING.value)