Skip to content

Commit 2fb298d

Browse files
committed
Add MVT Postgres Provider test
Fix Flake8
1 parent b3a9e9a commit 2fb298d

File tree

2 files changed

+274
-13
lines changed

2 files changed

+274
-13
lines changed

pygeoapi/provider/mvt_postgresql.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,37 +144,37 @@ def get_tiles(self, layer='default', tileset=None,
144144

145145
storage_srid = get_crs_from_uri(self.storage_crs).to_string()
146146
out_srid = get_crs_from_uri(tileset_schema.crs).to_string()
147+
envelope = func.ST_TileEnvelope(z, x, y).label('bounds')
147148

148-
tile_envelope = func.ST_TileEnvelope(z, x, y)
149-
envelope = (
150-
select(tile_envelope.label('bounds'))
151-
.cte('envelope')
149+
geom_column = getattr(self.table_model, self.geom)
150+
geom_filter = geom_column.intersects(
151+
func.ST_Transform(envelope, storage_srid)
152152
)
153153

154-
geom_column = getattr(self.table_model, self.geom)
155154
mvtgeom = (
156155
func.ST_AsMVTGeom(
157156
func.ST_Transform(func.ST_CurveToLine(geom_column), out_srid),
158-
func.ST_Transform(envelope.c.bounds, out_srid))
157+
func.ST_Transform(envelope, out_srid))
159158
.label('mvtgeom')
160159
)
161160

162-
geom_filter = geom_column.intersects(
163-
func.ST_Transform(tile_envelope, storage_srid))
164161
mvtrow = (
165-
select(*self.get_fields(), mvtgeom)
162+
select(mvtgeom, *self.fields)
166163
.filter(geom_filter)
167-
.select_from(self.table_model)
168164
.cte('mvtrow')
169165
.table_valued()
170166
)
171167

172-
mvt_query = select(func.ST_AsMVT(mvtrow, layer))
168+
mvtquery = select(
169+
func.ST_AsMVT(mvtrow, layer)
170+
)
173171

174172
with Session(self._engine) as session:
175-
result = session.execute(mvt_query).scalar()
173+
result = bytes(
174+
session.execute(mvtquery).scalar()
175+
) or None
176176

177-
return bytes(result) or None
177+
return result
178178

179179
def get_html_metadata(self, dataset, server_url, layer, tileset,
180180
title, description, keywords, **kwargs):

tests/test_postgresql_mvt_provider.py

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# =================================================================
2+
#
3+
# Authors: Ben Webb <bwebb@lincolninst.edu>
4+
#
5+
# Copyright (c) 2025 Ben Webb
6+
#
7+
# Permission is hereby granted, free of charge, to any person
8+
# obtaining a copy of this software and associated documentation
9+
# files (the "Software"), to deal in the Software without
10+
# restriction, including without limitation the rights to use,
11+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
# copies of the Software, and to permit persons to whom the
13+
# Software is furnished to do so, subject to the following
14+
# conditions:
15+
#
16+
# The above copyright notice and this permission notice shall be
17+
# included in all copies or substantial portions of the Software.
18+
#
19+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26+
# OTHER DEALINGS IN THE SOFTWARE.
27+
#
28+
# =================================================================
29+
30+
# Needs to be run like: python3 -m pytest
31+
# See pygeoapi/provider/postgresql.py for instructions on setting up
32+
# test database in Docker
33+
34+
import os
35+
import pytest
36+
37+
from pygeoapi.provider.mvt_postgresql import MVTPostgreSQLProvider
38+
from pygeoapi.provider.tile import ProviderTileNotFoundError
39+
40+
PASSWORD = os.environ.get('POSTGRESQL_PASSWORD', 'postgres')
41+
SERVER_URL = 'http://localhost'
42+
DATASET = 'hotosm_bdi_waterways'
43+
44+
45+
@pytest.fixture()
46+
def config():
47+
return {
48+
'name': 'MVT-postgresql',
49+
'type': 'tile',
50+
'data': {
51+
'host': '127.0.0.1',
52+
'dbname': 'test',
53+
'user': 'postgres',
54+
'password': PASSWORD,
55+
'search_path': ['osm', 'public']
56+
},
57+
'id_field': 'osm_id',
58+
'table': 'hotosm_bdi_waterways',
59+
'geom_field': 'foo_geom',
60+
'options': {
61+
'zoom': {
62+
'min': 0,
63+
'max': 15
64+
}
65+
},
66+
'format': {
67+
'name': 'pbf',
68+
'mimetype': 'application/vnd.mapbox-vector-tile'
69+
},
70+
'storage_crs': 'http://www.opengis.net/def/crs/EPSG/0/4326'
71+
}
72+
73+
74+
def test_metadata(config):
75+
"""Testing query for a valid JSON object with geometry"""
76+
p = MVTPostgreSQLProvider(config)
77+
78+
assert p.table == 'hotosm_bdi_waterways'
79+
assert p.geom == 'foo_geom'
80+
assert p.id_field == 'osm_id'
81+
assert p.get_layer() == config['table']
82+
83+
84+
def test_get_tiling_schemes(config):
85+
provider = MVTPostgreSQLProvider(config)
86+
87+
schemes = provider.get_tiling_schemes()
88+
assert any(s.tileMatrixSet == 'WebMercatorQuad' for s in schemes)
89+
assert any(s.tileMatrixSet == 'WorldCRS84Quad' for s in schemes)
90+
91+
92+
def test_get_default_metadata_WebMercatorQuad(config):
93+
provider = MVTPostgreSQLProvider(config)
94+
ts = 'WebMercatorQuad'
95+
96+
md = provider.get_default_metadata(
97+
dataset=DATASET,
98+
server_url=SERVER_URL,
99+
layer='layer1',
100+
tileset=ts,
101+
title='Waterways',
102+
description='OpenStreetMap Waterways',
103+
keywords=['osm', 'rivers']
104+
)
105+
106+
assert md['tileMatrixSetURI'] == \
107+
'http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad'
108+
assert md['crs'] == \
109+
'http://www.opengis.net/def/crs/EPSG/0/3857'
110+
111+
assert 'links' in md
112+
assert any(link['rel'].endswith('tiling-scheme') for link in md['links'])
113+
114+
[tile_format,] = [link for link in md['links'] if link['rel'] == 'item']
115+
assert tile_format['href'].startswith(SERVER_URL)
116+
assert DATASET in tile_format['href']
117+
assert ts in tile_format['href']
118+
119+
120+
def test_get_default_metadata_WorldCRS84Quad(config):
121+
provider = MVTPostgreSQLProvider(config)
122+
ts = 'WorldCRS84Quad'
123+
124+
md = provider.get_default_metadata(
125+
dataset=DATASET,
126+
server_url=SERVER_URL,
127+
layer='layer1',
128+
tileset=ts,
129+
title='Waterways',
130+
description='OpenStreetMap Waterways',
131+
keywords=['osm', 'rivers']
132+
)
133+
134+
assert md['tileMatrixSetURI'] == \
135+
'http://www.opengis.net/def/tilematrixset/OGC/1.0/WorldCRS84Quad'
136+
assert md['crs'] == \
137+
'http://www.opengis.net/def/crs/OGC/1.3/CRS84'
138+
139+
assert 'links' in md
140+
assert any(link['rel'].endswith('tiling-scheme') for link in md['links'])
141+
142+
[tile_format,] = [link for link in md['links'] if link['rel'] == 'item']
143+
assert tile_format['href'].startswith(SERVER_URL)
144+
assert DATASET in tile_format['href']
145+
assert ts in tile_format['href']
146+
147+
148+
def test_get_html_metadata_WebMercatorQuad(config):
149+
provider = MVTPostgreSQLProvider(config)
150+
title = 'Waterways'
151+
ts = 'WebMercatorQuad'
152+
153+
md = provider.get_html_metadata(
154+
dataset=DATASET,
155+
server_url=SERVER_URL,
156+
layer='layer1',
157+
tileset=ts,
158+
title=title,
159+
description='OpenStreetMap Waterways',
160+
keywords=['osm', 'rivers']
161+
)
162+
163+
assert md['id'] == DATASET
164+
assert md['title'] == title
165+
assert md['tileset'] == ts
166+
167+
assert md['collections_path'].startswith(SERVER_URL)
168+
assert DATASET in md['collections_path']
169+
assert ts in md['collections_path']
170+
171+
assert md['json_url'].startswith(SERVER_URL)
172+
assert DATASET in md['json_url']
173+
assert ts in md['json_url']
174+
175+
176+
def test_get_html_metadata_WorldCRS84Quad(config):
177+
provider = MVTPostgreSQLProvider(config)
178+
title = 'Waterways'
179+
ts = 'WorldCRS84Quad'
180+
181+
md = provider.get_html_metadata(
182+
dataset=DATASET,
183+
server_url=SERVER_URL,
184+
layer='layer1',
185+
tileset=ts,
186+
title=title,
187+
description='OpenStreetMap Waterways',
188+
keywords=['osm', 'rivers']
189+
)
190+
191+
assert md['id'] == DATASET
192+
assert md['title'] == title
193+
assert md['tileset'] == ts
194+
195+
assert md['collections_path'].startswith(SERVER_URL)
196+
assert DATASET in md['collections_path']
197+
assert ts in md['collections_path']
198+
199+
assert md['json_url'].startswith(SERVER_URL)
200+
assert DATASET in md['json_url']
201+
assert ts in md['json_url']
202+
203+
204+
def test_get_tiles_WebMercatorQuad(config):
205+
p = MVTPostgreSQLProvider(config)
206+
tileset = 'WebMercatorQuad'
207+
208+
# Valid tile, no content
209+
z, x, y = 14, 10200, 10300
210+
tile = p.get_tiles(
211+
tileset=tileset,
212+
z=z, x=x, y=y,
213+
)
214+
assert tile is None
215+
216+
# Valid tile, content
217+
z, x, y = 10, 595, 521
218+
tile = p.get_tiles(
219+
tileset=tileset,
220+
z=z, x=x, y=y,
221+
)
222+
assert isinstance(tile, bytes)
223+
assert len(tile) > 0
224+
225+
# Tile does not exist in matrixset
226+
z, x, y = 1, 1000000, 1000000
227+
result = p.get_tiles(
228+
tileset=tileset,
229+
z=z, x=x, y=y
230+
)
231+
assert result == ProviderTileNotFoundError
232+
233+
234+
def test_get_tiles_WorldCRS84Quad(config):
235+
p = MVTPostgreSQLProvider(config)
236+
tileset = 'WorldCRS84Quad'
237+
238+
# Valid tile, no content
239+
z, x, y = 14, 10200, 10300
240+
tile = p.get_tiles(
241+
tileset=tileset,
242+
z=z, x=x, y=y,
243+
)
244+
assert tile is None
245+
246+
# Valid tile, content
247+
z, x, y = 10, 595, 521
248+
tile = p.get_tiles(
249+
tileset=tileset,
250+
z=z, x=x, y=y,
251+
)
252+
assert isinstance(tile, bytes)
253+
assert len(tile) > 0
254+
255+
# Tile does not exist in matrixset
256+
z, x, y = 1, 1000000, 1000000
257+
result = p.get_tiles(
258+
tileset=tileset,
259+
z=z, x=x, y=y
260+
)
261+
assert result == ProviderTileNotFoundError

0 commit comments

Comments
 (0)