Skip to content

Commit 51ca4e8

Browse files
777arcMarc Lichtman
andauthored
Fixed searchid bug, added unit tests, improved main readme (#236)
* fixed searchid bug and added unit tests * readme tweaks * black line length * change line length in flake settings * revert line length change, going to do it in separate PR * autoformatter * retrigger github actions * Delete scripts/test-mosaic * hack for not needing secrets AZURITE_ACCOUNT_KEY * shorten command * testing output * remove grep * quotes * trying another method * trying another method * remove extra echo * tweaks * remove echo * use env * test failure * fail step * try removing azurite from api validator * autoformatter * pipeline tweak * Delete storage-use-azurite?tabs=visual-studio,blob-storage --------- Co-authored-by: Marc Lichtman <[email protected]>
1 parent 822f8f5 commit 51ca4e8

File tree

5 files changed

+123
-26
lines changed

5 files changed

+123
-26
lines changed

.github/workflows/pr.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ jobs:
1212
- uses: actions/checkout@v3
1313

1414
- name: Set Azurite Default Key
15-
run: |
16-
echo "AZURITE_ACCOUNT_KEY=${{ secrets.AZURITE_ACCOUNT_KEY }}" >> $GITHUB_ENV
17-
echo "Using Azurite default key: $AZURITE_ACCOUNT_KEY"
15+
run: echo "AZURITE_ACCOUNT_KEY=$(curl https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite | grep "Account key:" | cut -b 24-111)" >> $GITHUB_ENV
16+
17+
- name: Verify Azurite Key was retrieved correctly
18+
if: "!startsWith(env.AZURITE_ACCOUNT_KEY, 'Eby8')"
19+
run: echo Failed to find key at learn.microsoft.com && exit 1
1820

1921
- name: Run cibuild
2022
run: ./scripts/cibuild
@@ -29,9 +31,7 @@ jobs:
2931
cache: "pip"
3032

3133
- name: Set Azurite Default Key
32-
run: |
33-
echo "AZURITE_ACCOUNT_KEY=${{ secrets.AZURITE_ACCOUNT_KEY }}" >> $GITHUB_ENV
34-
echo "Using Azurite default key: $AZURITE_ACCOUNT_KEY"
34+
run: echo "AZURITE_ACCOUNT_KEY=$(curl https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite | grep "Account key:" | cut -b 24-111)" >> $GITHUB_ENV
3535

36-
- name: Validate
36+
- name: API Validator
3737
run: ./scripts/validate

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ This repository contains two components of the Planetary Computer APIs: the STAC
1111
The `pcstac` project provides a STAC API which indexes Microsoft's publicly available [geospatial data](https://planetarycomputer.microsoft.com/catalog) and an API for searching through this large collection.
1212
The `pctiler` provides visualization and data access capabilities for the data in the Planetary Computer.
1313

14-
## Azure Functions
14+
## Azure Functions (a.k.a. Funcs)
1515

16-
This repository also contains Azure Functions that provide additional endpoints for working with Planetary Computer data and metadata. This includes Function endpoints for generating images and animations based on STAC searches, using the tiler to render mosaiced data from Collections
16+
This repository also contains Azure Functions that provide additional endpoints for working with Planetary Computer data and metadata. This includes Function endpoints for generating images and animations based on STAC searches, using the tiler to render mosaiced data from Collections.
1717

1818
## Collection configuration
1919

@@ -61,26 +61,27 @@ This project uses a variation on [scripts to rule them all](https://github.com/g
6161

6262
#### Environment setup and building images
6363

64-
Before setting up the local environment, ensure that you have set the AZURITE_ACCOUNT_KEY environment variable.
65-
The account key can be found in the [Azurite GitHub repository](https://github.com/Azure/Azurite?tab=readme-ov-file#usage-with-azure-storage-sdks-or-tools)
64+
Before setting up the local environment, you must set the AZURITE_ACCOUNT_KEY environment variable to the Azurite default
65+
account key, a string that can be [found here](https://github.com/Azure/Azurite?tab=readme-ov-file#usage-with-azure-storage-sdks-or-tools).
6666

6767
For example, you can set the environment variable in your terminal with:
68+
6869
```console
69-
> export AZURITE_ACCOUNT_KEY=<azurite_account_key>
70+
export AZURITE_ACCOUNT_KEY=<azurite_account_key>
7071
```
7172

72-
To set up a local environment, use
73+
To set up a local environment, use:
7374

7475
```console
75-
> ./scripts/setup
76+
./scripts/setup
7677
```
7778

7879
This will build containers, apply database migrations, and load the development data.
7980

80-
After migrations and development database loading are in place, you can rebuild the docker images with
81+
After migrations and development database loading are in place, you can rebuild the docker images with:
8182

8283
```console
83-
> ./scripts/update
84+
./scripts/update
8485
```
8586

8687
`pip` dependencies in `setup.py` are collected and installed through requirements files.
@@ -99,11 +100,13 @@ az login
99100
To run the servers, use
100101

101102
```console
102-
> ./scripts/server
103+
./scripts/server
103104
```
104105

105106
This will bring up the development database, STAC API, Tiler, Azure Functions, and other services.
106107

108+
To test the tiler, try going to <http://localhost:8080/data/mosaic/info?collection=naip>.
109+
107110
#### Testing and and formatting
108111

109112
To run tests, use
@@ -148,4 +151,4 @@ See the [Helm chart repository](https://microsoft.github.io/planetary-computer-a
148151

149152
### Functions
150153

151-
See the [Function package repository](https://microsoft.github.io/planetary-computer-apis) published to GitHub pages for the published Azure Functions.
154+
See the [Function package repository](https://microsoft.github.io/planetary-computer-apis) published to GitHub pages for the published Azure Functions.

pctiler/pctiler/endpoints/pg_mosaic.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from titiler.core.factory import img_endpoint_params
1111
from titiler.core.resources.enums import ImageType
1212
from titiler.pgstac.dependencies import SearchIdParams, TmsTileParams
13+
from titiler.pgstac.extensions import searchInfoExtension
1314
from titiler.pgstac.factory import MosaicTilerFactory
1415

1516
from pccommon.config import get_collection_config
@@ -22,7 +23,6 @@
2223

2324
@dataclass
2425
class AssetsBidxExprParams(dependencies.AssetsBidxExprParams):
25-
2626
collection: str = Query(None, description="STAC Collection ID")
2727

2828

@@ -45,9 +45,11 @@ def __init__(self, request: Request):
4545
colormap_dependency=PCColorMapParams,
4646
layer_dependency=AssetsBidxExprParams,
4747
reader_dependency=ReaderParams,
48-
router_prefix=get_settings().mosaic_endpoint_prefix + "/{search_id}",
48+
router_prefix=get_settings().mosaic_endpoint_prefix
49+
+ "/{search_id}", # reverts /searches back to /mosaic
4950
backend_dependency=BackendParams,
5051
add_statistics=False,
52+
extensions=[searchInfoExtension()],
5153
)
5254

5355

pctiler/tests/endpoints/test_pg_mosaic.py

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,47 @@
1010

1111
@pytest.fixture
1212
async def register_search(client: AsyncClient) -> REGISTER_TYPE:
13-
1413
cql = {
1514
"filter-lang": "cql2-json",
1615
"filter": {
1716
"op": "and",
1817
"args": [{"op": "=", "args": [{"property": "collection"}, "naip"]}],
1918
},
2019
}
21-
expected_content_hash = "8b989f86a149628eabfde894fb965982"
2220
response = await client.post("/mosaic/register", json=cql)
21+
expected_content_hash = response.json()["searchid"]
2322
resp = response.json()
24-
2523
return (expected_content_hash, resp)
2624

2725

26+
async def test_register_search_with_geom(client: AsyncClient) -> None:
27+
geom = {
28+
"type": "Polygon",
29+
"coordinates": [
30+
[
31+
[-79.09062791441062, 43.08554661560049],
32+
[-79.0629876337021, 43.08554661560049],
33+
[-79.0629876337021, 43.067969831431895],
34+
[-79.09062791441062, 43.067969831431895],
35+
[-79.09062791441062, 43.08554661560049],
36+
]
37+
],
38+
}
39+
cql = {
40+
"filter-lang": "cql2-json",
41+
"filter": {
42+
"op": "and",
43+
"args": [
44+
{"op": "=", "args": [{"property": "collection"}, "naip"]},
45+
{"op": "s_intersects", "args": [{"property": "geometry"}, geom]},
46+
],
47+
},
48+
}
49+
response = await client.post("/mosaic/register", json=cql)
50+
assert response.status_code == 200
51+
assert response.json()["searchid"] == "2607eab51afd5d626da8d50d9df3bbf0"
52+
53+
2854
@pytest.mark.asyncio
2955
async def test_mosaic_info(client: AsyncClient) -> None:
3056
response = await client.get("/mosaic/info?collection=naip")
@@ -36,18 +62,20 @@ async def test_mosaic_info(client: AsyncClient) -> None:
3662

3763
@pytest.mark.asyncio
3864
async def test_register(client: AsyncClient, register_search: REGISTER_TYPE) -> None:
39-
4065
expected_content_hash, register_resp = register_search
4166

4267
# Test that `searchid` which has been removed in titiler remains in pctiler,
4368
# and that the search hash remains consistent
4469
assert register_resp["searchid"] == expected_content_hash
4570
# Test that the links have had the {tileMatrixSetId} template string removed
46-
assert len(register_resp["links"]) == 2
71+
assert len(register_resp["links"]) == 3
4772
assert register_resp["links"][0]["href"].endswith(
73+
f"/mosaic/{expected_content_hash}/info"
74+
) # gets added by searchInfoExtension
75+
assert register_resp["links"][1]["href"].endswith(
4876
f"/mosaic/{expected_content_hash}/tilejson.json"
4977
)
50-
assert register_resp["links"][1]["href"].endswith(
78+
assert register_resp["links"][2]["href"].endswith(
5179
f"/mosaic/{expected_content_hash}/WMTSCapabilities.xml"
5280
)
5381

@@ -101,6 +129,51 @@ async def test_mosaic_tile_routes(
101129
assert response.status_code == 200
102130

103131

132+
async def test_info_path_with_searchid(
133+
client: AsyncClient, register_search: REGISTER_TYPE
134+
) -> None:
135+
# route source code is in titiler/mosaic/titiler/mosaic/factory.py#L157
136+
# the searchId functionality is added by titiler-pgstac
137+
route = "mosaic/{searchId}/info"
138+
expected_content_hash, _ = register_search
139+
formatted_route = route.format(searchId=expected_content_hash)
140+
url = (
141+
f"/{formatted_route}?asset_bidx=image%7C1%2C2%2C3&assets=image&collection=naip"
142+
)
143+
response = await client.get(url)
144+
assert response.status_code == 200
145+
146+
147+
async def test_info_path_with_bad_searchid(client: AsyncClient) -> None:
148+
route = "mosaic/{searchId}/info"
149+
150+
# does not match the one we registered in the fixture
151+
expected_content_hash = "9b989f86a149628eabfde894fb965982"
152+
153+
formatted_route = route.format(searchId=expected_content_hash)
154+
url = (
155+
f"/{formatted_route}?asset_bidx=image%7C1%2C2%2C3&assets=image&collection=naip"
156+
)
157+
response = await client.get(url)
158+
assert response.status_code == 404
159+
160+
161+
async def test_bad_searchid(client: AsyncClient) -> None:
162+
route = "mosaic/tiles/{searchId}/{z}/{x}/{y}"
163+
164+
# does not match the one we registered in the fixture
165+
expected_content_hash = "9b989f86a149628eabfde894fb965982"
166+
167+
formatted_route = route.format(
168+
searchId=expected_content_hash, z=16, x=17218, y=26838
169+
)
170+
url = (
171+
f"/{formatted_route}?asset_bidx=image%7C1%2C2%2C3&assets=image&collection=naip"
172+
)
173+
response = await client.get(url)
174+
assert response.status_code == 404
175+
176+
104177
@pytest.mark.asyncio
105178
@pytest.mark.parametrize(
106179
"route",

scripts/format-local

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
isort --overwrite-in-place pccommon
3+
isort --overwrite-in-place pccommon/pccommon
4+
isort --overwrite-in-place pccommon/tests
5+
isort --overwrite-in-place pcfuncs
6+
isort --overwrite-in-place scripts/bin
7+
isort --overwrite-in-place pctiler/pctiler
8+
isort --overwrite-in-place pctiler/tests
9+
isort --overwrite-in-place pcstac/pcstac
10+
isort --overwrite-in-place pcstac/tests
11+
black pccommon/pccommon
12+
black pccommon/tests
13+
black pcfuncs
14+
black scripts/bin
15+
black pcstac/pcstac
16+
black pcstac/tests
17+
black pccommon
18+
black pctiler/pctiler
19+
black pctiler/tests

0 commit comments

Comments
 (0)