diff --git a/app/routes/geostore/geostore.py b/app/routes/geostore/geostore.py index 53849c0f..6e19d246 100644 --- a/app/routes/geostore/geostore.py +++ b/app/routes/geostore/geostore.py @@ -55,7 +55,7 @@ async def add_new_geostore( If request follows RW style forward to RW, otherwise create in Data API """ if isinstance(request, RWGeostoreIn): - result: RWGeostoreResponse = await create_rw_geostore(request.dict(), x_api_key) + result: RWGeostoreResponse = await create_rw_geostore(request, x_api_key) return result # Otherwise, meant for GFW Data API geostore try: diff --git a/app/utils/rw_api.py b/app/utils/rw_api.py index a1071dd5..04da6847 100644 --- a/app/utils/rw_api.py +++ b/app/utils/rw_api.py @@ -20,6 +20,7 @@ RWAdminListResponse, RWCalcAreaForGeostoreResponse, RWFindByIDsResponse, + RWGeostoreIn, RWGeostoreResponse, RWViewGeostoreResponse, ) @@ -197,19 +198,19 @@ async def signup(name: str, email: str) -> User: async def create_rw_geostore( - payload: Dict, x_api_key: str | None = None + payload: RWGeostoreIn, x_api_key: str | None = None ) -> RWGeostoreResponse: url = f"{RW_API_URL}/v1/geostore" async with AsyncClient() as client: if x_api_key is not None: response: HTTPXResponse = await client.post( - url, json=payload, headers={"x-api-key": x_api_key} + url, json=payload.dict(), headers={"x-api-key": x_api_key} ) else: - response = await client.post(url, json=payload) + response = await client.post(url, json=payload.dict()) - if response.status_code == 200: + if response.status_code == 201: return RWGeostoreResponse.parse_obj(response.json()) else: raise HTTPException(response.status_code, response.text) diff --git a/tests_v2/unit/app/routes/geostore/test_geostore.py b/tests_v2/unit/app/routes/geostore/test_geostore.py index 1555b9a7..d8dfb616 100644 --- a/tests_v2/unit/app/routes/geostore/test_geostore.py +++ b/tests_v2/unit/app/routes/geostore/test_geostore.py @@ -1,10 +1,12 @@ from functools import partial +from unittest.mock import AsyncMock, MagicMock import pytest from _pytest.monkeypatch import MonkeyPatch from httpx import AsyncClient, MockTransport, Request, Response -from app.models.pydantic.geostore import RWGeostoreResponse +from app.crud import geostore as crud_geostore +from app.models.pydantic.geostore import Geostore, RWGeostoreResponse from app.routes.geostore import geostore from app.utils import rw_api @@ -18,11 +20,65 @@ { "geostoreId": "23b11bc0d0b417d3af08bca543fc2d0b", # pragma: allowlist secret "iso": "ABW", - }, # pragma: allowlist secret + }, ] } +example_admin_geostore_snipped = { + "data": { + "type": "geoStore", + "id": "851679102625f53c3254df99efbfba17", # pragma: allowlist secret + "attributes": { + "geojson": { + "crs": {}, + "features": [ + { + "geometry": { + "coordinates": [ + [ + [ + [-102.44799041748, 21.6610717773437], + [-102.455261230469, 21.6625995635987], + [-102.460227966309, 21.6666717529297], + [-102.443138122558, 21.6583995819092], + [-102.44799041748, 21.6610717773437], + [-102.44799041748, 21.6610717773437], + ] + ] + ], + "type": "MultiPolygon", + }, + "properties": None, + "type": "Feature", + } + ], + "type": "FeatureCollection", + }, + "hash": "851679102625f53c3254df99efbfba17", # pragma: allowlist secret + "provider": {}, + "areaHa": 168384.12865462166, + "bbox": [ + -102.61302947998, + 21.6217498779298, + -101.896156311035, + 22.0676307678222, + ], + "lock": False, + "info": { + "use": {}, + "simplifyThresh": 0.00005, + "gadm": "3.6", + "name": "Aguascalientes", + "id2": 1, + "id1": 1, + "iso": "MEX", + }, + }, + } +} + + example_geostore_resp = { "data": { "type": "geoStore", @@ -63,6 +119,64 @@ } +create_rw_geostore_payload = { + "geojson": { + "type": "MultiPolygon", + "coordinates": [[[[8, 51], [11, 55], [12, 49], [8, 52]]]], + } +} + + +create_gfw_geostore_payload = { + "geometry": { + "type": "MultiPolygon", + "coordinates": [[[[8, 51], [11, 55], [12, 49], [8, 52]]]], + } +} + +create_rw_geostore_response = { + "data": { + "type": "geoStore", + "id": "b73a4b48eb305110b8bfa604fe58df82", # pragma: allowlist secret + "attributes": { + "geojson": { + "crs": {}, + "type": "FeatureCollection", + "features": [ + { + "geometry": { + "coordinates": [[[[8, 51], [11, 55], [12, 49], [8, 51]]]], + "type": "MultiPolygon", + }, + "type": "Feature", + "properties": None, + } + ], + }, + "hash": "b73a4b48eb305110b8bfa604fe58df82", # pragma: allowlist secret + "provider": {}, + "areaHa": 8354467.362218728, + "bbox": [8, 49, 12, 55], + "lock": False, + "info": {"use": {}}, + }, + } +} + + +create_gfw_geostore_data = { + "created_on": "2025-01-21T15:24:10.315976", + "updated_on": "2025-01-21T15:24:10.315986", + "gfw_geostore_id": "db2b4428-bad2-fc94-1ea8-041597dc482c", + "gfw_geojson": { + "type": "MultiPolygon", + "coordinates": [[[[8, 51], [11, 55], [12, 49], [8, 52]]]], + }, + "gfw_area__ha": 8640517.2263933, + "gfw_bbox": [8.0, 49.0, 12.0, 55.0], +} + + @pytest.mark.asyncio async def test_wdpa_geostore_mock_helper( async_client: AsyncClient, monkeypatch: MonkeyPatch @@ -95,3 +209,95 @@ async def mock_resp_func(request: Request) -> Response: assert response.json() == example_geostore_resp assert response.status_code == 200 + + +@pytest.mark.asyncio +async def test_get_admin_geostore(async_client: AsyncClient, monkeypatch: MonkeyPatch): + async def mock_resp_func(request: Request) -> Response: + return Response(status_code=200, json=example_admin_geostore_snipped) + + transport = MockTransport(mock_resp_func) + + mocked_client = partial(AsyncClient, transport=transport) + monkeypatch.setattr(rw_api, "AsyncClient", mocked_client) + response = await async_client.get("/geostore/admin/MEX/1/1") + + assert response.json() == example_admin_geostore_snipped + assert response.status_code == 200 + + +@pytest.mark.asyncio +async def test_add_geostore_rw_branch( + async_client: AsyncClient, monkeypatch: MonkeyPatch +): + url = "/geostore" + + mock_create_rw_geostore = AsyncMock( + return_value=RWGeostoreResponse(**create_rw_geostore_response), + spec=geostore.create_rw_geostore, + ) + monkeypatch.setattr(geostore, "create_rw_geostore", mock_create_rw_geostore) + + mock_geostore_obj = MagicMock(spec=Geostore) + mock_create_gfw_geostore = AsyncMock( + return_value=mock_geostore_obj, spec=crud_geostore.create_user_area + ) + monkeypatch.setattr(crud_geostore, "create_user_area", mock_create_gfw_geostore) + + _ = await async_client.post( + url, json=create_rw_geostore_payload, follow_redirects=True + ) + + assert mock_create_rw_geostore.called is True + assert mock_create_gfw_geostore.called is False + + +@pytest.mark.asyncio +async def test_add_geostore_gfw_branch( + async_client: AsyncClient, monkeypatch: MonkeyPatch +): + url = "/geostore" + + mock_create_rw_geostore = AsyncMock( + return_value=RWGeostoreResponse(**create_rw_geostore_response), + spec=geostore.create_rw_geostore, + ) + monkeypatch.setattr(geostore, "create_rw_geostore", mock_create_rw_geostore) + + mock_create_gfw_geostore = AsyncMock( + return_value=create_gfw_geostore_data, spec=crud_geostore.create_user_area + ) + monkeypatch.setattr(crud_geostore, "create_user_area", mock_create_gfw_geostore) + + _ = await async_client.post( + url, json=create_gfw_geostore_payload, follow_redirects=True + ) + + assert mock_create_rw_geostore.called is False + assert mock_create_gfw_geostore.called is True + + +# @pytest.mark.asyncio +# async def test_get_geostore_rw_branch( +# async_client: AsyncClient, monkeypatch: MonkeyPatch +# ): +# url = "/geostore/88db597b6bcd096fb80d1542cdc442be" +# +# mock_proxy_get_geostore = AsyncMock( +# return_value=Response(status_code=200), +# spec=geostore.proxy_get_geostore +# ) +# +# monkeypatch.setattr(geostore, "proxy_get_geostore", mock_proxy_get_geostore) +# +# response = await async_client.post( +# url, +# json=RWGeostoreIn(**create_rw_geostore_payload).dict(), +# follow_redirects=True +# ) +# +# assert response.json() == create_rw_geostore_output +# assert response.status_code == 200 +# +# +#