def test_app_sort_extension(load_test_data, app_client, postgres_transactions): first_item = load_test_data("test_item.json") item_date = datetime.strptime(first_item["properties"]["datetime"], "%Y-%m-%dT%H:%M:%SZ") postgres_transactions.create_item(Item.parse_obj(first_item), request=MockStarletteRequest) second_item = load_test_data("test_item.json") 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") postgres_transactions.create_item(Item.parse_obj(second_item), request=MockStarletteRequest) params = { "collections": [first_item["collection"]], "sortby": [{ "field": "datetime", "direction": "desc" }], } resp = app_client.post("/search", json=params) 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"]
def test_fields_filter(): fields = FieldsExtension(includes={"id", "geometry", "properties.foo"}, excludes={"properties.bar"}) item = Item( id="test-fields-filter", geometry=Polygon.from_bounds(0, 0, 0, 0), properties={ "datetime": datetime.utcnow(), "foo": "foo", "bar": "bar" }, assets={}, links=[], bbox=[0, 0, 0, 0], ) d = item.to_dict(**fields.filter) assert d.pop("id") == item.id assert d.pop("geometry") == item.geometry props = d.pop("properties") assert props["foo"] == "foo" assert not props.get("bar") assert not d
async def test_fetches_valid_item(app_client, load_test_data: Callable, load_test_collection): coll = load_test_collection in_json = load_test_data("test_item.json") in_item = Item.parse_obj(in_json) resp = await app_client.post( "/collections/{coll.id}/items", json=in_json, ) assert resp.status_code == 200 post_item = Item.parse_obj(resp.json()) assert in_item.dict(exclude={"links"}) == post_item.dict(exclude={"links"}) resp = await app_client.get(f"/collections/{coll.id}/items/{post_item.id}") assert resp.status_code == 200 item_dict = resp.json() # Mock root to allow validation mock_root = pystac.Catalog(id="test", description="test desc", href="https://example.com") item = pystac.Item.from_dict(item_dict, preserve_dict=False, root=mock_root) item.validate()
def test_invalid_geometry(): test_item = request(EO_EXTENSION) # Remove the last coordinate test_item["geometry"]["coordinates"][0].pop(-1) with pytest.raises(ValidationError) as e: Item(**test_item)
def main(scene_list, wrs2_grid, collection, level): """Create Landsat STAC Items.""" # Create items for item in create_stac_items(scene_list, wrs2_grid, collection=collection, level=level): click.echo(Item(**item).json(exclude_none=True))
async def test_create_item_conflict(app_client, load_test_data: Callable, load_test_collection): pass in_json = load_test_data("test_item.json") Item.parse_obj(in_json) resp = await app_client.post( "/collections/{coll.id}/items", json=in_json, ) assert resp.status_code == 200 resp = await app_client.post( "/collections/{coll.id}/items", json=in_json, ) assert resp.status_code == 409
def test_asset_extras(): test_item = request(EO_EXTENSION) for asset in test_item["assets"]: test_item["assets"][asset]["foo"] = "bar" item = Item(**test_item) for (asset_name, asset) in item.assets.items(): assert asset.foo == "bar"
async def load_test_item(app_client, load_test_data, load_test_collection): data = load_test_data("test_item.json") resp = await app_client.post( "/collections/{coll.id}/items", json=data, ) assert resp.status_code == 200 return Item.parse_obj(resp.json())
async def _search_base(self, search_request: PgstacSearch, **kwargs) -> Dict[str, Any]: """Cross catalog search (POST). Called with `POST /search`. Args: search_request: search request parameters. Returns: ItemCollection containing items which match the search criteria. """ request = kwargs["request"] pool = request.app.state.readpool # pool = kwargs["request"].app.state.readpool req = search_request.json(exclude_none=True) async with pool.acquire() as conn: q, p = render( """ SELECT * FROM search(:req::text::jsonb); """, req=req, ) items = await conn.fetchval(q, *p) next = items.pop("next", None) prev = items.pop("prev", None) collection = ItemCollection.construct(**items) cleaned_features = [] if collection.features is None or len(collection.features) == 0: raise NotFoundError("No features found") for feature in collection.features: feature = Item.construct(**feature) if "links" not in search_request.fields.exclude: links = await ItemLinks( collection_id=feature.collection, item_id=feature.id, request=request, ).get_links() feature.links = links exclude = search_request.fields.exclude if len(exclude) == 0: exclude = None include = search_request.fields.include if len(include) == 0: include = None feature = feature.dict(exclude_none=True, ) cleaned_features.append(feature) collection.features = cleaned_features collection.links = await PagingLinks( request=request, next=next, prev=prev, ).get_links() return collection
def test_create_duplicate_item_different_collections( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): # create test-collection coll = load_test_data("test_collection.json") postgres_transactions.create_collection(coll, request=MockStarletteRequest) # create test-collection-2 coll["id"] = "test-collection-2" postgres_transactions.create_collection(coll, request=MockStarletteRequest) # add item to test-collection item = load_test_data("test_item.json") postgres_transactions.create_item(item, request=MockStarletteRequest) # get item from test-collection resp = postgres_core.get_item(item["id"], item["collection"], request=MockStarletteRequest) assert Item(**item).dict(exclude={ "links":..., "properties": {"created", "updated"} }) == Item(**resp).dict(exclude={ "links":..., "properties": {"created", "updated"} }) # add item to test-collection-2 item["collection"] = "test-collection-2" postgres_transactions.create_item(item, request=MockStarletteRequest) # get item with same id from test-collection-2 resp = postgres_core.get_item(item["id"], item["collection"], request=MockStarletteRequest) assert Item(**item).dict(exclude={ "links":..., "properties": {"created", "updated"} }) == Item(**resp).dict(exclude={ "links":..., "properties": {"created", "updated"} })
async def test_create_item(app_client, load_test_data: Callable, load_test_collection): coll = load_test_collection in_json = load_test_data("test_item.json") in_item = Item.parse_obj(in_json) resp = await app_client.post( "/collections/{coll.id}/items", json=in_json, ) assert resp.status_code == 200 post_item = Item.parse_obj(resp.json()) assert in_item.dict(exclude={"links"}) == post_item.dict(exclude={"links"}) resp = await app_client.get(f"/collections/{coll.id}/items/{post_item.id}") assert resp.status_code == 200 get_item = Item.parse_obj(resp.json()) assert in_item.dict(exclude={"links"}) == get_item.dict(exclude={"links"})
def test_create_item( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = load_test_data("test_collection.json") postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = load_test_data("test_item.json") postgres_transactions.create_item(item, request=MockStarletteRequest) resp = postgres_core.get_item(item["id"], item["collection"], request=MockStarletteRequest) assert Item(**item).dict(exclude={ "links":..., "properties": {"created", "updated"} }) == Item(**resp).dict(exclude={ "links":..., "properties": {"created", "updated"} })
def test_app_fields_extension(load_test_data, app_client, postgres_transactions): item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) resp = 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"]
def test_app_context_extension(load_test_data, app_client, postgres_transactions): item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) resp = app_client.get("/search", params={"collections": ["test-collection"]}) assert resp.status_code == 200 resp_json = resp.json() assert "context" in resp_json assert resp_json["context"]["returned"] == resp_json["context"][ "matched"] == 1
def validate_item(infile): """Validate stac item""" r = requests.get(infile) r.raise_for_status() stac_item = r.json() try: item = Item(**stac_item) validate_extensions(item, reraise_exception=True) except ValidationError as e: click.echo(str(e)) return click.echo(f"{infile} is valid") return
def test_create_item_already_exists( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) with pytest.raises(ConflictError): postgres_transactions.create_item(item, request=MockStarletteRequest)
def test_create_item( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) resp = postgres_core.get_item( item.id, item.collection, request=MockStarletteRequest ) assert item.dict( exclude={"links": ..., "properties": {"created", "updated"}} ) == resp.dict(exclude={"links": ..., "properties": {"created", "updated"}})
async def test_update_item(app_client, load_test_collection, load_test_item): coll = load_test_collection item = load_test_item item.properties.description = "Update Test" resp = await app_client.put(f"/collections/{coll.id}/items", json=item.dict()) assert resp.status_code == 200 resp = await app_client.get(f"/collections/{coll.id}/items/{item.id}") assert resp.status_code == 200 get_item = Item.parse_obj(resp.json()) assert item.dict(exclude={"links"}) == get_item.dict(exclude={"links"}) assert get_item.properties.description == "Update Test"
def test_delete_item( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) postgres_transactions.delete_item(item.id, request=MockStarletteRequest) with pytest.raises(NotFoundError): postgres_core.get_item(item.id, request=MockStarletteRequest)
def test_update_item( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) item.properties.foo = "bar" postgres_transactions.update_item(item, request=MockStarletteRequest) updated_item = postgres_core.get_item(item.id, request=MockStarletteRequest) assert updated_item.properties.foo == "bar"
def test_app_query_extension(load_test_data, app_client, postgres_transactions): test_item = load_test_data("test_item.json") item = Item.parse_obj(test_item) postgres_transactions.create_item(item, request=MockStarletteRequest) params = { "query": { "proj:epsg": { "gt": test_item["properties"]["proj:epsg"] + 1 } } } resp = app_client.post("/search", json=params) assert resp.status_code == 200 resp_json = resp.json() assert len(resp_json["features"]) == 0
def test_get_collection_items( postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) for _ in range(5): item.id = str(uuid.uuid4()) postgres_transactions.create_item(item, request=MockStarletteRequest) fc = postgres_core.item_collection(coll.id, request=MockStarletteRequest) assert len(fc.features) == 5 for item in fc.features: assert item.collection == coll.id
def tiles_extension_app(postgres_core, postgres_transactions, load_test_data): # Ingest test data for testing coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) postgres_transactions.create_item(item, request=MockStarletteRequest) settings = SqlalchemySettings() api = StacApi( settings=settings, client=postgres_core, extensions=[TilesExtension(TilesClient(postgres_core))], ) with TestClient(api.app) as test_app: yield test_app # Cleanup test data postgres_transactions.delete_item(item.id, request=MockStarletteRequest) postgres_transactions.delete_collection(coll.id, request=MockStarletteRequest)
def test_bulk_item_insert( postgres_transactions: TransactionsClient, postgres_bulk_transactions: BulkTransactionsClient, load_test_data: Callable, ): coll = Collection.parse_obj(load_test_data("test_collection.json")) postgres_transactions.create_collection(coll, request=MockStarletteRequest) item = Item.parse_obj(load_test_data("test_item.json")) items = [] for _ in range(10): _item = item.dict() _item["id"] = str(uuid.uuid4()) items.append(_item) postgres_bulk_transactions.bulk_item_insert(Items(items=items)) for item in items: postgres_transactions.delete_item(item["id"], request=MockStarletteRequest)
def test_item_to_json(): test_item = request(EO_EXTENSION) item = Item(**test_item) assert item.to_json() == json.dumps(item.to_dict())
def test_item_to_json(): test_item = request(EO_EXTENSION) item = Item(**test_item) dict_match(json.loads(item.to_json()), item.to_dict())
def test_label_extension_validation_error(): test_item = request(LABEL_EXTENSION) test_item["properties"]["label:type"] = "invalid-label-type" with pytest.raises(ValidationError): Item(**test_item)
def test_single_file_stac_validation_error(): test_item = request(SINGLE_FILE_STAC) del test_item["collections"] with pytest.raises(ValidationError): Item(**test_item)
def test_geo_interface(): test_item = request(EO_EXTENSION) item = Item(**test_item) geom = shape(item.geometry) test_item["geometry"] = geom Item(**test_item)
async def test_pagination(app_client, load_test_data, load_test_collection): """Test item collection pagination (paging extension)""" coll = load_test_collection item_count = 21 test_item = load_test_data("test_item.json") for idx in range(1, item_count): item = Item.parse_obj(test_item) item.id = item.id + str(idx) item.properties.datetime = f"2020-01-{idx:02d}T00:00:00" resp = await app_client.post(f"/collections/{coll.id}/items", json=item.dict()) assert resp.status_code == 200 resp = await app_client.get(f"/collections/{coll.id}/items", params={"limit": 3}) assert resp.status_code == 200 first_page = resp.json() for feature in first_page["features"]: print(feature["id"], feature["properties"]["datetime"]) print(f"first page links {first_page['links']}") assert len(first_page["features"]) == 3 nextlink = [ link["href"] for link in first_page["links"] if link["rel"] == "next" ].pop() assert nextlink is not None assert [f["id"] for f in first_page["features"]] == [ "test-item20", "test-item19", "test-item18", ] print(f"Next {nextlink}") resp = await app_client.get(nextlink) assert resp.status_code == 200 second_page = resp.json() for feature in second_page["features"]: print(feature["id"], feature["properties"]["datetime"]) print(f"second page links {second_page['links']}") assert len(first_page["features"]) == 3 nextlink = [ link["href"] for link in second_page["links"] if link["rel"] == "next" ].pop() assert nextlink is not None prevlink = [ link["href"] for link in second_page["links"] if link["rel"] == "previous" ].pop() assert prevlink is not None print(nextlink, prevlink) assert [f["id"] for f in second_page["features"]] == [ "test-item17", "test-item16", "test-item15", ] resp = await app_client.get(prevlink) assert resp.status_code == 200 back_page = resp.json() for feature in back_page["features"]: print(feature["id"], feature["properties"]["datetime"]) print(back_page["links"]) assert len(back_page["features"]) == 3 assert [f["id"] for f in back_page["features"]] == [ "test-item20", "test-item19", "test-item18", ]