gws.test.mockmap¶
Mockmap: a map server that serves predictable synthetic geometry.
Mockmap exists to test OWS and tile clients. It serves the same synthetic scene through several protocols and projections, so a client can be checked against content whose true position is known exactly, without depending on a remote service or on real imagery.
Running¶
Standalone, with its own compose file:
docker compose -f docker-compose.yml up
or inside a GWS container:
PYTHONPATH=/gws-app python3 -m gws.test.mockmap.server [config path]
Environment: MOCKMAP_PORT (default 80), MOCKMAP_DELAY (milliseconds
added to every response, default 0).
Services¶
One service is one protocol in one CRS with at most one tile grid. Capabilities are deliberately minimal: mockmap tests rendering, not capabilities parsing.
xyz/<uid>/{z}/{x}/{y}.png, north-west origin, no capabilitiestms/<uid>/1.0.0/<layer>/{z}/{x}/{y}.png, south-west origin,service and tilemap documents at
/<uid>/1.0.0[/<layer>]
wmtsWMTS KVP:GetCapabilitiesandGetTileon/<uid>wmts_restWMTS RESTful:/<uid>/WMTSCapabilities.xmland
/<uid>/<layer>/<style>/<tms>/{z}/{y}/{x}.png
wmsGetCapabilitiesandGetMapon/<uid>, version1.1.1 or 1.3.0
Every request is /<service-uid>/ followed by the service’s own path and/or
query parameters:
/xyz_3857/7/68/44.png
/wms_32?SERVICE=WMS&REQUEST=GetMap&BBOX=...
/ lists the configured service uids. The TileMatrixSet identifier is derived
from the CRS as EPSG_<srid>.
WMS 1.3.0 swaps BBOX and the advertised BoundingBox for a CRS with
latitude/northing first; WMTS swaps TopLeftCorner the same way.
A tile service needs no grid configuration. services.Tms derives one from
the service CRS: the frame is the CRS extent, level 0 is a single tile across
its width and levels halve down to MIN_RESOLUTION. EPSG:3857 is the
exception, where the frame is the de-facto slippy-map square rather than the
CRS extent, which spans latitude +-85.06 degrees. The origin comes from the
service type, north-west everywhere except tms.
Configuration¶
A jump/slon file, (see config.cx). It has a default block, shallow-merged
into every services+ entry, and is re-read on every request; the services
are rebuilt only when the parsed result actually changes.
There is no validation. Values are assumed present and of the right type.
Service keys:
uidservice id, first path segment, must be uniquetypeone of the service types abovecrsthe CRS this service speaksversionWMS only,1.1.1or1.3.0layeradvertised layer name, defaultmapstyleadvertised style name, defaultdefaultoverlaydraw a frame and a caption on every imageoverlayTileadd the tile z/x/y to that captionprobestamp the pixel-aligned scaling probe
Scene keys, see below:
extentthe scene extent, always in EPSG:4326stepgraticule and checkerboard step in degreesgraticule,checker,shapes,labelswhich elements to drawlabelSize,labelPad,labelPartials,labelForcebackgrounda CSS color, empty for a transparent background
The scene¶
The scene is defined once in EPSG:4326 and reprojected by MapServer into whatever a service speaks, so a projection error shows up as a distorted graticule rather than as nothing at all. It consists of a densified graticule, a checkerboard, a few reference shapes (circle, square, cross) and a point with its own coordinates as a label at every graticule intersection. Lines are densified so that reprojection curvature is visible; a two-point line would reproject to a straight line and hide it.
extent is the only place where the data location is configured. Each
service’s advertised bounding box is derived from it, so moving the scene moves
every service. A tile grid is not: it is derived from the service CRS in
services.Tms, because a grid frame follows the CRS, not the data.
Everything in the scene is anchored to world coordinates, so a line lands on
an arbitrary sub-pixel position and MapServer antialiases it - a 1px line comes
out as two columns at partial alpha. That makes the scene useless for answering
“has anything rescaled this image”. The probe answers it: a checkerboard of
single pixels, drawn in raster space after MapServer, repeated every
PROBE_STEP pixels so it survives cropping into tiles. At 1:1 it is exactly
two colors; it sits at the Nyquist frequency, so any resampling - a client scale
off the ladder, an unwanted reprojection, a half-pixel shift - collapses it to
flat grey. If the probe is crisp, nothing in the pipeline touched the raster.
Labels are anchored to features, so they exercise the per-request placement a
tiled WMS client has to cope with: labelPartials and labelForce control
whether MapServer drops or duplicates a label at an image edge, and
labelPad widens the text to find the point where a client’s edge buffer
stops being enough.
Modules¶
server.pyHTTP, routing, configuration loading and reloadingservices.pythe service types, tile addressing, rendering and therender cache
scene.pythe synthetic scene and the MapServer mapfilecaps.cxjump templates for the capabilities documentsconfig.cxexample configuration
Rendering goes through gws.lib.mapserver, with the scene built as a mapfile
of inline features. One MapServer quirk is worked around in scene.py: an
image is drawn with square pixels and scaled to the requested size afterwards,
because MapServer silently widens an extent whose aspect does not match that
size.
Rendered images are cached in memory, keyed by scene, CRS, extent, size and caption, so a repeated request costs nothing and load tests measure the client rather than mockmap.
Source code: gws.test.mockmap