MapProxy 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
- MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
- MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
- MapProxy-2.1.0.dist-info/METADATA +165 -0
- MapProxy-2.1.0.dist-info/RECORD +459 -0
- MapProxy-2.1.0.dist-info/WHEEL +5 -0
- MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
- MapProxy-2.1.0.dist-info/top_level.txt +1 -0
- mapproxy/__init__.py +0 -0
- mapproxy/cache/__init__.py +36 -0
- mapproxy/cache/azureblob.py +145 -0
- mapproxy/cache/base.py +120 -0
- mapproxy/cache/compact.py +665 -0
- mapproxy/cache/couchdb.py +301 -0
- mapproxy/cache/dummy.py +36 -0
- mapproxy/cache/file.py +200 -0
- mapproxy/cache/geopackage.py +647 -0
- mapproxy/cache/legend.py +87 -0
- mapproxy/cache/mbtiles.py +411 -0
- mapproxy/cache/meta.py +80 -0
- mapproxy/cache/path.py +261 -0
- mapproxy/cache/redis.py +152 -0
- mapproxy/cache/renderd.py +100 -0
- mapproxy/cache/riak.py +206 -0
- mapproxy/cache/s3.py +209 -0
- mapproxy/cache/tile.py +736 -0
- mapproxy/client/__init__.py +0 -0
- mapproxy/client/arcgis.py +82 -0
- mapproxy/client/cgi.py +141 -0
- mapproxy/client/http.py +295 -0
- mapproxy/client/log.py +33 -0
- mapproxy/client/tile.py +158 -0
- mapproxy/client/wms.py +255 -0
- mapproxy/compat/__init__.py +0 -0
- mapproxy/compat/image.py +86 -0
- mapproxy/config/__init__.py +22 -0
- mapproxy/config/config-schema.json +813 -0
- mapproxy/config/config.py +213 -0
- mapproxy/config/coverage.py +108 -0
- mapproxy/config/defaults.py +102 -0
- mapproxy/config/loader.py +2399 -0
- mapproxy/config/spec.py +657 -0
- mapproxy/config/validator.py +242 -0
- mapproxy/config_template/__init__.py +0 -0
- mapproxy/config_template/base_config/config.wsgi +10 -0
- mapproxy/config_template/base_config/full_example.yaml +598 -0
- mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
- mapproxy/config_template/base_config/log.ini +35 -0
- mapproxy/config_template/base_config/mapproxy.yaml +60 -0
- mapproxy/config_template/base_config/seed.yaml +27 -0
- mapproxy/exception.py +149 -0
- mapproxy/featureinfo.py +251 -0
- mapproxy/grid.py +1199 -0
- mapproxy/image/__init__.py +549 -0
- mapproxy/image/fonts/DejaVuSans.ttf +0 -0
- mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
- mapproxy/image/fonts/LICENSE +99 -0
- mapproxy/image/fonts/__init__.py +0 -0
- mapproxy/image/mask.py +79 -0
- mapproxy/image/merge.py +323 -0
- mapproxy/image/message.py +357 -0
- mapproxy/image/opts.py +185 -0
- mapproxy/image/tile.py +171 -0
- mapproxy/image/transform.py +350 -0
- mapproxy/layer.py +489 -0
- mapproxy/multiapp.py +230 -0
- mapproxy/proj.py +309 -0
- mapproxy/request/__init__.py +18 -0
- mapproxy/request/arcgis.py +268 -0
- mapproxy/request/base.py +466 -0
- mapproxy/request/tile.py +131 -0
- mapproxy/request/wms/__init__.py +829 -0
- mapproxy/request/wms/exception.py +107 -0
- mapproxy/request/wmts.py +442 -0
- mapproxy/response.py +237 -0
- mapproxy/script/__init__.py +0 -0
- mapproxy/script/conf/__init__.py +0 -0
- mapproxy/script/conf/app.py +222 -0
- mapproxy/script/conf/caches.py +44 -0
- mapproxy/script/conf/geopackage.py +136 -0
- mapproxy/script/conf/layers.py +54 -0
- mapproxy/script/conf/seeds.py +36 -0
- mapproxy/script/conf/sources.py +88 -0
- mapproxy/script/conf/utils.py +148 -0
- mapproxy/script/defrag.py +187 -0
- mapproxy/script/export.py +337 -0
- mapproxy/script/grids.py +198 -0
- mapproxy/script/scales.py +134 -0
- mapproxy/script/util.py +410 -0
- mapproxy/script/wms_capabilities.py +160 -0
- mapproxy/seed/__init__.py +0 -0
- mapproxy/seed/cachelock.py +127 -0
- mapproxy/seed/cleanup.py +191 -0
- mapproxy/seed/config.py +481 -0
- mapproxy/seed/script.py +391 -0
- mapproxy/seed/seeder.py +551 -0
- mapproxy/seed/spec.py +66 -0
- mapproxy/seed/util.py +266 -0
- mapproxy/service/__init__.py +14 -0
- mapproxy/service/base.py +45 -0
- mapproxy/service/demo.py +364 -0
- mapproxy/service/kml.py +333 -0
- mapproxy/service/ows.py +39 -0
- mapproxy/service/template_helper.py +55 -0
- mapproxy/service/templates/demo/capabilities_demo.html +18 -0
- mapproxy/service/templates/demo/demo.html +181 -0
- mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
- mapproxy/service/templates/demo/static/img/blank.gif +0 -0
- mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
- mapproxy/service/templates/demo/static/logo.png +0 -0
- mapproxy/service/templates/demo/static/ol.css +345 -0
- mapproxy/service/templates/demo/static/ol.js +4 -0
- mapproxy/service/templates/demo/static/proj4.min.js +1 -0
- mapproxy/service/templates/demo/static/proj4defs.js +1 -0
- mapproxy/service/templates/demo/static/site.css +137 -0
- mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
- mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
- mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
- mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
- mapproxy/service/templates/demo/static.html +34 -0
- mapproxy/service/templates/demo/tms_demo.html +117 -0
- mapproxy/service/templates/demo/wms_demo.html +144 -0
- mapproxy/service/templates/demo/wmts_demo.html +118 -0
- mapproxy/service/templates/tms_capabilities.xml +13 -0
- mapproxy/service/templates/tms_exception.xml +4 -0
- mapproxy/service/templates/tms_root_resource.xml +7 -0
- mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
- mapproxy/service/templates/wms100capabilities.xml +112 -0
- mapproxy/service/templates/wms100exception.xml +4 -0
- mapproxy/service/templates/wms110capabilities.xml +152 -0
- mapproxy/service/templates/wms110exception.xml +5 -0
- mapproxy/service/templates/wms111capabilities.xml +183 -0
- mapproxy/service/templates/wms111exception.xml +5 -0
- mapproxy/service/templates/wms130capabilities.xml +326 -0
- mapproxy/service/templates/wms130exception.xml +8 -0
- mapproxy/service/templates/wmts100capabilities.xml +155 -0
- mapproxy/service/templates/wmts100exception.xml +9 -0
- mapproxy/service/tile.py +540 -0
- mapproxy/service/wms.py +868 -0
- mapproxy/service/wmts.py +387 -0
- mapproxy/source/__init__.py +83 -0
- mapproxy/source/arcgis.py +39 -0
- mapproxy/source/error.py +40 -0
- mapproxy/source/mapnik.py +262 -0
- mapproxy/source/tile.py +97 -0
- mapproxy/source/wms.py +273 -0
- mapproxy/srs.py +734 -0
- mapproxy/template.py +54 -0
- mapproxy/test/__init__.py +0 -0
- mapproxy/test/conftest.py +8 -0
- mapproxy/test/helper.py +255 -0
- mapproxy/test/http.py +511 -0
- mapproxy/test/image.py +219 -0
- mapproxy/test/mocker.py +2291 -0
- mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
- mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
- mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
- mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
- mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
- mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
- mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
- mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
- mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
- mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
- mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
- mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
- mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
- mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
- mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
- mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
- mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
- mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
- mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
- mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
- mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
- mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
- mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
- mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
- mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
- mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
- mapproxy/test/schemas/xml.xsd +287 -0
- mapproxy/test/system/__init__.py +98 -0
- mapproxy/test/system/fixture/arcgis.yaml +57 -0
- mapproxy/test/system/fixture/auth.yaml +70 -0
- mapproxy/test/system/fixture/cache.mbtiles +0 -0
- mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
- mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
- mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
- mapproxy/test/system/fixture/cache_coverage.yaml +84 -0
- mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
- mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
- mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
- mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
- mapproxy/test/system/fixture/cache_s3.yaml +58 -0
- mapproxy/test/system/fixture/cache_source.yaml +81 -0
- mapproxy/test/system/fixture/combined_sources.yaml +130 -0
- mapproxy/test/system/fixture/coverage.yaml +77 -0
- mapproxy/test/system/fixture/demo.yaml +135 -0
- mapproxy/test/system/fixture/dimension.yaml +59 -0
- mapproxy/test/system/fixture/disable_storage.yaml +25 -0
- mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
- mapproxy/test/system/fixture/formats.yaml +72 -0
- mapproxy/test/system/fixture/inspire.yaml +101 -0
- mapproxy/test/system/fixture/inspire_full.yaml +124 -0
- mapproxy/test/system/fixture/kml_layer.yaml +66 -0
- mapproxy/test/system/fixture/layer.yaml +260 -0
- mapproxy/test/system/fixture/layergroups.yaml +57 -0
- mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
- mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
- mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
- mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
- mapproxy/test/system/fixture/mapserver.yaml +23 -0
- mapproxy/test/system/fixture/minimal_cgi.py +16 -0
- mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
- mapproxy/test/system/fixture/multi_cache_layers.yaml +111 -0
- mapproxy/test/system/fixture/multiapp1.yaml +20 -0
- mapproxy/test/system/fixture/multiapp2.yaml +19 -0
- mapproxy/test/system/fixture/renderd_client.yaml +55 -0
- mapproxy/test/system/fixture/scalehints.yaml +70 -0
- mapproxy/test/system/fixture/seed.yaml +94 -0
- mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
- mapproxy/test/system/fixture/seed_old.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
- mapproxy/test/system/fixture/seedonly.yaml +51 -0
- mapproxy/test/system/fixture/sld.yaml +35 -0
- mapproxy/test/system/fixture/source_errors.yaml +84 -0
- mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
- mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
- mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
- mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
- mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
- mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
- mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
- mapproxy/test/system/fixture/util_grids.yaml +29 -0
- mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
- mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
- mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
- mapproxy/test/system/fixture/watermark.yaml +50 -0
- mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
- mapproxy/test/system/fixture/wms_versions.yaml +38 -0
- mapproxy/test/system/fixture/wmts.yaml +134 -0
- mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
- mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
- mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
- mapproxy/test/system/test_arcgis.py +156 -0
- mapproxy/test/system/test_auth.py +1133 -0
- mapproxy/test/system/test_behind_proxy.py +75 -0
- mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
- mapproxy/test/system/test_cache_azureblob.py +127 -0
- mapproxy/test/system/test_cache_band_merge.py +103 -0
- mapproxy/test/system/test_cache_coverage.py +168 -0
- mapproxy/test/system/test_cache_geopackage.py +144 -0
- mapproxy/test/system/test_cache_grid_names.py +89 -0
- mapproxy/test/system/test_cache_mbtiles.py +85 -0
- mapproxy/test/system/test_cache_s3.py +115 -0
- mapproxy/test/system/test_cache_source.py +146 -0
- mapproxy/test/system/test_combined_sources.py +335 -0
- mapproxy/test/system/test_coverage.py +140 -0
- mapproxy/test/system/test_decorate_img.py +214 -0
- mapproxy/test/system/test_demo.py +56 -0
- mapproxy/test/system/test_demo_with_extra_service.py +57 -0
- mapproxy/test/system/test_dimensions.py +279 -0
- mapproxy/test/system/test_disable_storage.py +42 -0
- mapproxy/test/system/test_formats.py +219 -0
- mapproxy/test/system/test_inspire_vs.py +173 -0
- mapproxy/test/system/test_kml.py +264 -0
- mapproxy/test/system/test_layergroups.py +160 -0
- mapproxy/test/system/test_legendgraphic.py +308 -0
- mapproxy/test/system/test_mapnik.py +162 -0
- mapproxy/test/system/test_mapserver.py +83 -0
- mapproxy/test/system/test_mixed_mode_format.py +201 -0
- mapproxy/test/system/test_multi_cache_layers.py +169 -0
- mapproxy/test/system/test_multiapp.py +92 -0
- mapproxy/test/system/test_refresh.py +206 -0
- mapproxy/test/system/test_renderd_client.py +304 -0
- mapproxy/test/system/test_response_headers.py +54 -0
- mapproxy/test/system/test_scalehints.py +140 -0
- mapproxy/test/system/test_seed.py +425 -0
- mapproxy/test/system/test_seed_only.py +93 -0
- mapproxy/test/system/test_sld.py +120 -0
- mapproxy/test/system/test_source_errors.py +377 -0
- mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
- mapproxy/test/system/test_tms.py +277 -0
- mapproxy/test/system/test_tms_origin.py +46 -0
- mapproxy/test/system/test_util_conf.py +434 -0
- mapproxy/test/system/test_util_export.py +210 -0
- mapproxy/test/system/test_util_grids.py +88 -0
- mapproxy/test/system/test_util_wms_capabilities.py +182 -0
- mapproxy/test/system/test_watermark.py +91 -0
- mapproxy/test/system/test_wms.py +1616 -0
- mapproxy/test/system/test_wms_srs_extent.py +165 -0
- mapproxy/test/system/test_wms_version.py +85 -0
- mapproxy/test/system/test_wmsc.py +116 -0
- mapproxy/test/system/test_wmts.py +334 -0
- mapproxy/test/system/test_wmts_dimensions.py +206 -0
- mapproxy/test/system/test_wmts_restful.py +198 -0
- mapproxy/test/system/test_xslt_featureinfo.py +423 -0
- mapproxy/test/test_http_helper.py +217 -0
- mapproxy/test/unit/__init__.py +0 -0
- mapproxy/test/unit/epsg +2 -0
- mapproxy/test/unit/polygons/polygons.dbf +0 -0
- mapproxy/test/unit/polygons/polygons.shp +0 -0
- mapproxy/test/unit/polygons/polygons.shx +0 -0
- mapproxy/test/unit/test_async.py +242 -0
- mapproxy/test/unit/test_auth.py +430 -0
- mapproxy/test/unit/test_cache.py +1356 -0
- mapproxy/test/unit/test_cache_azureblob.py +97 -0
- mapproxy/test/unit/test_cache_compact.py +324 -0
- mapproxy/test/unit/test_cache_couchdb.py +118 -0
- mapproxy/test/unit/test_cache_geopackage.py +256 -0
- mapproxy/test/unit/test_cache_redis.py +123 -0
- mapproxy/test/unit/test_cache_riak.py +80 -0
- mapproxy/test/unit/test_cache_s3.py +93 -0
- mapproxy/test/unit/test_cache_tile.py +477 -0
- mapproxy/test/unit/test_client.py +488 -0
- mapproxy/test/unit/test_client_arcgis.py +74 -0
- mapproxy/test/unit/test_client_cgi.py +140 -0
- mapproxy/test/unit/test_collections.py +116 -0
- mapproxy/test/unit/test_concat_legends.py +37 -0
- mapproxy/test/unit/test_conf_loader.py +1267 -0
- mapproxy/test/unit/test_conf_validator.py +427 -0
- mapproxy/test/unit/test_config.py +118 -0
- mapproxy/test/unit/test_decorate_img.py +185 -0
- mapproxy/test/unit/test_exceptions.py +270 -0
- mapproxy/test/unit/test_featureinfo.py +313 -0
- mapproxy/test/unit/test_file_lock_load.py +49 -0
- mapproxy/test/unit/test_geom.py +512 -0
- mapproxy/test/unit/test_grid.py +1279 -0
- mapproxy/test/unit/test_image.py +1051 -0
- mapproxy/test/unit/test_image_mask.py +181 -0
- mapproxy/test/unit/test_image_messages.py +209 -0
- mapproxy/test/unit/test_image_options.py +160 -0
- mapproxy/test/unit/test_isodate.py +118 -0
- mapproxy/test/unit/test_multiapp.py +163 -0
- mapproxy/test/unit/test_ogr_reader.py +51 -0
- mapproxy/test/unit/test_request.py +745 -0
- mapproxy/test/unit/test_request_wmts.py +178 -0
- mapproxy/test/unit/test_response.py +78 -0
- mapproxy/test/unit/test_seed.py +365 -0
- mapproxy/test/unit/test_seed_cachelock.py +91 -0
- mapproxy/test/unit/test_srs.py +215 -0
- mapproxy/test/unit/test_tiled_source.py +122 -0
- mapproxy/test/unit/test_tilefilter.py +31 -0
- mapproxy/test/unit/test_times.py +25 -0
- mapproxy/test/unit/test_timeutils.py +50 -0
- mapproxy/test/unit/test_util_conf_utils.py +75 -0
- mapproxy/test/unit/test_utils.py +476 -0
- mapproxy/test/unit/test_wms_capabilities.py +44 -0
- mapproxy/test/unit/test_wms_layer.py +113 -0
- mapproxy/test/unit/test_yaml.py +68 -0
- mapproxy/tilefilter.py +61 -0
- mapproxy/util/__init__.py +0 -0
- mapproxy/util/async_.py +229 -0
- mapproxy/util/collections.py +134 -0
- mapproxy/util/coverage.py +337 -0
- mapproxy/util/ext/__init__.py +14 -0
- mapproxy/util/ext/dictspec/__init__.py +1 -0
- mapproxy/util/ext/dictspec/spec.py +131 -0
- mapproxy/util/ext/dictspec/test/__init__.py +0 -0
- mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
- mapproxy/util/ext/dictspec/validator.py +194 -0
- mapproxy/util/ext/local.py +198 -0
- mapproxy/util/ext/lockfile.py +140 -0
- mapproxy/util/ext/odict.py +321 -0
- mapproxy/util/ext/serving.py +491 -0
- mapproxy/util/ext/tempita/__init__.py +1093 -0
- mapproxy/util/ext/tempita/_looper.py +163 -0
- mapproxy/util/ext/tempita/string_utils.py +24 -0
- mapproxy/util/ext/wmsparse/__init__.py +3 -0
- mapproxy/util/ext/wmsparse/duration.py +600 -0
- mapproxy/util/ext/wmsparse/parse.py +307 -0
- mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
- mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
- mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
- mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
- mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
- mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
- mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
- mapproxy/util/ext/wmsparse/util.py +189 -0
- mapproxy/util/fs.py +164 -0
- mapproxy/util/geom.py +307 -0
- mapproxy/util/lib.py +117 -0
- mapproxy/util/lock.py +171 -0
- mapproxy/util/ogr.py +247 -0
- mapproxy/util/py.py +75 -0
- mapproxy/util/times.py +78 -0
- mapproxy/util/yaml.py +58 -0
- mapproxy/version.py +33 -0
- mapproxy/wsgiapp.py +167 -0
|
@@ -0,0 +1,1616 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from __future__ import print_function, division
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
import sys
|
|
20
|
+
import functools
|
|
21
|
+
|
|
22
|
+
from io import BytesIO
|
|
23
|
+
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
from mapproxy.image import ImageSource
|
|
27
|
+
from mapproxy.srs import SRS
|
|
28
|
+
from mapproxy.compat.image import Image
|
|
29
|
+
from mapproxy.request.wms import (
|
|
30
|
+
WMS100MapRequest,
|
|
31
|
+
WMS111MapRequest,
|
|
32
|
+
WMS130MapRequest,
|
|
33
|
+
WMS111FeatureInfoRequest,
|
|
34
|
+
WMS111CapabilitiesRequest,
|
|
35
|
+
WMS130CapabilitiesRequest,
|
|
36
|
+
WMS100CapabilitiesRequest,
|
|
37
|
+
WMS100FeatureInfoRequest,
|
|
38
|
+
WMS130FeatureInfoRequest,
|
|
39
|
+
WMS110MapRequest,
|
|
40
|
+
WMS110FeatureInfoRequest,
|
|
41
|
+
WMS110CapabilitiesRequest,
|
|
42
|
+
wms_request,
|
|
43
|
+
)
|
|
44
|
+
from mapproxy.test.image import is_jpeg, is_png, tmp_image, create_tmp_image
|
|
45
|
+
from mapproxy.test.unit.test_image import assert_geotiff_tags
|
|
46
|
+
from mapproxy.test.http import mock_httpd
|
|
47
|
+
from mapproxy.test.helper import validate_with_dtd, validate_with_xsd
|
|
48
|
+
from mapproxy.test.system import SysTest
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.fixture(scope="module")
|
|
52
|
+
def config_file():
|
|
53
|
+
return "layer.yaml"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TestBase(SysTest):
|
|
57
|
+
|
|
58
|
+
def test_invalid_url(self, app):
|
|
59
|
+
app.get("/invalid?fop", status=404)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TestCoverageWMS(SysTest):
|
|
63
|
+
config_file = "layer.yaml"
|
|
64
|
+
|
|
65
|
+
def test_unknown_version_110(self, app):
|
|
66
|
+
resp = app.get(
|
|
67
|
+
"http://localhost/service?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
68
|
+
"&VERSION=1.1.0"
|
|
69
|
+
)
|
|
70
|
+
assert is_110_capa(resp.lxml)
|
|
71
|
+
|
|
72
|
+
def test_unknown_version_113(self, app):
|
|
73
|
+
resp = app.get(
|
|
74
|
+
"http://localhost/service?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
75
|
+
"&VERSION=1.1.3"
|
|
76
|
+
)
|
|
77
|
+
assert is_111_capa(resp.lxml)
|
|
78
|
+
|
|
79
|
+
def test_unknown_version_090(self, app):
|
|
80
|
+
resp = app.get(
|
|
81
|
+
"http://localhost/service?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
82
|
+
"&WMTVER=0.9.0"
|
|
83
|
+
)
|
|
84
|
+
assert is_100_capa(resp.lxml)
|
|
85
|
+
|
|
86
|
+
def test_unknown_version_200(self, app):
|
|
87
|
+
resp = app.get(
|
|
88
|
+
"http://localhost/service?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
89
|
+
"&VERSION=2.0.0"
|
|
90
|
+
)
|
|
91
|
+
assert is_130_capa(resp.lxml)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def bbox_srs_from_boundingbox(bbox_elem):
|
|
95
|
+
return [
|
|
96
|
+
float(bbox_elem.attrib["minx"]),
|
|
97
|
+
float(bbox_elem.attrib["miny"]),
|
|
98
|
+
float(bbox_elem.attrib["maxx"]),
|
|
99
|
+
float(bbox_elem.attrib["maxy"]),
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class TestWMS111(SysTest):
|
|
104
|
+
config_file = "layer.yaml"
|
|
105
|
+
|
|
106
|
+
def setup_method(self):
|
|
107
|
+
# WMSTest.setup_method(self)
|
|
108
|
+
self.common_req = WMS111MapRequest(
|
|
109
|
+
url="/service?", param=dict(service="WMS", version="1.1.1")
|
|
110
|
+
)
|
|
111
|
+
self.common_map_req = WMS111MapRequest(
|
|
112
|
+
url="/service?",
|
|
113
|
+
param=dict(
|
|
114
|
+
service="WMS",
|
|
115
|
+
version="1.1.1",
|
|
116
|
+
bbox="-180,0,0,80",
|
|
117
|
+
width="200",
|
|
118
|
+
height="200",
|
|
119
|
+
layers="wms_cache",
|
|
120
|
+
srs="EPSG:4326",
|
|
121
|
+
format="image/png",
|
|
122
|
+
styles="",
|
|
123
|
+
request="GetMap",
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
self.common_fi_req = WMS111FeatureInfoRequest(
|
|
127
|
+
url="/service?",
|
|
128
|
+
param=dict(
|
|
129
|
+
x="10",
|
|
130
|
+
y="20",
|
|
131
|
+
width="200",
|
|
132
|
+
height="200",
|
|
133
|
+
layers="wms_cache",
|
|
134
|
+
format="image/png",
|
|
135
|
+
query_layers="wms_cache",
|
|
136
|
+
styles="",
|
|
137
|
+
bbox="1000,400,2000,1400",
|
|
138
|
+
srs="EPSG:900913",
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def test_invalid_request_type(self, app):
|
|
143
|
+
req = str(self.common_map_req).replace("GetMap", "invalid")
|
|
144
|
+
resp = app.get(req)
|
|
145
|
+
is_111_exception(resp.lxml, "unknown WMS request type 'invalid'")
|
|
146
|
+
|
|
147
|
+
def test_endpoints(self, app):
|
|
148
|
+
for endpoint in ("service", "ows", "wms"):
|
|
149
|
+
req = WMS111CapabilitiesRequest(
|
|
150
|
+
url="/%s?" % endpoint
|
|
151
|
+
).copy_with_request_params(self.common_req)
|
|
152
|
+
resp = app.get(req)
|
|
153
|
+
assert resp.content_type == "application/vnd.ogc.wms_xml"
|
|
154
|
+
xml = resp.lxml
|
|
155
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.1/WMS_MS_Capabilities.dtd")
|
|
156
|
+
|
|
157
|
+
def test_wms_capabilities(self, app):
|
|
158
|
+
req = WMS111CapabilitiesRequest(url="/service?").copy_with_request_params(
|
|
159
|
+
self.common_req
|
|
160
|
+
)
|
|
161
|
+
resp = app.get(req)
|
|
162
|
+
assert resp.content_type == "application/vnd.ogc.wms_xml"
|
|
163
|
+
xml = resp.lxml
|
|
164
|
+
assert (
|
|
165
|
+
xml.xpath(
|
|
166
|
+
"//GetMap//OnlineResource/@xlink:href",
|
|
167
|
+
namespaces=dict(xlink="http://www.w3.org/1999/xlink"),
|
|
168
|
+
)[0] ==
|
|
169
|
+
"http://localhost/service?"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# test for MetadataURL
|
|
173
|
+
assert (
|
|
174
|
+
xml.xpath(
|
|
175
|
+
"//Layer/MetadataURL/OnlineResource/@xlink:href",
|
|
176
|
+
namespaces=dict(xlink="http://www.w3.org/1999/xlink"),
|
|
177
|
+
)[0] ==
|
|
178
|
+
"http://some.url/"
|
|
179
|
+
)
|
|
180
|
+
assert xml.xpath("//Layer/MetadataURL/@type")[0] == "TC211"
|
|
181
|
+
|
|
182
|
+
layer_names = set(xml.xpath("//Layer/Layer/Name/text()"))
|
|
183
|
+
expected_names = set(
|
|
184
|
+
[
|
|
185
|
+
"direct_fwd_params",
|
|
186
|
+
"direct",
|
|
187
|
+
"wms_cache",
|
|
188
|
+
"wms_cache_100",
|
|
189
|
+
"wms_cache_130",
|
|
190
|
+
"wms_cache_transparent",
|
|
191
|
+
"wms_merge",
|
|
192
|
+
"tms_cache",
|
|
193
|
+
"tms_fi_cache",
|
|
194
|
+
"wms_cache_multi",
|
|
195
|
+
"wms_cache_link_single",
|
|
196
|
+
"wms_cache_110",
|
|
197
|
+
"watermark_cache",
|
|
198
|
+
"wms_managed_cookies_cache",
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
assert layer_names == expected_names
|
|
202
|
+
assert set(xml.xpath("//Layer/Layer[3]/Abstract/text()")) == set(["Some abstract"])
|
|
203
|
+
|
|
204
|
+
bboxs = xml.xpath("//Layer/Layer[1]/BoundingBox")
|
|
205
|
+
bboxs = dict((e.attrib["SRS"], e) for e in bboxs)
|
|
206
|
+
assert_almost_equal_bbox(
|
|
207
|
+
bbox_srs_from_boundingbox(bboxs["EPSG:3857"]),
|
|
208
|
+
[-20037508.3428, -15538711.0963, 18924313.4349, 15538711.0963],
|
|
209
|
+
)
|
|
210
|
+
assert_almost_equal_bbox(
|
|
211
|
+
bbox_srs_from_boundingbox(bboxs["EPSG:4326"]), [-180.0, -70.0, 170.0, 80.0]
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
bbox_srs = xml.xpath("//Layer/Layer/BoundingBox")
|
|
215
|
+
bbox_srs = set(e.attrib["SRS"] for e in bbox_srs)
|
|
216
|
+
# we have a coverage in EPSG:4258, but it is not in wms.srs (#288)
|
|
217
|
+
assert "EPSG:4258" not in bbox_srs
|
|
218
|
+
|
|
219
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.1/WMS_MS_Capabilities.dtd")
|
|
220
|
+
|
|
221
|
+
def test_invalid_layer(self, app):
|
|
222
|
+
self.common_map_req.params["layers"] = "invalid"
|
|
223
|
+
resp = app.get(self.common_map_req)
|
|
224
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
225
|
+
is_111_exception(resp.lxml, "unknown layer: invalid", "LayerNotDefined")
|
|
226
|
+
|
|
227
|
+
def test_invalid_layer_img_exception(self, app):
|
|
228
|
+
self.common_map_req.params["layers"] = "invalid"
|
|
229
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
230
|
+
resp = app.get(self.common_map_req)
|
|
231
|
+
assert resp.content_type == "image/png"
|
|
232
|
+
assert is_png(BytesIO(resp.body))
|
|
233
|
+
|
|
234
|
+
def test_invalid_format(self, app):
|
|
235
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
236
|
+
resp = app.get(self.common_map_req)
|
|
237
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
238
|
+
is_111_exception(
|
|
239
|
+
resp.lxml, "unsupported image format: image/ascii", "InvalidFormat"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def test_invalid_format_img_exception(self, app):
|
|
243
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
244
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
245
|
+
resp = app.get(self.common_map_req)
|
|
246
|
+
assert resp.content_type == "image/png"
|
|
247
|
+
assert is_png(BytesIO(resp.body))
|
|
248
|
+
|
|
249
|
+
def test_invalid_format_options_img_exception(self, app):
|
|
250
|
+
self.common_map_req.params["format"] = "image/png; mode=12bit"
|
|
251
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
252
|
+
resp = app.get(self.common_map_req)
|
|
253
|
+
assert resp.content_type == "image/png"
|
|
254
|
+
assert is_png(BytesIO(resp.body))
|
|
255
|
+
|
|
256
|
+
def test_missing_format_img_exception(self, app):
|
|
257
|
+
del self.common_map_req.params["format"]
|
|
258
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
259
|
+
resp = app.get(self.common_map_req)
|
|
260
|
+
assert resp.content_type == "image/png"
|
|
261
|
+
assert is_png(BytesIO(resp.body))
|
|
262
|
+
|
|
263
|
+
def test_invalid_srs(self, app):
|
|
264
|
+
self.common_map_req.params["srs"] = "EPSG:1234"
|
|
265
|
+
resp = app.get(self.common_map_req)
|
|
266
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
267
|
+
is_111_exception(resp.lxml, "unsupported srs: EPSG:1234", "InvalidSRS")
|
|
268
|
+
|
|
269
|
+
def test_get_map_unknown_style(self, app):
|
|
270
|
+
self.common_map_req.params["styles"] = "unknown"
|
|
271
|
+
resp = app.get(self.common_map_req)
|
|
272
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
273
|
+
is_111_exception(resp.lxml, "unsupported styles: unknown", "StyleNotDefined")
|
|
274
|
+
|
|
275
|
+
def test_get_map_too_large(self, app):
|
|
276
|
+
self.common_map_req.params.size = (5000, 5000)
|
|
277
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
278
|
+
resp = app.get(self.common_map_req)
|
|
279
|
+
# is xml, even if inimage was requested
|
|
280
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
281
|
+
is_111_exception(resp.lxml, "image size too large")
|
|
282
|
+
|
|
283
|
+
def test_get_map_default_style(self, app, fixture_cache_data):
|
|
284
|
+
self.common_map_req.params["styles"] = "default"
|
|
285
|
+
resp = app.get(self.common_map_req)
|
|
286
|
+
assert resp.content_type == "image/png"
|
|
287
|
+
data = BytesIO(resp.body)
|
|
288
|
+
assert is_png(data)
|
|
289
|
+
assert Image.open(data).mode == "RGB"
|
|
290
|
+
|
|
291
|
+
def test_get_map_png(self, app, fixture_cache_data):
|
|
292
|
+
resp = app.get(self.common_map_req)
|
|
293
|
+
assert "Cache-Control" not in resp.headers
|
|
294
|
+
assert resp.content_type == "image/png"
|
|
295
|
+
data = BytesIO(resp.body)
|
|
296
|
+
assert is_png(data)
|
|
297
|
+
assert Image.open(data).mode == "RGB"
|
|
298
|
+
|
|
299
|
+
def test_get_map_float_size(self, app, fixture_cache_data):
|
|
300
|
+
self.common_map_req.params['width'] = '200.0'
|
|
301
|
+
resp = app.get(self.common_map_req)
|
|
302
|
+
assert "Cache-Control" not in resp.headers
|
|
303
|
+
assert resp.content_type == "image/png"
|
|
304
|
+
data = BytesIO(resp.body)
|
|
305
|
+
assert is_png(data)
|
|
306
|
+
assert Image.open(data).mode == "RGB"
|
|
307
|
+
|
|
308
|
+
def test_get_map_png8_custom_format(self, app, fixture_cache_data):
|
|
309
|
+
self.common_map_req.params["layers"] = "wms_cache"
|
|
310
|
+
self.common_map_req.params["format"] = "image/png; mode=8bit"
|
|
311
|
+
resp = app.get(self.common_map_req)
|
|
312
|
+
assert resp.headers["Content-type"] == "image/png; mode=8bit"
|
|
313
|
+
data = BytesIO(resp.body)
|
|
314
|
+
assert is_png(data)
|
|
315
|
+
img = Image.open(data)
|
|
316
|
+
assert img.mode == "P"
|
|
317
|
+
|
|
318
|
+
def test_get_map_png_transparent_non_transparent_data(
|
|
319
|
+
self, app, fixture_cache_data
|
|
320
|
+
):
|
|
321
|
+
self.common_map_req.params["transparent"] = "True"
|
|
322
|
+
resp = app.get(self.common_map_req)
|
|
323
|
+
assert resp.content_type == "image/png"
|
|
324
|
+
data = BytesIO(resp.body)
|
|
325
|
+
assert is_png(data)
|
|
326
|
+
img = Image.open(data)
|
|
327
|
+
assert img.mode == "RGB"
|
|
328
|
+
|
|
329
|
+
def test_get_map_png_transparent(self, app, fixture_cache_data):
|
|
330
|
+
self.common_map_req.params["layers"] = "wms_cache_transparent"
|
|
331
|
+
self.common_map_req.params["transparent"] = "True"
|
|
332
|
+
resp = app.get(self.common_map_req)
|
|
333
|
+
assert resp.content_type == "image/png"
|
|
334
|
+
data = BytesIO(resp.body)
|
|
335
|
+
assert is_png(data)
|
|
336
|
+
assert Image.open(data).mode == "RGBA"
|
|
337
|
+
|
|
338
|
+
def test_get_map_png_w_default_bgcolor(self, app, fixture_cache_data):
|
|
339
|
+
self.common_map_req.params["layers"] = "wms_cache_transparent"
|
|
340
|
+
resp = app.get(self.common_map_req)
|
|
341
|
+
assert resp.content_type == "image/png"
|
|
342
|
+
data = BytesIO(resp.body)
|
|
343
|
+
assert is_png(data)
|
|
344
|
+
img = Image.open(data)
|
|
345
|
+
assert img.mode == "RGB"
|
|
346
|
+
assert img.getcolors()[0][1] == (255, 255, 255)
|
|
347
|
+
|
|
348
|
+
def test_get_map_png_w_bgcolor(self, app, fixture_cache_data):
|
|
349
|
+
self.common_map_req.params["layers"] = "wms_cache_transparent"
|
|
350
|
+
self.common_map_req.params["bgcolor"] = "0xff00a0"
|
|
351
|
+
resp = app.get(self.common_map_req)
|
|
352
|
+
assert resp.content_type == "image/png"
|
|
353
|
+
data = BytesIO(resp.body)
|
|
354
|
+
assert is_png(data)
|
|
355
|
+
img = Image.open(data)
|
|
356
|
+
assert img.mode == "RGB"
|
|
357
|
+
assert sorted(img.getcolors())[-1][1] == (255, 0, 160)
|
|
358
|
+
|
|
359
|
+
def test_get_map_jpeg(self, app, fixture_cache_data):
|
|
360
|
+
self.common_map_req.params["format"] = "image/jpeg"
|
|
361
|
+
resp = app.get(self.common_map_req)
|
|
362
|
+
assert resp.content_type == "image/jpeg"
|
|
363
|
+
assert is_jpeg(BytesIO(resp.body))
|
|
364
|
+
|
|
365
|
+
def test_get_map_geotiff(self, app, fixture_cache_data):
|
|
366
|
+
self.common_map_req.params["format"] = "image/tiff"
|
|
367
|
+
resp = app.get(self.common_map_req)
|
|
368
|
+
assert resp.content_type == "image/tiff"
|
|
369
|
+
img = ImageSource(BytesIO(resp.body)).as_image()
|
|
370
|
+
assert_geotiff_tags(img, (-180, 80), (180/200.0, 80/200.0), 4326, False)
|
|
371
|
+
|
|
372
|
+
def test_get_map_xml_exception(self, app):
|
|
373
|
+
self.common_map_req.params["bbox"] = "0,0,90,90"
|
|
374
|
+
resp = app.get(self.common_map_req)
|
|
375
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
376
|
+
xml = resp.lxml
|
|
377
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
378
|
+
assert "No response from URL" in xml.xpath("//ServiceException/text()")[0]
|
|
379
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
380
|
+
|
|
381
|
+
def test_direct_layer_error(self, app):
|
|
382
|
+
self.common_map_req.params["layers"] = "direct"
|
|
383
|
+
resp = app.get(self.common_map_req)
|
|
384
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
385
|
+
xml = resp.lxml
|
|
386
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
387
|
+
# TODO hide error
|
|
388
|
+
# assert 'unable to get map for layers: direct' in \
|
|
389
|
+
# xml.xpath('//ServiceException/text()')[0]
|
|
390
|
+
assert "No response from URL" in xml.xpath("//ServiceException/text()")[0]
|
|
391
|
+
|
|
392
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
393
|
+
|
|
394
|
+
def test_direct_layer_non_image_response(self, app):
|
|
395
|
+
self.common_map_req.params["layers"] = "direct"
|
|
396
|
+
expected_req = (
|
|
397
|
+
{
|
|
398
|
+
"path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
399
|
+
"&REQUEST=GetMap&HEIGHT=200&SRS=EPSG%3A4326&styles="
|
|
400
|
+
"&VERSION=1.1.1&BBOX=-180.0,0.0,0.0,80.0"
|
|
401
|
+
"&WIDTH=200"
|
|
402
|
+
},
|
|
403
|
+
{"body": b"notanimage", "headers": {"content-type": "image/jpeg"}},
|
|
404
|
+
)
|
|
405
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
406
|
+
resp = app.get(self.common_map_req)
|
|
407
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
408
|
+
xml = resp.lxml
|
|
409
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
410
|
+
assert (
|
|
411
|
+
"error while processing image file"
|
|
412
|
+
in xml.xpath("//ServiceException/text()")[0]
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
416
|
+
|
|
417
|
+
def test_get_map_non_image_response(self, app, cache_dir):
|
|
418
|
+
expected_req = (
|
|
419
|
+
{
|
|
420
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
421
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
422
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
423
|
+
"&WIDTH=256"
|
|
424
|
+
},
|
|
425
|
+
{"body": b"notanimage", "headers": {"content-type": "image/jpeg"}},
|
|
426
|
+
)
|
|
427
|
+
with mock_httpd(
|
|
428
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
429
|
+
):
|
|
430
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
431
|
+
resp = app.get(self.common_map_req)
|
|
432
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
433
|
+
|
|
434
|
+
xml = resp.lxml
|
|
435
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
436
|
+
assert (
|
|
437
|
+
"unable to transform image: cannot identify image file"
|
|
438
|
+
in xml.xpath("//ServiceException/text()")[0]
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
442
|
+
|
|
443
|
+
assert cache_dir.join(
|
|
444
|
+
"wms_cache_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
445
|
+
).check()
|
|
446
|
+
|
|
447
|
+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
|
|
448
|
+
def test_get_map(self, app, base_dir, cache_dir):
|
|
449
|
+
# check global tile lock directory
|
|
450
|
+
tiles_lock_dir = base_dir.join("wmscachetilelockdir")
|
|
451
|
+
# make sure global tile_lock_dir was ot created by other tests
|
|
452
|
+
if tiles_lock_dir.check():
|
|
453
|
+
tiles_lock_dir.remove()
|
|
454
|
+
|
|
455
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
456
|
+
expected_req = (
|
|
457
|
+
{
|
|
458
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
459
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
460
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
461
|
+
"&WIDTH=256"
|
|
462
|
+
},
|
|
463
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
464
|
+
)
|
|
465
|
+
with mock_httpd(
|
|
466
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
467
|
+
):
|
|
468
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
469
|
+
resp = app.get(self.common_map_req)
|
|
470
|
+
assert 35000 < int(resp.headers["Content-length"]) < 75000
|
|
471
|
+
assert resp.content_type == "image/png"
|
|
472
|
+
|
|
473
|
+
# check custom tile_lock_dir
|
|
474
|
+
assert cache_dir.join(
|
|
475
|
+
"wms_cache_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
476
|
+
).check()
|
|
477
|
+
assert tiles_lock_dir.check()
|
|
478
|
+
|
|
479
|
+
def test_get_map_direct_fwd_params_layer(self, app):
|
|
480
|
+
img = create_tmp_image((200, 200), format="png")
|
|
481
|
+
expected_req = (
|
|
482
|
+
{
|
|
483
|
+
"path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
484
|
+
"&REQUEST=GetMap&HEIGHT=200&SRS=EPSG%3A4326&styles="
|
|
485
|
+
"&VERSION=1.1.1&BBOX=-180.0,0.0,0.0,80.0"
|
|
486
|
+
"&WIDTH=200&TIME=20041012"
|
|
487
|
+
},
|
|
488
|
+
{"body": img},
|
|
489
|
+
)
|
|
490
|
+
with mock_httpd(
|
|
491
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
492
|
+
):
|
|
493
|
+
self.common_map_req.params["layers"] = "direct_fwd_params"
|
|
494
|
+
self.common_map_req.params["time"] = "20041012"
|
|
495
|
+
resp = app.get(self.common_map_req)
|
|
496
|
+
assert resp.content_type == "image/png"
|
|
497
|
+
|
|
498
|
+
def test_get_map_use_direct_from_level(self, app):
|
|
499
|
+
with tmp_image((200, 200), format="png") as img:
|
|
500
|
+
expected_req = (
|
|
501
|
+
{
|
|
502
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
503
|
+
"&REQUEST=GetMap&HEIGHT=200&SRS=EPSG%3A4326&styles="
|
|
504
|
+
"&VERSION=1.1.1&BBOX=5.0,-10.0,6.0,-9.0"
|
|
505
|
+
"&WIDTH=200"
|
|
506
|
+
},
|
|
507
|
+
{"body": img.read(), "headers": {"content-type": "image/png"}},
|
|
508
|
+
)
|
|
509
|
+
with mock_httpd(
|
|
510
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
511
|
+
):
|
|
512
|
+
self.common_map_req.params["bbox"] = "5,-10,6,-9"
|
|
513
|
+
resp = app.get(self.common_map_req)
|
|
514
|
+
img.seek(0)
|
|
515
|
+
assert resp.body == img.read()
|
|
516
|
+
is_png(img)
|
|
517
|
+
assert resp.content_type == "image/png"
|
|
518
|
+
|
|
519
|
+
def test_get_map_use_direct_from_level_with_transform(self, app):
|
|
520
|
+
with tmp_image((200, 200), format="png") as img:
|
|
521
|
+
expected_req = (
|
|
522
|
+
{
|
|
523
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
524
|
+
"&REQUEST=GetMap&HEIGHT=200&SRS=EPSG%3A900913&styles="
|
|
525
|
+
"&VERSION=1.1.1&BBOX=908822.944624,7004479.85652,920282.144964,7014491.63726"
|
|
526
|
+
"&WIDTH=229"
|
|
527
|
+
},
|
|
528
|
+
{"body": img.read(), "headers": {"content-type": "image/png"}},
|
|
529
|
+
)
|
|
530
|
+
with mock_httpd(
|
|
531
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
532
|
+
):
|
|
533
|
+
self.common_map_req.params[
|
|
534
|
+
"bbox"
|
|
535
|
+
] = "444122.311736,5885498.04243,450943.508884,5891425.10484"
|
|
536
|
+
self.common_map_req.params["srs"] = "EPSG:25832"
|
|
537
|
+
resp = app.get(self.common_map_req)
|
|
538
|
+
img.seek(0)
|
|
539
|
+
assert resp.body != img.read()
|
|
540
|
+
is_png(img)
|
|
541
|
+
assert resp.content_type == "image/png"
|
|
542
|
+
|
|
543
|
+
def test_get_map_invalid_bbox(self, app):
|
|
544
|
+
# min x larger than max x
|
|
545
|
+
url = (
|
|
546
|
+
"""/service?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&BBOX=7,2,-9,10&SRS=EPSG:4326&WIDTH=164&HEIGHT=388&LAYERS=wms_cache&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE""" # noqa
|
|
547
|
+
)
|
|
548
|
+
resp = app.get(url)
|
|
549
|
+
is_111_exception(resp.lxml, "invalid bbox 7,2,-9,10")
|
|
550
|
+
|
|
551
|
+
def test_get_map_invalid_bbox2(self, app):
|
|
552
|
+
# broken bbox for the requested srs
|
|
553
|
+
url = (
|
|
554
|
+
"""/service?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&BBOX=-72988843.697212,-255661507.634227,142741550.188860,255661507.634227&SRS=EPSG:25833&WIDTH=164&HEIGHT=388&LAYERS=wms_cache_100&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE""" # noqa
|
|
555
|
+
)
|
|
556
|
+
resp = app.get(url)
|
|
557
|
+
# result depends on proj version
|
|
558
|
+
is_111_exception(
|
|
559
|
+
resp.lxml,
|
|
560
|
+
re_msg="Request too large or invalid BBOX.|Could not transform BBOX: Invalid result.",
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
def test_get_map_broken_bbox(self, app):
|
|
564
|
+
url = (
|
|
565
|
+
"""/service?VERSION=1.1.11&REQUEST=GetMap&SRS=EPSG:31468&BBOX=-20000855.0573254,2847125.18913603,-19329367.42767611,4239924.78564583&WIDTH=130&HEIGHT=62&LAYERS=wms_cache&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE""" # noqa
|
|
566
|
+
)
|
|
567
|
+
resp = app.get(url)
|
|
568
|
+
is_111_exception(resp.lxml, "Could not transform BBOX: Invalid result.")
|
|
569
|
+
|
|
570
|
+
def test_get_map100(self, app, base_dir, cache_dir):
|
|
571
|
+
# check global tile lock directory
|
|
572
|
+
tiles_lock_dir = base_dir.join("defaulttilelockdir")
|
|
573
|
+
# make sure global tile_lock_dir was ot created by other tests
|
|
574
|
+
if tiles_lock_dir.check():
|
|
575
|
+
tiles_lock_dir.remove()
|
|
576
|
+
|
|
577
|
+
# request_format tiff, cache format jpeg, wms request in png
|
|
578
|
+
with tmp_image((256, 256), format="tiff") as img:
|
|
579
|
+
expected_req = (
|
|
580
|
+
{
|
|
581
|
+
"path": r"/service?LAYERs=foo,bar&FORMAT=TIFF"
|
|
582
|
+
"&REQUEST=map&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
583
|
+
"&WMTVER=1.0.0&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
584
|
+
"&WIDTH=256"
|
|
585
|
+
},
|
|
586
|
+
{"body": img.read(), "headers": {"content-type": "image/tiff"}},
|
|
587
|
+
)
|
|
588
|
+
with mock_httpd(
|
|
589
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
590
|
+
):
|
|
591
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
592
|
+
self.common_map_req.params["layers"] = "wms_cache_100"
|
|
593
|
+
resp = app.get(self.common_map_req)
|
|
594
|
+
assert resp.content_type == "image/png"
|
|
595
|
+
|
|
596
|
+
# check global tile lock directory was created
|
|
597
|
+
assert tiles_lock_dir.check()
|
|
598
|
+
|
|
599
|
+
assert cache_dir.join(
|
|
600
|
+
"wms_cache_100_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
601
|
+
).check()
|
|
602
|
+
|
|
603
|
+
def test_get_map130(self, app, cache_dir):
|
|
604
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
605
|
+
expected_req = (
|
|
606
|
+
{
|
|
607
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
608
|
+
"&REQUEST=GetMap&HEIGHT=256&CRS=EPSG%3A900913&styles="
|
|
609
|
+
"&VERSION=1.3.0&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
610
|
+
"&WIDTH=256"
|
|
611
|
+
},
|
|
612
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
613
|
+
)
|
|
614
|
+
with mock_httpd(
|
|
615
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
616
|
+
):
|
|
617
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
618
|
+
self.common_map_req.params["layers"] = "wms_cache_130"
|
|
619
|
+
resp = app.get(self.common_map_req)
|
|
620
|
+
assert resp.content_type == "image/png"
|
|
621
|
+
assert cache_dir.join(
|
|
622
|
+
"wms_cache_130_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
623
|
+
).check()
|
|
624
|
+
|
|
625
|
+
def test_get_map130_axis_order(self, app, cache_dir):
|
|
626
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
627
|
+
img = img.read()
|
|
628
|
+
expected_reqs = [
|
|
629
|
+
(
|
|
630
|
+
{
|
|
631
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
632
|
+
"&REQUEST=GetMap&HEIGHT=256&CRS=EPSG%3A4326&styles="
|
|
633
|
+
"&VERSION=1.3.0&BBOX=0.0,90.0,90.0,180.0"
|
|
634
|
+
"&WIDTH=256"
|
|
635
|
+
},
|
|
636
|
+
{"body": img, "headers": {"content-type": "image/jpeg"}},
|
|
637
|
+
)
|
|
638
|
+
]
|
|
639
|
+
with mock_httpd(("localhost", 42423), expected_reqs):
|
|
640
|
+
self.common_map_req.params["bbox"] = "90,0,180,90"
|
|
641
|
+
self.common_map_req.params["layers"] = "wms_cache_multi"
|
|
642
|
+
resp = app.get(self.common_map_req)
|
|
643
|
+
assert resp.content_type == "image/png"
|
|
644
|
+
assert cache_dir.join(
|
|
645
|
+
"wms_cache_multi_EPSG4326/02/000/000/003/000/000/001.jpeg"
|
|
646
|
+
).check()
|
|
647
|
+
|
|
648
|
+
def test_get_featureinfo(self, app):
|
|
649
|
+
expected_req = (
|
|
650
|
+
{
|
|
651
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
652
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
653
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
654
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20&feature_count=100"
|
|
655
|
+
},
|
|
656
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
657
|
+
)
|
|
658
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
659
|
+
self.common_fi_req.params["feature_count"] = 100
|
|
660
|
+
resp = app.get(self.common_fi_req)
|
|
661
|
+
assert resp.content_type == "text/plain"
|
|
662
|
+
assert resp.body == b"info"
|
|
663
|
+
|
|
664
|
+
def test_get_featureinfo_coverage(self, app):
|
|
665
|
+
self.common_fi_req.params["bbox"] = "-180.0,-90.0,180.0,90.0"
|
|
666
|
+
self.common_fi_req.params["srs"] = "EPSG:4326"
|
|
667
|
+
self.common_fi_req.params["width"] = "400"
|
|
668
|
+
self.common_fi_req.params["height"] = "200"
|
|
669
|
+
self.common_fi_req.params["x"] = 395 # outside of coverage
|
|
670
|
+
self.common_fi_req.params["y"] = 50
|
|
671
|
+
self.common_fi_req.params["layers"] = 'tms_fi_cache'
|
|
672
|
+
self.common_fi_req.params["query_layers"] = 'tms_fi_cache'
|
|
673
|
+
|
|
674
|
+
resp = app.get(self.common_fi_req)
|
|
675
|
+
assert resp.body == b""
|
|
676
|
+
assert resp.content_type == "text/plain"
|
|
677
|
+
|
|
678
|
+
expected_req = (
|
|
679
|
+
{
|
|
680
|
+
"path": r"/service?LAYERs=fi&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
681
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A4326"
|
|
682
|
+
"&VERSION=1.1.1&BBOX=-180.0,-90.0,180.0,90.0&styles="
|
|
683
|
+
"&WIDTH=400&QUERY_LAYERS=fi&X=380&Y=50"
|
|
684
|
+
},
|
|
685
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
686
|
+
)
|
|
687
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
688
|
+
self.common_fi_req.params["x"] = 380 # inside of coverage
|
|
689
|
+
|
|
690
|
+
resp = app.get(self.common_fi_req)
|
|
691
|
+
assert resp.body == b"info"
|
|
692
|
+
assert resp.content_type == "text/plain"
|
|
693
|
+
|
|
694
|
+
def test_get_featureinfo_float(self, app):
|
|
695
|
+
expected_req = (
|
|
696
|
+
{
|
|
697
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
698
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
699
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
700
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10.123&Y=20.567&feature_count=100"
|
|
701
|
+
},
|
|
702
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
703
|
+
)
|
|
704
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
705
|
+
self.common_fi_req.params["feature_count"] = 100
|
|
706
|
+
self.common_fi_req.params["x"] = 10.123
|
|
707
|
+
self.common_fi_req.params["y"] = 20.567
|
|
708
|
+
resp = app.get(self.common_fi_req)
|
|
709
|
+
assert resp.content_type == "text/plain"
|
|
710
|
+
assert resp.body == b"info"
|
|
711
|
+
|
|
712
|
+
def test_get_featureinfo_transformed(self, app):
|
|
713
|
+
expected_req = (
|
|
714
|
+
{
|
|
715
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
716
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
717
|
+
"&BBOX=1172272.30156,7196018.03449,1189711.04571,7213496.99738"
|
|
718
|
+
"&styles=&VERSION=1.1.1&feature_count=100"
|
|
719
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=14&Y=20"
|
|
720
|
+
},
|
|
721
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
# out fi point at x=10,y=20
|
|
725
|
+
p_25832 = (
|
|
726
|
+
600000 + 10 * (610000 - 600000) / 200,
|
|
727
|
+
6010000 - 20 * (6010000 - 6000000) / 200,
|
|
728
|
+
)
|
|
729
|
+
# the transformed fi point at x=14,y=20
|
|
730
|
+
p_900913 = (
|
|
731
|
+
1172272.30156 + 14 * (1189711.04571 - 1172272.30156) / 200,
|
|
732
|
+
7213496.99738 - 20 * (7213496.99738 - 7196018.03449) / 200,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
# are they the same?
|
|
736
|
+
# check with tolerance: pixel resolution is ~50 and x/y position is rounded to pizel
|
|
737
|
+
assert abs(SRS(25832).transform_to(SRS(900913), p_25832)[0] - p_900913[0]) < 50
|
|
738
|
+
assert abs(SRS(25832).transform_to(SRS(900913), p_25832)[1] - p_900913[1]) < 50
|
|
739
|
+
|
|
740
|
+
with mock_httpd(
|
|
741
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
742
|
+
):
|
|
743
|
+
self.common_fi_req.params["bbox"] = "600000,6000000,610000,6010000"
|
|
744
|
+
self.common_fi_req.params["srs"] = "EPSG:25832"
|
|
745
|
+
self.common_fi_req.params.pos = 10, 20
|
|
746
|
+
self.common_fi_req.params["feature_count"] = 100
|
|
747
|
+
resp = app.get(self.common_fi_req)
|
|
748
|
+
assert resp.content_type == "text/plain"
|
|
749
|
+
assert resp.body == b"info"
|
|
750
|
+
|
|
751
|
+
def test_get_featureinfo_info_format(self, app):
|
|
752
|
+
expected_req = (
|
|
753
|
+
{
|
|
754
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
755
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
756
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
757
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20"
|
|
758
|
+
"&info_format=text%2Fhtml"
|
|
759
|
+
},
|
|
760
|
+
{"body": b"info", "headers": {"content-type": "text/html"}},
|
|
761
|
+
)
|
|
762
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
763
|
+
self.common_fi_req.params["info_format"] = "text/html"
|
|
764
|
+
resp = app.get(self.common_fi_req)
|
|
765
|
+
assert resp.content_type == "text/html"
|
|
766
|
+
assert resp.body == b"<html><body><p>info</p></body></html>"
|
|
767
|
+
|
|
768
|
+
def test_get_featureinfo_130(self, app):
|
|
769
|
+
expected_req = (
|
|
770
|
+
{
|
|
771
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
772
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&CRS=EPSG%3A900913"
|
|
773
|
+
"&VERSION=1.3.0&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
774
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&I=10&J=20"
|
|
775
|
+
},
|
|
776
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
777
|
+
)
|
|
778
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
779
|
+
self.common_fi_req.params["layers"] = "wms_cache_130"
|
|
780
|
+
self.common_fi_req.params["query_layers"] = "wms_cache_130"
|
|
781
|
+
resp = app.get(self.common_fi_req)
|
|
782
|
+
assert resp.content_type == "text/plain"
|
|
783
|
+
assert resp.body == b"info"
|
|
784
|
+
|
|
785
|
+
def test_get_featureinfo_missing_params(self, app):
|
|
786
|
+
expected_req = (
|
|
787
|
+
{
|
|
788
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
789
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
790
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
791
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20"
|
|
792
|
+
},
|
|
793
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
794
|
+
)
|
|
795
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
796
|
+
del self.common_fi_req.params["format"]
|
|
797
|
+
del self.common_fi_req.params["styles"]
|
|
798
|
+
resp = app.get(self.common_fi_req)
|
|
799
|
+
assert resp.content_type == "text/plain"
|
|
800
|
+
assert resp.body == b"info"
|
|
801
|
+
|
|
802
|
+
def test_get_featureinfo_missing_params_strict(self, app):
|
|
803
|
+
request_parser = app.app.handlers["service"].services["wms"].request_parser
|
|
804
|
+
try:
|
|
805
|
+
app.app.handlers["service"].services[
|
|
806
|
+
"wms"
|
|
807
|
+
].request_parser = functools.partial(wms_request, strict=True)
|
|
808
|
+
|
|
809
|
+
del self.common_fi_req.params["format"]
|
|
810
|
+
del self.common_fi_req.params["styles"]
|
|
811
|
+
resp = app.get(self.common_fi_req)
|
|
812
|
+
xml = resp.lxml
|
|
813
|
+
assert "missing parameters" in xml.xpath("//ServiceException/text()")[0]
|
|
814
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
815
|
+
finally:
|
|
816
|
+
app.app.handlers["service"].services["wms"].request_parser = request_parser
|
|
817
|
+
app.app.handlers["service"].request_parser = request_parser
|
|
818
|
+
|
|
819
|
+
def test_get_featureinfo_not_queryable(self, app):
|
|
820
|
+
self.common_fi_req.params["query_layers"] = "tms_cache"
|
|
821
|
+
self.common_fi_req.params["exceptions"] = "application/vnd.ogc.se_xml"
|
|
822
|
+
resp = app.get(self.common_fi_req)
|
|
823
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
824
|
+
xml = resp.lxml
|
|
825
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
826
|
+
assert "tms_cache is not queryable" in xml.xpath("//ServiceException/text()")[0]
|
|
827
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
class TestWMS110(SysTest):
|
|
831
|
+
config_file = "layer.yaml"
|
|
832
|
+
|
|
833
|
+
def setup_method(self):
|
|
834
|
+
# WMSTest.setup_method(self)
|
|
835
|
+
self.common_req = WMS110MapRequest(
|
|
836
|
+
url="/service?", param=dict(service="WMS", version="1.1.0")
|
|
837
|
+
)
|
|
838
|
+
self.common_map_req = WMS110MapRequest(
|
|
839
|
+
url="/service?",
|
|
840
|
+
param=dict(
|
|
841
|
+
service="WMS",
|
|
842
|
+
version="1.1.0",
|
|
843
|
+
bbox="-180,0,0,80",
|
|
844
|
+
width="200",
|
|
845
|
+
height="200",
|
|
846
|
+
layers="wms_cache",
|
|
847
|
+
srs="EPSG:4326",
|
|
848
|
+
format="image/png",
|
|
849
|
+
styles="",
|
|
850
|
+
request="GetMap",
|
|
851
|
+
),
|
|
852
|
+
)
|
|
853
|
+
self.common_fi_req = WMS110FeatureInfoRequest(
|
|
854
|
+
url="/service?",
|
|
855
|
+
param=dict(
|
|
856
|
+
x="10",
|
|
857
|
+
y="20",
|
|
858
|
+
width="200",
|
|
859
|
+
height="200",
|
|
860
|
+
layers="wms_cache",
|
|
861
|
+
format="image/png",
|
|
862
|
+
query_layers="wms_cache_110",
|
|
863
|
+
styles="",
|
|
864
|
+
bbox="1000,400,2000,1400",
|
|
865
|
+
srs="EPSG:900913",
|
|
866
|
+
),
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
def test_wms_capabilities(self, app):
|
|
870
|
+
req = WMS110CapabilitiesRequest(url="/service?").copy_with_request_params(
|
|
871
|
+
self.common_req
|
|
872
|
+
)
|
|
873
|
+
resp = app.get(req)
|
|
874
|
+
assert resp.content_type == "application/vnd.ogc.wms_xml"
|
|
875
|
+
xml = resp.lxml
|
|
876
|
+
assert (
|
|
877
|
+
xml.xpath(
|
|
878
|
+
"//GetMap//OnlineResource/@xlink:href",
|
|
879
|
+
namespaces=dict(xlink="http://www.w3.org/1999/xlink"),
|
|
880
|
+
)[0] ==
|
|
881
|
+
"http://localhost/service?"
|
|
882
|
+
)
|
|
883
|
+
|
|
884
|
+
llbox = xml.xpath("//Capability/Layer/LatLonBoundingBox")[0]
|
|
885
|
+
# some clients don't like 90deg north/south
|
|
886
|
+
assert float(llbox.attrib["miny"]) == pytest.approx(-70.0)
|
|
887
|
+
assert float(llbox.attrib["maxy"]) == pytest.approx(89.999999)
|
|
888
|
+
assert float(llbox.attrib["minx"]) == pytest.approx(-180.0)
|
|
889
|
+
assert float(llbox.attrib["maxx"]) == pytest.approx(180.0)
|
|
890
|
+
|
|
891
|
+
layer_names = set(xml.xpath("//Layer/Layer/Name/text()"))
|
|
892
|
+
expected_names = set(
|
|
893
|
+
[
|
|
894
|
+
"direct_fwd_params",
|
|
895
|
+
"direct",
|
|
896
|
+
"wms_cache",
|
|
897
|
+
"wms_cache_100",
|
|
898
|
+
"wms_cache_130",
|
|
899
|
+
"wms_cache_transparent",
|
|
900
|
+
"wms_merge",
|
|
901
|
+
"tms_cache",
|
|
902
|
+
"tms_fi_cache",
|
|
903
|
+
"wms_cache_multi",
|
|
904
|
+
"wms_cache_link_single",
|
|
905
|
+
"wms_cache_110",
|
|
906
|
+
"watermark_cache",
|
|
907
|
+
"wms_managed_cookies_cache",
|
|
908
|
+
]
|
|
909
|
+
)
|
|
910
|
+
assert layer_names == expected_names
|
|
911
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.0/capabilities_1_1_0.dtd")
|
|
912
|
+
|
|
913
|
+
def test_invalid_layer(self, app):
|
|
914
|
+
self.common_map_req.params["layers"] = "invalid"
|
|
915
|
+
resp = app.get(self.common_map_req)
|
|
916
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
917
|
+
xml = resp.lxml
|
|
918
|
+
assert xml.xpath("/ServiceExceptionReport/@version")[0] == "1.1.0"
|
|
919
|
+
assert (
|
|
920
|
+
xml.xpath("/ServiceExceptionReport/ServiceException/@code")[0] ==
|
|
921
|
+
"LayerNotDefined"
|
|
922
|
+
)
|
|
923
|
+
assert xml.xpath("//ServiceException/text()")[0] == "unknown layer: invalid"
|
|
924
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.0/exception_1_1_0.dtd")
|
|
925
|
+
|
|
926
|
+
def test_invalid_format(self, app):
|
|
927
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
928
|
+
resp = app.get(self.common_map_req)
|
|
929
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
930
|
+
xml = resp.lxml
|
|
931
|
+
assert xml.xpath("/ServiceExceptionReport/@version")[0] == "1.1.0"
|
|
932
|
+
assert (
|
|
933
|
+
xml.xpath("/ServiceExceptionReport/ServiceException/@code")[0] ==
|
|
934
|
+
"InvalidFormat"
|
|
935
|
+
)
|
|
936
|
+
assert (
|
|
937
|
+
xml.xpath("//ServiceException/text()")[0] ==
|
|
938
|
+
"unsupported image format: image/ascii"
|
|
939
|
+
)
|
|
940
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.0/exception_1_1_0.dtd")
|
|
941
|
+
|
|
942
|
+
def test_invalid_format_img_exception(self, app):
|
|
943
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
944
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
945
|
+
resp = app.get(self.common_map_req)
|
|
946
|
+
assert resp.content_type == "image/png"
|
|
947
|
+
assert is_png(BytesIO(resp.body))
|
|
948
|
+
|
|
949
|
+
def test_missing_format_img_exception(self, app):
|
|
950
|
+
del self.common_map_req.params["format"]
|
|
951
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
952
|
+
resp = app.get(self.common_map_req)
|
|
953
|
+
assert resp.content_type == "image/png"
|
|
954
|
+
assert is_png(BytesIO(resp.body))
|
|
955
|
+
|
|
956
|
+
def test_invalid_srs(self, app):
|
|
957
|
+
self.common_map_req.params["srs"] = "EPSG:1234"
|
|
958
|
+
resp = app.get(self.common_map_req)
|
|
959
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
960
|
+
xml = resp.lxml
|
|
961
|
+
assert xml.xpath("/ServiceExceptionReport/@version")[0] == "1.1.0"
|
|
962
|
+
assert (
|
|
963
|
+
xml.xpath("/ServiceExceptionReport/ServiceException/@code")[0] == "InvalidSRS"
|
|
964
|
+
)
|
|
965
|
+
assert xml.xpath("//ServiceException/text()")[0] == "unsupported srs: EPSG:1234"
|
|
966
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.1.0/exception_1_1_0.dtd")
|
|
967
|
+
|
|
968
|
+
def test_get_map_png(self, app, fixture_cache_data):
|
|
969
|
+
resp = app.get(self.common_map_req)
|
|
970
|
+
assert resp.content_type == "image/png"
|
|
971
|
+
data = BytesIO(resp.body)
|
|
972
|
+
assert is_png(data)
|
|
973
|
+
assert Image.open(data).mode == "RGB"
|
|
974
|
+
|
|
975
|
+
def test_get_map_jpeg(self, app, fixture_cache_data):
|
|
976
|
+
self.common_map_req.params["format"] = "image/jpeg"
|
|
977
|
+
resp = app.get(self.common_map_req)
|
|
978
|
+
assert resp.content_type == "image/jpeg"
|
|
979
|
+
assert is_jpeg(BytesIO(resp.body))
|
|
980
|
+
|
|
981
|
+
def test_get_map_xml_exception(self, app):
|
|
982
|
+
self.common_map_req.params["bbox"] = "0,0,90,90"
|
|
983
|
+
resp = app.get(self.common_map_req)
|
|
984
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
985
|
+
xml = resp.lxml
|
|
986
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
987
|
+
assert "No response from URL" in xml.xpath("//ServiceException/text()")[0]
|
|
988
|
+
assert validate_with_dtd(xml, "wms/1.1.0/exception_1_1_0.dtd")
|
|
989
|
+
|
|
990
|
+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
|
|
991
|
+
def test_get_map(self, app, cache_dir):
|
|
992
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
993
|
+
expected_req = (
|
|
994
|
+
{
|
|
995
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
996
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
997
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
998
|
+
"&WIDTH=256"
|
|
999
|
+
},
|
|
1000
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
1001
|
+
)
|
|
1002
|
+
with mock_httpd(
|
|
1003
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
1004
|
+
):
|
|
1005
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
1006
|
+
resp = app.get(self.common_map_req)
|
|
1007
|
+
assert 35000 < int(resp.headers["Content-length"]) < 75000
|
|
1008
|
+
assert resp.content_type == "image/png"
|
|
1009
|
+
|
|
1010
|
+
assert cache_dir.join(
|
|
1011
|
+
"wms_cache_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
1012
|
+
).check()
|
|
1013
|
+
|
|
1014
|
+
def test_get_map_110(self, app, cache_dir):
|
|
1015
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
1016
|
+
expected_req = (
|
|
1017
|
+
{
|
|
1018
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
1019
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
1020
|
+
"&VERSION=1.1.0&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
1021
|
+
"&WIDTH=256"
|
|
1022
|
+
},
|
|
1023
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
1024
|
+
)
|
|
1025
|
+
with mock_httpd(
|
|
1026
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
1027
|
+
):
|
|
1028
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
1029
|
+
self.common_map_req.params["layers"] = "wms_cache_110"
|
|
1030
|
+
resp = app.get(self.common_map_req)
|
|
1031
|
+
assert 35000 < int(resp.headers["Content-length"]) < 75000
|
|
1032
|
+
assert resp.content_type == "image/png"
|
|
1033
|
+
|
|
1034
|
+
assert cache_dir.join(
|
|
1035
|
+
"wms_cache_110_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
1036
|
+
).check()
|
|
1037
|
+
|
|
1038
|
+
def test_get_featureinfo(self, app):
|
|
1039
|
+
expected_req = (
|
|
1040
|
+
{
|
|
1041
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
1042
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
1043
|
+
"&VERSION=1.1.0&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
1044
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20"
|
|
1045
|
+
},
|
|
1046
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
1047
|
+
)
|
|
1048
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
1049
|
+
resp = app.get(self.common_fi_req)
|
|
1050
|
+
assert resp.content_type == "text/plain"
|
|
1051
|
+
assert resp.body == b"info"
|
|
1052
|
+
|
|
1053
|
+
def test_get_featureinfo_not_queryable(self, app):
|
|
1054
|
+
self.common_fi_req.params["query_layers"] = "tms_cache"
|
|
1055
|
+
self.common_fi_req.params["exceptions"] = "application/vnd.ogc.se_xml"
|
|
1056
|
+
resp = app.get(self.common_fi_req)
|
|
1057
|
+
assert resp.content_type == "application/vnd.ogc.se_xml"
|
|
1058
|
+
xml = resp.lxml
|
|
1059
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code") == []
|
|
1060
|
+
assert "tms_cache is not queryable" in xml.xpath("//ServiceException/text()")[0]
|
|
1061
|
+
assert validate_with_dtd(xml, "wms/1.1.0/exception_1_1_0.dtd")
|
|
1062
|
+
|
|
1063
|
+
def test_managed_cookies(self, app):
|
|
1064
|
+
def assert_no_cookie(req_handler):
|
|
1065
|
+
return 'Cookie' not in req_handler.headers
|
|
1066
|
+
|
|
1067
|
+
def assert_cookie(req_handler):
|
|
1068
|
+
assert 'Cookie' in req_handler.headers
|
|
1069
|
+
cookie_name, cookie_val = req_handler.headers['Cookie'].split(';')[0].split('=')
|
|
1070
|
+
assert cookie_name == 'testcookie'
|
|
1071
|
+
assert cookie_val == '42'
|
|
1072
|
+
return True
|
|
1073
|
+
|
|
1074
|
+
url = (r"/service?LAYERs=layer1&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
1075
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
1076
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
1077
|
+
"&WIDTH=200&QUERY_LAYERS=layer1&X=10&Y=20")
|
|
1078
|
+
# First response has a Set-Cookie => with managed_cookies=True, mapproxy should send the
|
|
1079
|
+
# cookie in the second request
|
|
1080
|
+
expected_requests = [
|
|
1081
|
+
(
|
|
1082
|
+
{'path': url, 'req_assert_function': assert_no_cookie},
|
|
1083
|
+
{'body': b'nothing', 'headers': {'Set-Cookie': "testcookie=42"}}
|
|
1084
|
+
),
|
|
1085
|
+
(
|
|
1086
|
+
{'path': url, 'req_assert_function': assert_cookie},
|
|
1087
|
+
{'body': b'nothing'}
|
|
1088
|
+
)
|
|
1089
|
+
]
|
|
1090
|
+
with mock_httpd(("localhost", 42423), expected_requests):
|
|
1091
|
+
self.common_fi_req.params["layers"] = "wms_managed_cookies_cache"
|
|
1092
|
+
self.common_fi_req.params["query_layers"] = "wms_managed_cookies_cache"
|
|
1093
|
+
resp = app.get(self.common_fi_req)
|
|
1094
|
+
assert resp.body == b"nothing"
|
|
1095
|
+
resp = app.get(self.common_fi_req)
|
|
1096
|
+
assert resp.body == b"nothing"
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
class TestWMS100(SysTest):
|
|
1100
|
+
config_file = "layer.yaml"
|
|
1101
|
+
|
|
1102
|
+
def setup_method(self):
|
|
1103
|
+
self.common_req = WMS100MapRequest(url="/service?", param=dict(wmtver="1.0.0"))
|
|
1104
|
+
self.common_map_req = WMS100MapRequest(
|
|
1105
|
+
url="/service?",
|
|
1106
|
+
param=dict(
|
|
1107
|
+
wmtver="1.0.0",
|
|
1108
|
+
bbox="-180,0,0,80",
|
|
1109
|
+
width="200",
|
|
1110
|
+
height="200",
|
|
1111
|
+
layers="wms_cache",
|
|
1112
|
+
srs="EPSG:4326",
|
|
1113
|
+
format="PNG",
|
|
1114
|
+
styles="",
|
|
1115
|
+
request="GetMap",
|
|
1116
|
+
),
|
|
1117
|
+
)
|
|
1118
|
+
self.common_fi_req = WMS100FeatureInfoRequest(
|
|
1119
|
+
url="/service?",
|
|
1120
|
+
param=dict(
|
|
1121
|
+
x="10",
|
|
1122
|
+
y="20",
|
|
1123
|
+
width="200",
|
|
1124
|
+
height="200",
|
|
1125
|
+
layers="wms_cache_100",
|
|
1126
|
+
format="PNG",
|
|
1127
|
+
query_layers="wms_cache_100",
|
|
1128
|
+
styles="",
|
|
1129
|
+
bbox="1000,400,2000,1400",
|
|
1130
|
+
srs="EPSG:900913",
|
|
1131
|
+
),
|
|
1132
|
+
)
|
|
1133
|
+
|
|
1134
|
+
def test_wms_capabilities(self, app):
|
|
1135
|
+
req = WMS100CapabilitiesRequest(url="/service?").copy_with_request_params(
|
|
1136
|
+
self.common_req
|
|
1137
|
+
)
|
|
1138
|
+
resp = app.get(req)
|
|
1139
|
+
assert resp.content_type == "text/xml"
|
|
1140
|
+
xml = resp.lxml
|
|
1141
|
+
assert (
|
|
1142
|
+
xml.xpath("/WMT_MS_Capabilities/Service/Title/text()")[0] ==
|
|
1143
|
+
u"MapProxy test fixture \u2603"
|
|
1144
|
+
)
|
|
1145
|
+
layer_names = set(xml.xpath("//Layer/Layer/Name/text()"))
|
|
1146
|
+
expected_names = set(
|
|
1147
|
+
[
|
|
1148
|
+
"direct_fwd_params",
|
|
1149
|
+
"direct",
|
|
1150
|
+
"wms_cache",
|
|
1151
|
+
"wms_cache_100",
|
|
1152
|
+
"wms_cache_130",
|
|
1153
|
+
"wms_cache_transparent",
|
|
1154
|
+
"wms_merge",
|
|
1155
|
+
"tms_cache",
|
|
1156
|
+
"tms_fi_cache",
|
|
1157
|
+
"wms_cache_multi",
|
|
1158
|
+
"wms_cache_link_single",
|
|
1159
|
+
"wms_cache_110",
|
|
1160
|
+
"watermark_cache",
|
|
1161
|
+
"wms_managed_cookies_cache",
|
|
1162
|
+
]
|
|
1163
|
+
)
|
|
1164
|
+
assert layer_names == expected_names
|
|
1165
|
+
# TODO srs
|
|
1166
|
+
assert validate_with_dtd(xml, dtd_name="wms/1.0.0/capabilities_1_0_0.dtd")
|
|
1167
|
+
|
|
1168
|
+
def test_invalid_layer(self, app):
|
|
1169
|
+
self.common_map_req.params["layers"] = "invalid"
|
|
1170
|
+
resp = app.get(self.common_map_req)
|
|
1171
|
+
assert resp.content_type == "text/xml"
|
|
1172
|
+
xml = resp.lxml
|
|
1173
|
+
assert xml.xpath("/WMTException/@version")[0] == "1.0.0"
|
|
1174
|
+
assert xml.xpath("//WMTException/text()")[0].strip() == "unknown layer: invalid"
|
|
1175
|
+
|
|
1176
|
+
def test_invalid_format(self, app):
|
|
1177
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
1178
|
+
resp = app.get(self.common_map_req)
|
|
1179
|
+
assert resp.content_type == "text/xml"
|
|
1180
|
+
xml = resp.lxml
|
|
1181
|
+
assert xml.xpath("/WMTException/@version")[0] == "1.0.0"
|
|
1182
|
+
assert (
|
|
1183
|
+
xml.xpath("//WMTException/text()")[0].strip() ==
|
|
1184
|
+
"unsupported image format: ASCII"
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
def test_invalid_format_img_exception(self, app):
|
|
1188
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
1189
|
+
self.common_map_req.params["exceptions"] = "INIMAGE"
|
|
1190
|
+
resp = app.get(self.common_map_req)
|
|
1191
|
+
assert resp.content_type == "image/png"
|
|
1192
|
+
assert is_png(BytesIO(resp.body))
|
|
1193
|
+
|
|
1194
|
+
def test_missing_format_img_exception(self, app):
|
|
1195
|
+
del self.common_map_req.params["format"]
|
|
1196
|
+
self.common_map_req.params["exceptions"] = "INIMAGE"
|
|
1197
|
+
resp = app.get(self.common_map_req)
|
|
1198
|
+
assert resp.content_type == "image/png"
|
|
1199
|
+
assert is_png(BytesIO(resp.body))
|
|
1200
|
+
|
|
1201
|
+
def test_invalid_srs(self, app):
|
|
1202
|
+
self.common_map_req.params["srs"] = "EPSG:1234"
|
|
1203
|
+
print(self.common_map_req.complete_url)
|
|
1204
|
+
resp = app.get(self.common_map_req.complete_url)
|
|
1205
|
+
xml = resp.lxml
|
|
1206
|
+
assert xml.xpath("//WMTException/text()")[0].strip() == "unsupported srs: EPSG:1234"
|
|
1207
|
+
|
|
1208
|
+
def test_get_map_png(self, app, fixture_cache_data):
|
|
1209
|
+
resp = app.get(self.common_map_req)
|
|
1210
|
+
assert resp.content_type == "image/png"
|
|
1211
|
+
data = BytesIO(resp.body)
|
|
1212
|
+
assert is_png(data)
|
|
1213
|
+
assert Image.open(data).mode == "RGB"
|
|
1214
|
+
|
|
1215
|
+
def test_get_map_png_transparent_paletted(
|
|
1216
|
+
self, app, base_config, fixture_cache_data
|
|
1217
|
+
):
|
|
1218
|
+
try:
|
|
1219
|
+
base_config.image.paletted = True
|
|
1220
|
+
self.common_map_req.params["transparent"] = "True"
|
|
1221
|
+
resp = app.get(self.common_map_req)
|
|
1222
|
+
assert resp.content_type == "image/png"
|
|
1223
|
+
data = BytesIO(resp.body)
|
|
1224
|
+
assert is_png(data)
|
|
1225
|
+
assert Image.open(data).mode == "P"
|
|
1226
|
+
finally:
|
|
1227
|
+
base_config.image.paletted = False
|
|
1228
|
+
|
|
1229
|
+
def test_get_map_jpeg(self, app, fixture_cache_data):
|
|
1230
|
+
self.common_map_req.params["format"] = "image/jpeg"
|
|
1231
|
+
resp = app.get(self.common_map_req)
|
|
1232
|
+
assert resp.content_type == "image/jpeg"
|
|
1233
|
+
assert is_jpeg(BytesIO(resp.body))
|
|
1234
|
+
|
|
1235
|
+
def test_get_map_xml_exception(self, app):
|
|
1236
|
+
self.common_map_req.params["bbox"] = "0,0,90,90"
|
|
1237
|
+
resp = app.get(self.common_map_req)
|
|
1238
|
+
xml = resp.lxml
|
|
1239
|
+
assert "No response from URL" in xml.xpath("//WMTException/text()")[0]
|
|
1240
|
+
|
|
1241
|
+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
|
|
1242
|
+
def test_get_map(self, app, cache_dir):
|
|
1243
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
1244
|
+
expected_req = (
|
|
1245
|
+
{
|
|
1246
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
1247
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
1248
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
1249
|
+
"&WIDTH=256"
|
|
1250
|
+
},
|
|
1251
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
1252
|
+
)
|
|
1253
|
+
with mock_httpd(
|
|
1254
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
1255
|
+
):
|
|
1256
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
1257
|
+
resp = app.get(self.common_map_req)
|
|
1258
|
+
assert resp.content_type == "image/png"
|
|
1259
|
+
assert cache_dir.join(
|
|
1260
|
+
"wms_cache_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
1261
|
+
).check()
|
|
1262
|
+
|
|
1263
|
+
def test_get_featureinfo(self, app):
|
|
1264
|
+
expected_req = (
|
|
1265
|
+
{
|
|
1266
|
+
"path": r"/service?LAYERs=foo,bar&FORMAT=image%2FPNG" # TODO should be PNG only
|
|
1267
|
+
"&REQUEST=feature_info&HEIGHT=200&SRS=EPSG%3A900913"
|
|
1268
|
+
"&WMTVER=1.0.0&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
1269
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20"
|
|
1270
|
+
},
|
|
1271
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
1272
|
+
)
|
|
1273
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
1274
|
+
resp = app.get(self.common_fi_req)
|
|
1275
|
+
assert resp.content_type == "text/plain"
|
|
1276
|
+
assert resp.body == b"info"
|
|
1277
|
+
|
|
1278
|
+
def test_get_featureinfo_not_queryable(self, app):
|
|
1279
|
+
self.common_fi_req.params["query_layers"] = "tms_cache"
|
|
1280
|
+
self.common_fi_req.params["exceptions"] = "application/vnd.ogc.se_xml"
|
|
1281
|
+
resp = app.get(self.common_fi_req)
|
|
1282
|
+
assert resp.content_type == "text/xml"
|
|
1283
|
+
xml = resp.lxml
|
|
1284
|
+
assert "tms_cache is not queryable" in xml.xpath("//WMTException/text()")[0]
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
ns130 = {
|
|
1288
|
+
"wms": "http://www.opengis.net/wms",
|
|
1289
|
+
"ogc": "http://www.opengis.net/ogc",
|
|
1290
|
+
"sld": "http://www.opengis.net/sld",
|
|
1291
|
+
"xlink": "http://www.w3.org/1999/xlink",
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
|
|
1295
|
+
def assert_xpath(xml, xpath, expected, namespaces=None):
|
|
1296
|
+
assert xml.xpath(xpath, namespaces=namespaces)[0] == expected
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
assert_xpath_wms130 = functools.partial(assert_xpath, namespaces=ns130)
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
class TestWMS130(SysTest):
|
|
1303
|
+
config_file = "layer.yaml"
|
|
1304
|
+
|
|
1305
|
+
def setup_method(self):
|
|
1306
|
+
self.common_req = WMS130MapRequest(
|
|
1307
|
+
url="/service?", param=dict(service="WMS", version="1.3.0")
|
|
1308
|
+
)
|
|
1309
|
+
self.common_map_req = WMS130MapRequest(
|
|
1310
|
+
url="/service?",
|
|
1311
|
+
param=dict(
|
|
1312
|
+
service="WMS",
|
|
1313
|
+
version="1.3.0",
|
|
1314
|
+
bbox="0,-180,80,0",
|
|
1315
|
+
width="200",
|
|
1316
|
+
height="200",
|
|
1317
|
+
layers="wms_cache",
|
|
1318
|
+
crs="EPSG:4326",
|
|
1319
|
+
format="image/png",
|
|
1320
|
+
styles="",
|
|
1321
|
+
request="GetMap",
|
|
1322
|
+
),
|
|
1323
|
+
)
|
|
1324
|
+
self.common_fi_req = WMS130FeatureInfoRequest(
|
|
1325
|
+
url="/service?",
|
|
1326
|
+
param=dict(
|
|
1327
|
+
i="10",
|
|
1328
|
+
j="20",
|
|
1329
|
+
width="200",
|
|
1330
|
+
height="200",
|
|
1331
|
+
layers="wms_cache_130",
|
|
1332
|
+
format="image/png",
|
|
1333
|
+
query_layers="wms_cache_130",
|
|
1334
|
+
styles="",
|
|
1335
|
+
bbox="1000,400,2000,1400",
|
|
1336
|
+
crs="EPSG:900913",
|
|
1337
|
+
),
|
|
1338
|
+
)
|
|
1339
|
+
|
|
1340
|
+
def test_wms_capabilities(self, app):
|
|
1341
|
+
req = WMS130CapabilitiesRequest(url="/service?").copy_with_request_params(
|
|
1342
|
+
self.common_req
|
|
1343
|
+
)
|
|
1344
|
+
resp = app.get(req)
|
|
1345
|
+
assert resp.content_type == "text/xml"
|
|
1346
|
+
xml = resp.lxml
|
|
1347
|
+
assert_xpath_wms130(
|
|
1348
|
+
xml,
|
|
1349
|
+
"/wms:WMS_Capabilities/wms:Service/wms:Title/text()",
|
|
1350
|
+
u"MapProxy test fixture \u2603",
|
|
1351
|
+
)
|
|
1352
|
+
|
|
1353
|
+
# test for extended layer metadata
|
|
1354
|
+
assert_xpath_wms130(
|
|
1355
|
+
xml,
|
|
1356
|
+
"/wms:WMS_Capabilities/wms:Capability/wms:Layer/wms:Layer/wms:Attribution/wms:Title/text()",
|
|
1357
|
+
u"My attribution title",
|
|
1358
|
+
)
|
|
1359
|
+
|
|
1360
|
+
layer_names = set(
|
|
1361
|
+
xml.xpath("//wms:Layer/wms:Layer/wms:Name/text()", namespaces=ns130)
|
|
1362
|
+
)
|
|
1363
|
+
expected_names = set(
|
|
1364
|
+
[
|
|
1365
|
+
"direct_fwd_params",
|
|
1366
|
+
"direct",
|
|
1367
|
+
"wms_cache",
|
|
1368
|
+
"wms_cache_100",
|
|
1369
|
+
"wms_cache_130",
|
|
1370
|
+
"wms_cache_transparent",
|
|
1371
|
+
"wms_merge",
|
|
1372
|
+
"tms_cache",
|
|
1373
|
+
"tms_fi_cache",
|
|
1374
|
+
"wms_cache_multi",
|
|
1375
|
+
"wms_cache_link_single",
|
|
1376
|
+
"wms_cache_110",
|
|
1377
|
+
"watermark_cache",
|
|
1378
|
+
"wms_managed_cookies_cache",
|
|
1379
|
+
]
|
|
1380
|
+
)
|
|
1381
|
+
assert layer_names == expected_names
|
|
1382
|
+
assert is_130_capa(xml)
|
|
1383
|
+
|
|
1384
|
+
def test_invalid_layer(self, app):
|
|
1385
|
+
self.common_map_req.params["layers"] = "invalid"
|
|
1386
|
+
resp = app.get(self.common_map_req)
|
|
1387
|
+
assert resp.content_type == "text/xml"
|
|
1388
|
+
xml = resp.lxml
|
|
1389
|
+
assert_xpath_wms130(xml, "/ogc:ServiceExceptionReport/@version", "1.3.0")
|
|
1390
|
+
assert_xpath_wms130(
|
|
1391
|
+
xml,
|
|
1392
|
+
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code",
|
|
1393
|
+
"LayerNotDefined",
|
|
1394
|
+
)
|
|
1395
|
+
assert_xpath_wms130(xml, "//ogc:ServiceException/text()", "unknown layer: invalid")
|
|
1396
|
+
assert validate_with_xsd(xml, xsd_name="wms/1.3.0/exceptions_1_3_0.xsd")
|
|
1397
|
+
|
|
1398
|
+
def test_invalid_format(self, app):
|
|
1399
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
1400
|
+
resp = app.get(self.common_map_req)
|
|
1401
|
+
assert resp.content_type == "text/xml"
|
|
1402
|
+
xml = resp.lxml
|
|
1403
|
+
assert_xpath_wms130(xml, "/ogc:ServiceExceptionReport/@version", "1.3.0")
|
|
1404
|
+
assert_xpath_wms130(
|
|
1405
|
+
xml,
|
|
1406
|
+
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code",
|
|
1407
|
+
"InvalidFormat",
|
|
1408
|
+
)
|
|
1409
|
+
assert_xpath_wms130(
|
|
1410
|
+
xml,
|
|
1411
|
+
"//ogc:ServiceException/text()",
|
|
1412
|
+
"unsupported image format: image/ascii",
|
|
1413
|
+
)
|
|
1414
|
+
assert validate_with_xsd(xml, xsd_name="wms/1.3.0/exceptions_1_3_0.xsd")
|
|
1415
|
+
|
|
1416
|
+
def test_invalid_format_img_exception(self, app):
|
|
1417
|
+
self.common_map_req.params["format"] = "image/ascii"
|
|
1418
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
1419
|
+
resp = app.get(self.common_map_req)
|
|
1420
|
+
assert resp.content_type == "image/png"
|
|
1421
|
+
assert is_png(BytesIO(resp.body))
|
|
1422
|
+
|
|
1423
|
+
def test_missing_format_img_exception(self, app):
|
|
1424
|
+
del self.common_map_req.params["format"]
|
|
1425
|
+
self.common_map_req.params["exceptions"] = "application/vnd.ogc.se_inimage"
|
|
1426
|
+
resp = app.get(self.common_map_req)
|
|
1427
|
+
assert resp.content_type == "image/png"
|
|
1428
|
+
assert is_png(BytesIO(resp.body))
|
|
1429
|
+
|
|
1430
|
+
def test_invalid_srs(self, app):
|
|
1431
|
+
self.common_map_req.params["srs"] = "EPSG:1234"
|
|
1432
|
+
self.common_map_req.params["exceptions"] = "text/xml"
|
|
1433
|
+
|
|
1434
|
+
resp = app.get(self.common_map_req)
|
|
1435
|
+
assert resp.content_type == "text/xml"
|
|
1436
|
+
xml = resp.lxml
|
|
1437
|
+
assert_xpath_wms130(
|
|
1438
|
+
xml, "/ogc:ServiceExceptionReport/ogc:ServiceException/@code", "InvalidCRS"
|
|
1439
|
+
)
|
|
1440
|
+
assert_xpath_wms130(
|
|
1441
|
+
xml, "//ogc:ServiceException/text()", "unsupported crs: EPSG:1234"
|
|
1442
|
+
)
|
|
1443
|
+
assert validate_with_xsd(xml, xsd_name="wms/1.3.0/exceptions_1_3_0.xsd")
|
|
1444
|
+
|
|
1445
|
+
def test_get_map_png(self, app, fixture_cache_data):
|
|
1446
|
+
resp = app.get(self.common_map_req)
|
|
1447
|
+
assert resp.content_type == "image/png"
|
|
1448
|
+
data = BytesIO(resp.body)
|
|
1449
|
+
assert is_png(data)
|
|
1450
|
+
assert Image.open(data).mode == "RGB"
|
|
1451
|
+
|
|
1452
|
+
def test_get_map_jpeg(self, app, fixture_cache_data):
|
|
1453
|
+
self.common_map_req.params["format"] = "image/jpeg"
|
|
1454
|
+
resp = app.get(self.common_map_req)
|
|
1455
|
+
assert resp.content_type == "image/jpeg"
|
|
1456
|
+
assert is_jpeg(BytesIO(resp.body))
|
|
1457
|
+
|
|
1458
|
+
def test_get_map_xml_exception(self, app):
|
|
1459
|
+
self.common_map_req.params["bbox"] = "0,0,90,90"
|
|
1460
|
+
resp = app.get(self.common_map_req)
|
|
1461
|
+
assert resp.content_type == "text/xml"
|
|
1462
|
+
xml = resp.lxml
|
|
1463
|
+
assert (
|
|
1464
|
+
xml.xpath(
|
|
1465
|
+
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code",
|
|
1466
|
+
namespaces=ns130,
|
|
1467
|
+
) ==
|
|
1468
|
+
[]
|
|
1469
|
+
)
|
|
1470
|
+
assert (
|
|
1471
|
+
"No response from URL"
|
|
1472
|
+
in xml.xpath("//ogc:ServiceException/text()", namespaces=ns130)[0]
|
|
1473
|
+
)
|
|
1474
|
+
assert validate_with_xsd(xml, xsd_name="wms/1.3.0/exceptions_1_3_0.xsd")
|
|
1475
|
+
|
|
1476
|
+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
|
|
1477
|
+
def test_get_map(self, app, cache_dir):
|
|
1478
|
+
with tmp_image((256, 256), format="jpeg") as img:
|
|
1479
|
+
expected_req = (
|
|
1480
|
+
{
|
|
1481
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
1482
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
1483
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
1484
|
+
"&WIDTH=256"
|
|
1485
|
+
},
|
|
1486
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
1487
|
+
)
|
|
1488
|
+
with mock_httpd(
|
|
1489
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
1490
|
+
):
|
|
1491
|
+
self.common_map_req.params["bbox"] = "0,0,180,90" # internal axis-order
|
|
1492
|
+
resp = app.get(self.common_map_req)
|
|
1493
|
+
assert resp.content_type == "image/png"
|
|
1494
|
+
|
|
1495
|
+
assert cache_dir.join(
|
|
1496
|
+
"wms_cache_EPSG900913/01/000/000/001/000/000/001.jpeg"
|
|
1497
|
+
).check()
|
|
1498
|
+
|
|
1499
|
+
def test_get_featureinfo(self, app):
|
|
1500
|
+
expected_req = (
|
|
1501
|
+
{
|
|
1502
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
1503
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&CRS=EPSG%3A900913"
|
|
1504
|
+
"&VERSION=1.3.0&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
1505
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&I=10&J=20"
|
|
1506
|
+
},
|
|
1507
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
1508
|
+
)
|
|
1509
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
1510
|
+
resp = app.get(self.common_fi_req)
|
|
1511
|
+
assert resp.content_type == "text/plain"
|
|
1512
|
+
assert resp.body == b"info"
|
|
1513
|
+
|
|
1514
|
+
def test_get_featureinfo_111(self, app):
|
|
1515
|
+
expected_req = (
|
|
1516
|
+
{
|
|
1517
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fpng"
|
|
1518
|
+
"&REQUEST=GetFeatureInfo&HEIGHT=200&SRS=EPSG%3A900913"
|
|
1519
|
+
"&VERSION=1.1.1&BBOX=1000.0,400.0,2000.0,1400.0&styles="
|
|
1520
|
+
"&WIDTH=200&QUERY_LAYERS=foo,bar&X=10&Y=20"
|
|
1521
|
+
},
|
|
1522
|
+
{"body": b"info", "headers": {"content-type": "text/plain"}},
|
|
1523
|
+
)
|
|
1524
|
+
with mock_httpd(("localhost", 42423), [expected_req]):
|
|
1525
|
+
self.common_fi_req.params["layers"] = "wms_cache"
|
|
1526
|
+
self.common_fi_req.params["query_layers"] = "wms_cache"
|
|
1527
|
+
resp = app.get(self.common_fi_req)
|
|
1528
|
+
assert resp.content_type == "text/plain"
|
|
1529
|
+
assert resp.body == b"info"
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
@pytest.mark.skipif(sys.platform == "win32", reason="not supported on Windows")
|
|
1533
|
+
class TestWMSLinkSingleColorImages(SysTest):
|
|
1534
|
+
config_file = "layer.yaml"
|
|
1535
|
+
|
|
1536
|
+
def setup_method(self):
|
|
1537
|
+
self.common_map_req = WMS111MapRequest(
|
|
1538
|
+
url="/service?",
|
|
1539
|
+
param=dict(
|
|
1540
|
+
service="WMS",
|
|
1541
|
+
version="1.1.1",
|
|
1542
|
+
bbox="-180,0,0,80",
|
|
1543
|
+
width="200",
|
|
1544
|
+
height="200",
|
|
1545
|
+
layers="wms_cache_link_single",
|
|
1546
|
+
srs="EPSG:4326",
|
|
1547
|
+
format="image/jpeg",
|
|
1548
|
+
styles="",
|
|
1549
|
+
request="GetMap",
|
|
1550
|
+
),
|
|
1551
|
+
)
|
|
1552
|
+
|
|
1553
|
+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
|
|
1554
|
+
def test_get_map(self, app, cache_dir):
|
|
1555
|
+
link_name = "wms_cache_link_single_EPSG900913/01/000/000/001/000/000/001.png"
|
|
1556
|
+
real_name = "wms_cache_link_single_EPSG900913/single_color_tiles/fe00a0.png"
|
|
1557
|
+
with tmp_image((256, 256), format="jpeg", color="#fe00a0") as img:
|
|
1558
|
+
expected_req = (
|
|
1559
|
+
{
|
|
1560
|
+
"path": r"/service?LAYERs=foo,bar&SERVICE=WMS&FORMAT=image%2Fjpeg"
|
|
1561
|
+
"&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles="
|
|
1562
|
+
"&VERSION=1.1.1&BBOX=0.0,0.0,20037508.3428,20037508.3428"
|
|
1563
|
+
"&WIDTH=256"
|
|
1564
|
+
},
|
|
1565
|
+
{"body": img.read(), "headers": {"content-type": "image/jpeg"}},
|
|
1566
|
+
)
|
|
1567
|
+
with mock_httpd(
|
|
1568
|
+
("localhost", 42423), [expected_req], bbox_aware_query_comparator=True
|
|
1569
|
+
):
|
|
1570
|
+
self.common_map_req.params["bbox"] = "0,0,180,90"
|
|
1571
|
+
resp = app.get(self.common_map_req)
|
|
1572
|
+
assert resp.content_type == "image/jpeg"
|
|
1573
|
+
|
|
1574
|
+
single_loc = cache_dir.join(real_name)
|
|
1575
|
+
tile_loc = cache_dir.join(link_name)
|
|
1576
|
+
assert single_loc.check()
|
|
1577
|
+
assert tile_loc.check(link=True)
|
|
1578
|
+
|
|
1579
|
+
self.common_map_req.params["format"] = "image/png"
|
|
1580
|
+
resp = app.get(self.common_map_req)
|
|
1581
|
+
assert resp.content_type == "image/png"
|
|
1582
|
+
|
|
1583
|
+
|
|
1584
|
+
def assert_almost_equal_bbox(bbox1, bbox2, rel=0.01):
|
|
1585
|
+
assert bbox1 == pytest.approx(bbox2, rel=rel)
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
def is_100_capa(xml):
|
|
1589
|
+
return validate_with_dtd(xml, dtd_name="wms/1.0.0/capabilities_1_0_0.dtd")
|
|
1590
|
+
|
|
1591
|
+
|
|
1592
|
+
def is_110_capa(xml):
|
|
1593
|
+
return validate_with_dtd(xml, dtd_name="wms/1.1.0/capabilities_1_1_0.dtd")
|
|
1594
|
+
|
|
1595
|
+
|
|
1596
|
+
def is_111_exception(xml, msg=None, code=None, re_msg=None):
|
|
1597
|
+
assert xml.xpath("/ServiceExceptionReport/@version")[0] == "1.1.1"
|
|
1598
|
+
if msg:
|
|
1599
|
+
assert xml.xpath("//ServiceException/text()")[0] == msg
|
|
1600
|
+
if re_msg:
|
|
1601
|
+
exception_msg = xml.xpath("//ServiceException/text()")[0]
|
|
1602
|
+
assert re.findall(re_msg, exception_msg, re.I), "'%r' does not match '%s'" % (
|
|
1603
|
+
re_msg,
|
|
1604
|
+
exception_msg,
|
|
1605
|
+
)
|
|
1606
|
+
if code is not None:
|
|
1607
|
+
assert xml.xpath("/ServiceExceptionReport/ServiceException/@code")[0] == code
|
|
1608
|
+
assert validate_with_dtd(xml, "wms/1.1.1/exception_1_1_1.dtd")
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
def is_111_capa(xml):
|
|
1612
|
+
return validate_with_dtd(xml, dtd_name="wms/1.1.1/WMS_MS_Capabilities.dtd")
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
def is_130_capa(xml):
|
|
1616
|
+
return validate_with_xsd(xml, xsd_name="wms/1.3.0/capabilities_1_3_0.xsd")
|