Skip to content

Commit

Permalink
test: update entity tests to support latest bulk entity upload api
Browse files Browse the repository at this point in the history
  • Loading branch information
spwoodcock committed Jul 29, 2024
1 parent 0bb19ca commit a00ea82
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 83 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ exclude = [
[tool.ruff.lint]
select = ["I", "E", "W", "D", "B", "F", "N", "Q"]
ignore = ["N805", "B008"]
[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
"osm_fieldwork/basemapper.py" = ["N802"]
[tool.ruff.lint.pydocstyle]
convention = "google"
Expand Down
73 changes: 45 additions & 28 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

from osm_fieldwork.OdkCentral import OdkAppUser, OdkForm, OdkProject
from osm_fieldwork.OdkCentralAsync import OdkDataset
from osm_fieldwork.xlsforms import entities_registration_xml

logging.basicConfig(
level="DEBUG",
Expand Down Expand Up @@ -155,51 +154,69 @@ def odk_form_cleanup(odk_form):
assert success


# NOTE this is session scoped as odk_entity_cleanup depends on it
@pytest.fixture(scope="session")
def odk_entity(project_details) -> tuple:
"""Get entity for a project."""
async def odk_dataset(project_details) -> tuple:
"""Get dataset (entity list) for a project."""
odk_id = project_details.get("id")
entity = OdkDataset(
dataset = OdkDataset(
url="https://proxy",
user="[email protected]",
passwd="Password1234",
)
return odk_id, entity

# Create the dataset
async with dataset as odk_dataset:
created_dataset = await odk_dataset.createDataset(
odk_id,
"features",
[
"geometry",
"project_id",
"task_id",
"osm_id",
"tags",
"version",
"changeset",
"timestamp",
"status",
],
)
assert created_dataset.get("name") == "features"
assert sorted(created_dataset.get("properties", [])) == sorted(
[
"geometry",
"project_id",
"task_id",
"osm_id",
"tags",
"version",
"changeset",
"timestamp",
"status",
]
)

return odk_id, dataset

# NOTE this is session scoped to avoid attempting to create duplicate form
@pytest.fixture(scope="session")
async def odk_entity_cleanup(odk_entity):
"""Get Entity for project, with automatic cleanup after."""
odk_id, entity = odk_entity

# Create entity registration form
form = OdkForm(
entity.url,
entity.user,
entity.passwd,
)
form_name = form.createForm(odk_id, str(entities_registration_xml), publish=True)
if not form_name:
raise AssertionError("Failed to create form")
@pytest.fixture(scope="session")
async def odk_dataset_cleanup(odk_dataset):
"""Get Dataset for project, with automatic cleanup after."""
odk_id, dataset = odk_dataset

dataset_name = "features"
async with entity:
entity_json = await entity.createEntity(odk_id, dataset_name, "test entity", {"osm_id": "1", "geometry": "test"})
async with dataset as odk_dataset:
entity_json = await odk_dataset.createEntity(odk_id, dataset_name, "test entity", {"osm_id": "1", "geometry": "test"})
entity_uuid = entity_json.get("uuid")

# Before yield is used in tests
yield odk_id, dataset_name, entity_uuid, entity
yield odk_id, dataset_name, entity_uuid, dataset
# After yield is test cleanup

async with entity:
entity_deleted = await entity.deleteEntity(odk_id, dataset_name, entity_uuid)
async with dataset as odk_dataset:
entity_deleted = await odk_dataset.deleteEntity(odk_id, dataset_name, entity_uuid)
assert entity_deleted

form_deleted = form.deleteForm(odk_id, form_name)
assert form_deleted


@pytest.fixture(scope="session", autouse=True)
def cleanup():
Expand Down
113 changes: 59 additions & 54 deletions tests/test_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
from datetime import datetime, timezone

import pytest
from aiohttp.client_exceptions import ClientError


async def test_entity_modify(odk_entity_cleanup):
async def test_entity_modify(odk_dataset_cleanup):
"""Test modifying an entity."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
print(dataset_name)
async with entity:
updated_entity = await entity.updateEntity(odk_id, dataset_name, entity_uuid, label="new label")
assert updated_entity.get("currentVersion").get("label") == "new label"
Expand All @@ -38,66 +40,74 @@ async def test_entity_modify(odk_entity_cleanup):
assert new_data.get("project_id") == "100"


async def test_create_invalid_entities(odk_entity_cleanup):
async def test_create_invalid_entities(odk_dataset_cleanup):
"""Test uploading invalid data to an entity (HTTP 400)."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
async with entity:
# NOTE entity must have a geometry data field
with pytest.raises(ValueError):
await entity.createEntity(odk_id, dataset_name, label="test", data={"status": 0})

# NOTE data fields cannot be integer, this should 400 response
invalid_data_type = await entity.createEntity(odk_id, dataset_name, label="test", data={"geometry": "", "status": 0})
assert invalid_data_type == {}

bulk_entities_one_invaid = await entity.createEntities(
odk_id,
dataset_name,
{
"test entity 2": {"osm_id": 55, "geometry": "test"},
"test entity 3": {"osm_id": "66", "geometry": "test"},
},
)
assert len(bulk_entities_one_invaid) == 1
# NOTE data fields cannot be integer, this should raise error
with pytest.raises(ClientError):
await entity.createEntity(odk_id, dataset_name, label="test", data={"geometry": "", "status": 0})

# Also test bulk entity create using integer data
with pytest.raises(ClientError):
await entity.createEntities(
odk_id,
dataset_name,
[
{"label": "test entity 2", "data": {"osm_id": 55, "geometry": "test"}},
{"label": "test entity 3", "data": {"osm_id": "66", "geometry": "test"}},
],
)

# Bulk Entity creation, not a list
with pytest.raises(ValueError):
await entity.createEntities(
odk_id,
dataset_name,
{"label": "test", "data": {}},
)


async def test_bulk_create_entity_count(odk_entity_cleanup):
async def test_bulk_create_entity_count(odk_dataset_cleanup):
"""Test bulk creation of Entities."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
async with entity:
created_entities = await entity.createEntities(
await entity.createEntities(
odk_id,
dataset_name,
{
"test entity 1": {"osm_id": "44", "geometry": "test"},
"test entity 2": {"osm_id": "55", "geometry": "test"},
"test entity 3": {"osm_id": "66", "geometry": "test"},
},
[
{"label": "test entity 1", "data": {"osm_id": "44", "geometry": "test"}},
{"label": "test entity 2", "data": {"osm_id": "55", "geometry": "test"}},
{"label": "test entity 3", "data": {"osm_id": "66", "geometry": "test"}},
],
)
entity_count = await entity.getEntityCount(odk_id, dataset_name)

assert created_entities[0].get("currentVersion").get("data").get("geometry") == "test"
# NOTE this may be cumulative from the session... either 4 or 5
assert entity_count >= 4


async def test_get_entity_data(odk_entity_cleanup):
async def test_get_entity_data(odk_dataset_cleanup):
"""Test getting entity data, inluding via a OData filter."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
async with entity:
new_entities = await entity.createEntities(
await entity.createEntities(
odk_id,
dataset_name,
{
"test entity 1": {"geometry": "test"},
"test entity 2": {"geometry": "test"},
"test entity 3": {"geometry": "test"},
"test entity 4": {"geometry": "test"},
"test entity 5": {"geometry": "test"},
"test entity 6": {"geometry": "test"},
"test entity 7": {"geometry": "test"},
"test entity 8": {"geometry": "test"},
},
[
{"label": "test entity 1", "data": {"geometry": "test"}},
{"label": "test entity 2", "data": {"geometry": "test"}},
{"label": "test entity 3", "data": {"geometry": "test"}},
{"label": "test entity 4", "data": {"geometry": "test"}},
{"label": "test entity 5", "data": {"geometry": "test"}},
{"label": "test entity 6", "data": {"geometry": "test"}},
{"label": "test entity 7", "data": {"geometry": "test"}},
{"label": "test entity 8", "data": {"geometry": "test"}},
],
)

all_entities = await entity.getEntityData(odk_id, dataset_name)
Expand All @@ -113,32 +123,27 @@ async def test_get_entity_data(odk_entity_cleanup):
assert filtered_entities.get("@odata.count") >= 9
assert "@odata.nextLink" in filtered_entities.keys()

entity_uuids = [_entity.get("uuid") for _entity in new_entities]

# Update all entities, so updatedAt is not 'None'
for uuid in entity_uuids:
await entity.updateEntity(odk_id, dataset_name, uuid, data={"status": "READY"})

# Get current time NOTE time format = 2022-01-31T23:59:59.999Z
time_now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")

# Update last 3 entities prior to filter
entity_uuids = [_entity.get("uuid") for _entity in new_entities]
for uuid in entity_uuids[5:]:
# Update first 5 entities prior to filter
entity_uuids = [_entity.get("__id") for _entity in all_entities]
for uuid in sorted(entity_uuids[:5]):
await entity.updateEntity(odk_id, dataset_name, uuid, data={"status": "LOCKED_FOR_MAPPING"})

filter_updated = await entity.getEntityData(
odk_id,
dataset_name,
url_params=f"$filter=__system/updatedAt gt {time_now}",
)
assert len(filter_updated) == 3
assert filter_updated[0].get("status") == "LOCKED_FOR_MAPPING"
assert len(filter_updated) == 5
for entity in filter_updated:
assert entity.get("status") == "LOCKED_FOR_MAPPING"


async def test_get_entity_data_select_params(odk_entity_cleanup):
async def test_get_entity_data_select_params(odk_dataset_cleanup):
"""Test selecting specific param for an Entity."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
async with entity:
entities_select_params = await entity.getEntityData(
odk_id,
Expand All @@ -153,9 +158,9 @@ async def test_get_entity_data_select_params(odk_entity_cleanup):
assert "geometry" in first_entity, "Missing 'geometry' key"


async def test_get_single_entity(odk_entity_cleanup):
async def test_get_single_entity(odk_dataset_cleanup):
"""Test getting specific Entity by UUID."""
odk_id, dataset_name, entity_uuid, entity = odk_entity_cleanup
odk_id, dataset_name, entity_uuid, entity = odk_dataset_cleanup
async with entity:
single_entity = await entity.getEntity(
odk_id,
Expand Down

0 comments on commit a00ea82

Please sign in to comment.