Skip to content
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

Fix GET sortby, tests #157

Merged
merged 6 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Corrected the automatic converstion of float values to int when building Filter Clauses [#135](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/135)
- Do not index `proj:geometry` field as geo_shape [#154](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/154)
- Remove unsupported characters from Elasticsearch index names [#153](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/153)
- Fixed GET /search sortby requests [#25](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/25)

## [v0.3.0]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,10 @@ async def get_search(
sort_param.append(
{
"field": sort[1:],
"direction": "asc" if sort[0] == "+" else "desc",
"direction": "desc" if sort[0] == "-" else "asc",
}
)
print(sort_param)
base_args["sortby"] = sort_param

# todo: requires fastapi > 2.3 unreleased
Expand Down
98 changes: 97 additions & 1 deletion stac_fastapi/elasticsearch/tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import uuid
from datetime import datetime, timedelta

import pytest

from ..conftest import create_collection, create_item

ROUTES = {
Expand Down Expand Up @@ -31,17 +33,20 @@
}


@pytest.mark.asyncio
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async def test_post_search_content_type(app_client, ctx):
params = {"limit": 1}
resp = await app_client.post("/search", json=params)
assert resp.headers["content-type"] == "application/geo+json"


@pytest.mark.asyncio
async def test_get_search_content_type(app_client, ctx):
resp = await app_client.get("/search")
assert resp.headers["content-type"] == "application/geo+json"


@pytest.mark.asyncio
async def test_api_headers(app_client):
resp = await app_client.get("/api")
assert (
Expand All @@ -50,11 +55,13 @@ async def test_api_headers(app_client):
assert resp.status_code == 200


@pytest.mark.asyncio
async def test_router(app):
api_routes = set([f"{list(route.methods)[0]} {route.path}" for route in app.routes])
assert len(api_routes - ROUTES) == 0


@pytest.mark.asyncio
async def test_app_transaction_extension(app_client, ctx):
item = copy.deepcopy(ctx.item)
item["id"] = str(uuid.uuid4())
Expand All @@ -64,6 +71,7 @@ async def test_app_transaction_extension(app_client, ctx):
await app_client.delete(f"/collections/{item['collection']}/items/{item['id']}")


@pytest.mark.asyncio
async def test_app_search_response(app_client, ctx):
resp = await app_client.get("/search", params={"ids": ["test-item"]})
assert resp.status_code == 200
Expand All @@ -75,6 +83,7 @@ async def test_app_search_response(app_client, ctx):
assert resp_json.get("stac_extensions") is None


@pytest.mark.asyncio
async def test_app_context_extension(app_client, ctx, txn_client):
test_item = ctx.item
test_item["id"] = "test-item-2"
Expand Down Expand Up @@ -108,13 +117,15 @@ async def test_app_context_extension(app_client, ctx, txn_client):
assert matched == 1


@pytest.mark.asyncio
async def test_app_fields_extension(app_client, ctx, txn_client):
resp = await app_client.get("/search", params={"collections": ["test-collection"]})
assert resp.status_code == 200
resp_json = resp.json()
assert list(resp_json["features"][0]["properties"]) == ["datetime"]


@pytest.mark.asyncio
async def test_app_fields_extension_query(app_client, ctx, txn_client):
resp = await app_client.post(
"/search",
Expand All @@ -128,6 +139,7 @@ async def test_app_fields_extension_query(app_client, ctx, txn_client):
assert list(resp_json["features"][0]["properties"]) == ["datetime", "proj:epsg"]


@pytest.mark.asyncio
async def test_app_fields_extension_no_properties_get(app_client, ctx, txn_client):
resp = await app_client.get(
"/search", params={"collections": ["test-collection"], "fields": "-properties"}
Expand All @@ -137,6 +149,7 @@ async def test_app_fields_extension_no_properties_get(app_client, ctx, txn_clien
assert "properties" not in resp_json["features"][0]


@pytest.mark.asyncio
async def test_app_fields_extension_no_properties_post(app_client, ctx, txn_client):
resp = await app_client.post(
"/search",
Expand All @@ -150,6 +163,7 @@ async def test_app_fields_extension_no_properties_post(app_client, ctx, txn_clie
assert "properties" not in resp_json["features"][0]


@pytest.mark.asyncio
async def test_app_fields_extension_return_all_properties(app_client, ctx, txn_client):
item = ctx.item
resp = await app_client.get(
Expand All @@ -166,6 +180,7 @@ async def test_app_fields_extension_return_all_properties(app_client, ctx, txn_c
assert feature["properties"][expected_prop] == expected_value


@pytest.mark.asyncio
async def test_app_query_extension_gt(app_client, ctx):
params = {"query": {"proj:epsg": {"gt": ctx.item["properties"]["proj:epsg"]}}}
resp = await app_client.post("/search", json=params)
Expand All @@ -174,6 +189,7 @@ async def test_app_query_extension_gt(app_client, ctx):
assert len(resp_json["features"]) == 0


@pytest.mark.asyncio
async def test_app_query_extension_gte(app_client, ctx):
params = {"query": {"proj:epsg": {"gte": ctx.item["properties"]["proj:epsg"]}}}
resp = await app_client.post("/search", json=params)
Expand All @@ -182,23 +198,97 @@ async def test_app_query_extension_gte(app_client, ctx):
assert len(resp.json()["features"]) == 1


@pytest.mark.asyncio
async def test_app_query_extension_limit_lt0(app_client):
assert (await app_client.post("/search", json={"limit": -1})).status_code == 400


@pytest.mark.asyncio
async def test_app_query_extension_limit_gt10000(app_client):
resp = await app_client.post("/search", json={"limit": 10001})
assert resp.status_code == 200
assert resp.json()["context"]["limit"] == 10000


@pytest.mark.asyncio
async def test_app_query_extension_limit_10000(app_client):
params = {"limit": 10000}
resp = await app_client.post("/search", json=params)
assert resp.status_code == 200


async def test_app_sort_extension(app_client, txn_client, ctx):
@pytest.mark.asyncio
async def test_app_sort_extension_get_asc(app_client, txn_client, ctx):
first_item = ctx.item
item_date = datetime.strptime(
first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ"
)

second_item = dict(first_item)
second_item["id"] = "another-item"
another_item_date = item_date - timedelta(days=1)
second_item["properties"]["datetime"] = another_item_date.strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
await create_item(txn_client, second_item)

resp = await app_client.get("/search?sortby=+properties.datetime")
assert resp.status_code == 200
resp_json = resp.json()
assert resp_json["features"][1]["id"] == first_item["id"]
assert resp_json["features"][0]["id"] == second_item["id"]


@pytest.mark.asyncio
async def test_app_sort_extension_get_desc(app_client, txn_client, ctx):
first_item = ctx.item
item_date = datetime.strptime(
first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ"
)

second_item = dict(first_item)
second_item["id"] = "another-item"
another_item_date = item_date - timedelta(days=1)
second_item["properties"]["datetime"] = another_item_date.strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
await create_item(txn_client, second_item)

resp = await app_client.get("/search?sortby=-properties.datetime")
assert resp.status_code == 200
resp_json = resp.json()
assert resp_json["features"][0]["id"] == first_item["id"]
assert resp_json["features"][1]["id"] == second_item["id"]


@pytest.mark.asyncio
async def test_app_sort_extension_post_asc(app_client, txn_client, ctx):
first_item = ctx.item
item_date = datetime.strptime(
first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ"
)

second_item = dict(first_item)
second_item["id"] = "another-item"
another_item_date = item_date - timedelta(days=1)
second_item["properties"]["datetime"] = another_item_date.strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
await create_item(txn_client, second_item)

params = {
"collections": [first_item["collection"]],
"sortby": [{"field": "properties.datetime", "direction": "asc"}],
}
resp = await app_client.post("/search", json=params)
assert resp.status_code == 200
resp_json = resp.json()
assert resp_json["features"][1]["id"] == first_item["id"]
assert resp_json["features"][0]["id"] == second_item["id"]


@pytest.mark.asyncio
async def test_app_sort_extension_post_desc(app_client, txn_client, ctx):
first_item = ctx.item
item_date = datetime.strptime(
first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ"
Expand All @@ -223,6 +313,7 @@ async def test_app_sort_extension(app_client, txn_client, ctx):
assert resp_json["features"][1]["id"] == second_item["id"]


@pytest.mark.asyncio
async def test_search_invalid_date(app_client, ctx):
params = {
"datetime": "2020-XX-01/2020-10-30",
Expand All @@ -233,6 +324,7 @@ async def test_search_invalid_date(app_client, ctx):
assert resp.status_code == 400


@pytest.mark.asyncio
async def test_search_point_intersects(app_client, ctx):
point = [150.04, -33.14]
intersects = {"type": "Point", "coordinates": point}
Expand All @@ -248,6 +340,7 @@ async def test_search_point_intersects(app_client, ctx):
assert len(resp_json["features"]) == 1


@pytest.mark.asyncio
async def test_search_point_does_not_intersect(app_client, ctx):
point = [15.04, -3.14]
intersects = {"type": "Point", "coordinates": point}
Expand All @@ -263,6 +356,7 @@ async def test_search_point_does_not_intersect(app_client, ctx):
assert len(resp_json["features"]) == 0


@pytest.mark.asyncio
async def test_datetime_non_interval(app_client, ctx):
dt_formats = [
"2020-02-12T12:30:22+00:00",
Expand All @@ -284,6 +378,7 @@ async def test_datetime_non_interval(app_client, ctx):
assert resp_json["features"][0]["properties"]["datetime"][0:19] == dt[0:19]


@pytest.mark.asyncio
async def test_bbox_3d(app_client, ctx):
australia_bbox = [106.343365, -47.199523, 0.1, 168.218365, -19.437288, 0.1]
params = {
Expand All @@ -296,6 +391,7 @@ async def test_bbox_3d(app_client, ctx):
assert len(resp_json["features"]) == 1


@pytest.mark.asyncio
async def test_search_line_string_intersects(app_client, ctx):
line = [[150.04, -33.14], [150.22, -33.89]]
intersects = {"type": "LineString", "coordinates": line}
Expand Down
Loading