-
Notifications
You must be signed in to change notification settings - Fork 0
Add queries to test AOI for validate project #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| import logging | ||
|
|
||
| import strawberry | ||
| import strawberry_django | ||
| from django.db.models import QuerySet | ||
|
|
@@ -7,7 +9,14 @@ | |
|
|
||
| from apps.project.custom_options import get_custom_options | ||
| from apps.project.graphql.inputs.inputs import ProjectNameInput | ||
| from apps.project.graphql.types.project_types.validate import ( | ||
| TestValidateAoiObjectsResponse, | ||
| TestValidateTaskingManagerProjectResponse, | ||
| ) | ||
| from apps.project.models import Organization, Project, ProjectAsset, ProjectTypeEnum | ||
| from project_types.base.project import ValidationException | ||
| from project_types.validate.project import ValidateProject | ||
| from utils import fields | ||
| from utils.geo.raster_tile_server.config import RasterConfig, RasterTileServerNameEnum, RasterTileServerNameEnumWithoutCustom | ||
| from utils.geo.vector_tile_server.config import VectorConfig, VectorTileServerNameEnum, VectorTileServerNameEnumWithoutCustom | ||
|
|
||
|
|
@@ -25,6 +34,8 @@ | |
| ProjectType, | ||
| ) | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def get_tile_servers() -> RasterTileServersType: | ||
| def _get_raster_tile_server_type(enum: RasterTileServerNameEnumWithoutCustom): | ||
|
|
@@ -79,6 +90,73 @@ def default_custom_options(self, project_type: ProjectTypeEnum) -> list[CustomOp | |
| for item in custom_options | ||
| ] | ||
|
|
||
| @strawberry.field(extensions=[IsAuthenticated()]) | ||
| def test_aoi_objects( | ||
| self, | ||
| project_id: strawberry.ID | None, | ||
| asset_id: strawberry.ID | None, | ||
| ohsome_filter: str | None, | ||
| ) -> TestValidateAoiObjectsResponse: | ||
| response = TestValidateAoiObjectsResponse( | ||
| project_id=project_id, | ||
| asset_id=asset_id, | ||
| ohsome_filter=ohsome_filter, | ||
| ) | ||
|
|
||
| if project_id is None: | ||
| return response.generate_error("project_id is required to test aoi elements") | ||
|
|
||
| if asset_id is None: | ||
| return response.generate_error("asset_id is required to test aoi elements") | ||
|
|
||
| if ohsome_filter is None: | ||
| return response.generate_error("ohsome_filter is required to test aoi elements") | ||
|
|
||
| try: | ||
| object_count = ValidateProject.test_ohsome_objects_from_aoi_asset( | ||
| project_id, | ||
| asset_id, | ||
| ohsome_filter, | ||
| ) | ||
|
|
||
| response.object_count = object_count | ||
| return response | ||
| except ValidationException as e: | ||
| return response.generate_error(str(e)) | ||
| except Exception as e: | ||
| raise GraphQLError(str(e)) from e | ||
|
|
||
| @strawberry.field(extensions=[IsAuthenticated()]) | ||
| def test_tasking_manager_project( | ||
| self, | ||
| hot_tm_id: fields.PydanticId | None, | ||
| ohsome_filter: str | None, | ||
| ) -> TestValidateTaskingManagerProjectResponse: | ||
| response = TestValidateTaskingManagerProjectResponse( | ||
| hot_tm_id=hot_tm_id, | ||
| ohsome_filter=ohsome_filter, | ||
| ) | ||
|
|
||
| if hot_tm_id is None: | ||
| return response.generate_error("hot_tm_id is required to test HOT project aoi elements") | ||
|
|
||
| if ohsome_filter is None: | ||
| return response.generate_error("ohsome_filter is required to test HOT project aoi elements") | ||
|
Comment on lines
+129
to
+144
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should be required on the API schema itself. |
||
|
|
||
| try: | ||
| object_count = ValidateProject.test_tasking_manager_project( | ||
| hot_tm_id, | ||
| ohsome_filter, | ||
| ) | ||
|
|
||
| response.object_count = object_count | ||
|
|
||
| return response | ||
| except ValidationException as e: | ||
| return response.generate_error(str(e)) | ||
| except Exception as e: | ||
| raise GraphQLError(str(e)) from e | ||
|
|
||
| tile_servers: RasterTileServersType = strawberry.field(resolver=get_tile_servers, extensions=[IsAuthenticated()]) | ||
|
|
||
| # Private -------------------- | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -294,6 +294,32 @@ class Mutation: | |
| } | ||
| """ | ||
|
|
||
| class Query: | ||
| TEST_AOI_OBJECTS = """ | ||
| query TestAoiObjects($assetId: ID, $projectId: ID, $ohsomeFilter: String) { | ||
| testAoiObjects(assetId: $assetId, projectId: $projectId, ohsomeFilter: $ohsomeFilter) { | ||
| ok | ||
| error | ||
| objectCount | ||
| assetId | ||
| projectId | ||
| ohsomeFilter | ||
| } | ||
| } | ||
| """ | ||
|
|
||
| TEST_TASKING_MANAGER_PROJECT = """ | ||
| query TestTaskingManagerProject($hotTmId: String, $ohsomeFilter: String) { | ||
| testTaskingManagerProject(hotTmId: $hotTmId, ohsomeFilter: $ohsomeFilter) { | ||
| ok | ||
| error | ||
| objectCount | ||
| hotTmId | ||
| ohsomeFilter | ||
| } | ||
| } | ||
| """ | ||
|
|
||
| @pytest.mark.vcr("assets/tests/projects/validate/cassette") | ||
| def test_validate_project_e2e(self): | ||
| # TODO(susilnem): Add more test with filters | ||
|
|
@@ -398,6 +424,15 @@ def _test_project(self, filename: str): | |
| assert aoi_response["ok"] | ||
| aoi_id = aoi_response["result"]["id"] | ||
|
|
||
| # Test AOI objects | ||
| ohsomeFilter = "building=* and geometry:polygon" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ohsome_filter |
||
| test_aoi_objects_content = self.query_check( | ||
| self.Query.TEST_AOI_OBJECTS, | ||
| variables={"assetId": aoi_id, "projectId": project_id, "ohsomeFilter": ohsomeFilter}, | ||
| ) | ||
| test_aoi_objects_response = test_aoi_objects_content["data"]["testAoiObjects"] | ||
| assert test_aoi_objects_response["ok"] | ||
|
|
||
| # Update project | ||
| update_project_data = test_data["update_project"] | ||
| update_project_data["image"] = image_id | ||
|
|
||
| +101 −43 | tests/projects/validate/cassette/TestValidateProjectE2E.test_validate_project_e2e.yaml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
|
|
||
| from main.config import Config | ||
| from main.logging import log_extra_response | ||
| from utils.fields import PydanticLongText | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -175,6 +176,40 @@ def remove_noise_and_add_user_info(json: dict[str, Any]) -> dict[str, Any]: | |
| return json | ||
|
|
||
|
|
||
| # fixme(frozenhelium): merge this function with `ohsome` and also add appropriate messages to raised exceptions | ||
| def get_object_count_from_ohsome(area: str, ohsome_filter: PydanticLongText) -> int | None: | ||
| url = Config.OHSOME_API_LINK + "elements/count" | ||
| data = {"bpolys": area, "filter": ohsome_filter} | ||
|
|
||
| logger.info("Target: %s", url) | ||
| logger.info("Filter: %s", ohsome_filter) | ||
|
|
||
| # fixme(frozenhelium): use httpx for proper timeout | ||
| response = requests.post(url, data=data, timeout=100) | ||
| if response.status_code != 200: | ||
| logger.warning( | ||
| "ohsome element count request failed: check for errors in filter or geometries", | ||
| extra=log_extra_response(response=response), | ||
| ) | ||
| raise ValidateApiCallError | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to include the error message in the exception?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it does, currently we're replicating the behaviour of
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add this as a NOTE |
||
| logger.info("Query successful.") | ||
|
|
||
| response_json = response.json() | ||
| results = response_json.get("result", None) | ||
| if results is None: | ||
| return None | ||
|
|
||
| first_result = results[0] | ||
| if first_result is None: | ||
| return None | ||
|
|
||
| value = first_result.get("value", None) | ||
| if value is None: | ||
| return None | ||
|
|
||
| return int(value) | ||
|
|
||
|
|
||
| def ohsome(request: dict[str, Any], area: str, properties: str | None = None) -> dict[str, Any]: | ||
| """Request data from Ohsome API.""" | ||
| url = Config.OHSOME_API_LINK + request["endpoint"] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be required on the API schema itself.