def test_update_valid(): """Should work as expected.""" runner = CliRunner() with runner.isolated_filesystem(): with open("mosaic.json", "w") as f: f.write( json.dumps( MosaicJSON.from_urls([asset1]).dict(exclude_none=True))) with open("./list.txt", "w") as f: f.write("\n".join([asset2])) result = runner.invoke( cogeo_cli, ["update", "list.txt", "mosaic.json", "--quiet"]) assert not result.exception assert result.exit_code == 0 with open("mosaic.json", "r") as f: updated_mosaic = json.load(f) updated_mosaic["version"] == "1.0.1" assert not mosaic_content.tiles == updated_mosaic["tiles"] with open("mosaic.json", "w") as f: f.write( json.dumps( MosaicJSON.from_urls([asset1]).dict(exclude_none=True))) result = runner.invoke( cogeo_cli, ["update", "list.txt", "mosaic.json", "--add-last", "--quiet"]) assert not result.exception assert result.exit_code == 0 with open("mosaic.json", "r") as f: updated_mosaic = json.load(f) updated_mosaic["version"] == "1.0.1" assert mosaic_content.tiles == updated_mosaic["tiles"]
def create( input_files, output, minzoom, maxzoom, quadkey_zoom, min_tile_cover, tile_cover_sort, threads, quiet, ): """Create mosaic definition file.""" input_files = input_files.read().splitlines() mosaicjson = MosaicJSON.from_urls( input_files, minzoom=minzoom, maxzoom=maxzoom, quadkey_zoom=quadkey_zoom, minimum_tile_cover=min_tile_cover, tile_cover_sort=tile_cover_sort, max_threads=threads, quiet=quiet, ) if output: with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic: mosaic.write() else: click.echo(json.dumps(mosaicjson.dict(exclude_none=True)))
def tmpmosaic(): """Create a Temporary MosaicJSON file.""" fileobj = tempfile.NamedTemporaryFile(suffix=".json.gz", delete=False) fileobj.close() mosaic_def = MosaicJSON.from_urls(assets) with FileBackend(fileobj.name, mosaic_def=mosaic_def) as mosaic: mosaic.write(overwrite=True) try: yield fileobj.name finally: os.remove(fileobj.name)
def create_mosaicjson(body: CreateMosaicJSON): """Create a MosaicJSON""" mosaic = MosaicJSON.from_urls( body.files, minzoom=body.minzoom, maxzoom=body.maxzoom, max_threads=body.max_threads, ) mosaic_path = MosaicPath(body.url) with MosaicBackend(mosaic_path, mosaic_def=mosaic) as mosaic: try: mosaic.write() except NotImplementedError: raise BadRequestError( f"{mosaic.__class__.__name__} does not support write operations" ) return mosaic.mosaic_def
def create(body: CreateMosaicJSON): """Create a MosaicJSON""" mosaic = MosaicJSON.from_urls( body.files, minzoom=body.minzoom, maxzoom=body.maxzoom, max_threads=body.max_threads, ) src_path = self.path_dependency(body.url) with self.reader( src_path.url, mosaic_def=mosaic, reader=self.dataset_reader ) as mosaic: try: mosaic.write() except NotImplementedError: raise BadRequestError( f"{mosaic.__class__.__name__} does not support write operations" ) return mosaic.mosaic_def
def create( input_files, output, minzoom, maxzoom, quadkey_zoom, min_tile_cover, tile_cover_sort, threads, name, description, attribution, quiet, ): """Create mosaic definition file.""" input_files = [file.strip() for file in input_files if file.strip()] mosaicjson = MosaicJSON.from_urls( input_files, minzoom=minzoom, maxzoom=maxzoom, quadkey_zoom=quadkey_zoom, minimum_tile_cover=min_tile_cover, tile_cover_sort=tile_cover_sort, max_threads=threads, quiet=quiet, ) if name: mosaicjson.name = name if description: mosaicjson.description = description if attribution: mosaicjson.attribution = attribution if output: with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic: mosaic.write(overwrite=True) else: click.echo(mosaicjson.json(exclude_none=True))
"""tests cogeo_mosaic.scripts.cli.""" import json import os import rasterio from click.testing import CliRunner from cogeo_mosaic.mosaic import MosaicJSON from cogeo_mosaic.scripts.cli import cogeo_cli asset1 = os.path.join(os.path.dirname(__file__), "fixtures", "cog1.tif") asset2 = os.path.join(os.path.dirname(__file__), "fixtures", "cog2.tif") assets = [asset1, asset2] mosaic_content = MosaicJSON.from_urls(assets) def test_create_valid(): """Should work as expected.""" runner = CliRunner() with runner.isolated_filesystem(): with open("./list.txt", "w") as f: f.write("\n".join(assets)) result = runner.invoke(cogeo_cli, ["create", "list.txt", "--quiet"]) assert not result.exception assert result.exit_code == 0 assert mosaic_content == MosaicJSON(**json.loads(result.output)) result = runner.invoke(cogeo_cli, ["create", "list.txt", "-o", "mosaic.json"])
def test_sqlite_backend(): """Test sqlite backend.""" with MosaicBackend(f"sqlite:///{mosaic_db}:test") as mosaic: assert mosaic._backend_name == "SQLite" assert isinstance(mosaic, SQLiteBackend) assert (mosaic.mosaicid == "f7fc24d47a79f1496dcdf9997de83e6305c252a931fba2c7d006b7d8") assert mosaic.quadkey_zoom == 7 info = mosaic.info() assert not info["quadkeys"] assert list(info.dict()) == [ "bounds", "center", "minzoom", "maxzoom", "name", "quadkeys", ] info = mosaic.info(quadkeys=True) assert info["quadkeys"] assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [ "mosaicjson", "name", "version", "minzoom", "maxzoom", "quadkey_zoom", "bounds", "center", ] assert mosaic.assets_for_tile(150, 182, 9) == ["cog1.tif", "cog2.tif"] assert mosaic.assets_for_point(-73, 45) == ["cog1.tif", "cog2.tif"] assert len(mosaic.get_assets(150, 182, 9)) == 2 assert len(mosaic.get_assets(147, 182, 12)) == 0 # Validation error, mosaic_def is empty with pytest.raises(ValidationError): with MosaicBackend("sqlite:///:memory::test", mosaic_def={}): pass # invalid scheme `sqlit://` with pytest.raises(ValueError): with SQLiteBackend("sqlit:///:memory::test"): pass # `:` is an invalid character for mosaic name with pytest.raises(ValueError): with SQLiteBackend("sqlite:///:memory::test:"): pass # `mosaicjson_metadata` is a reserved mosaic name with pytest.raises(AssertionError): with MosaicBackend("sqlite:///:memory::mosaicjson_metadata"): pass # Warns when changing name with pytest.warns(UserWarning): with MosaicBackend(mosaic_gz) as m: with MosaicBackend("sqlite:///:memory::test", mosaic_def=m.mosaic_def) as d: assert d.mosaic_def.name == "test" # need to set overwrite when mosaic already exists with MosaicBackend("sqlite:///:memory::test", mosaic_def=mosaic_content) as mosaic: mosaic.write() with pytest.raises(MosaicExistsError): mosaic.write() mosaic.write(overwrite=True) # files doesn't exists with pytest.raises(MosaicNotFoundError): with MosaicBackend("sqlite:///test.db:test2") as mosaic: pass # mosaic doesn't exists in DB with pytest.raises(MosaicNotFoundError): with MosaicBackend(f"sqlite:///{mosaic_db}:test2") as mosaic: pass # Test with `.` in mosaic name with pytest.warns(UserWarning): with MosaicBackend("sqlite:///:memory::test.mosaic", mosaic_def=mosaic_content) as m: m.write() assert m._mosaic_exists() assert m.mosaic_def.name == "test.mosaic" m.delete() assert not m._mosaic_exists() assert not m._fetch_metadata() mosaic_oneasset = MosaicJSON.from_urls([asset1], quiet=True) features = get_footprints([asset2], quiet=True) # Test update methods with MosaicBackend("sqlite:///:memory::test", mosaic_def=mosaic_oneasset) as m: m.write() meta = m.metadata assert len(m.get_assets(150, 182, 9)) == 1 m.update(features) assert not m.metadata == meta assets = m.get_assets(150, 182, 9) assert len(assets) == 2 assert assets[0] == asset2 assert assets[1] == asset1 # Test update with `add_first=False` with MosaicBackend("sqlite:///:memory::test2", mosaic_def=mosaic_oneasset) as m: m.write() meta = m.metadata assert len(m.get_assets(150, 182, 9)) == 1 m.update(features, add_first=False) assert not m.metadata == meta assets = m.get_assets(150, 182, 9) assert len(assets) == 2 assert assets[0] == asset1 assert assets[1] == asset2 assert SQLiteBackend.list_mosaics_in_db(mosaic_db) == ["test"] assert SQLiteBackend.list_mosaics_in_db(f"sqlite:///{mosaic_db}") == [ "test" ] with pytest.raises(ValueError): assert SQLiteBackend.list_mosaics_in_db("test.db")
def test_BaseReader(): """Test BaseReader heritance methods.""" assets = [asset1, asset2] mosaicdef = MosaicJSON.from_urls(assets, quiet=False) # add some offset to the center to make # sure BaseBackend forward center from the mosaic definition mosaicdef.center = [x + 1 for x in mosaicdef.center] with MosaicBackend(None, mosaic_def=mosaicdef) as mosaic: (t, _), assets_used = mosaic.tile(150, 182, 9) assert t.shape (tR, _), assets_usedR = mosaic.tile(150, 182, 9, reverse=True) assert tR.shape assert not numpy.array_equal(t, tR) assert assets_used[0] == assets_usedR[-1] with pytest.raises(NoAssetFoundError): mosaic.tile(200, 182, 9) pts = mosaic.point(-73, 45) assert len(pts) == 2 assert pts[0]["asset"] assert pts[1]["values"] ptsR = mosaic.point(-73, 45, reverse=True) assert len(ptsR) == 2 assert ptsR[0]["asset"] == pts[-1]["asset"] pts = mosaic.point(-72.5, 46) assert len(pts) == 1 with pytest.raises(NoAssetFoundError): mosaic.point(-60, 45) assert mosaic.minzoom assert mosaic.maxzoom assert mosaic.bounds assert mosaic.center == mosaicdef.center with pytest.raises(NotImplementedError): mosaic.stats() with pytest.raises(NotImplementedError): mosaic.preview() with pytest.raises(NotImplementedError): mosaic.part() info = mosaic.info() assert list(info.dict()) == [ "bounds", "center", "minzoom", "maxzoom", "name", "quadkeys", ] assert mosaic.spatial_info
def test_mosaic_create(): """Fetch info from dataset and create the mosaicJSON definition.""" assets = [asset1, asset2] mosaic = MosaicJSON.from_urls(assets, quiet=False) assert [round(b, 3) for b in list(mosaic.bounds)] == [ round(b, 3) for b in mosaic_content["bounds"] ] assert mosaic.maxzoom == mosaic_content["maxzoom"] assert mosaic.minzoom == mosaic_content["minzoom"] assert list(mosaic.tiles.keys()) == list(mosaic_content["tiles"].keys()) assert mosaic.tiles == mosaic_content["tiles"] mosaic = MosaicJSON.from_urls(assets, minzoom=7, maxzoom=9) assert [round(b, 3) for b in list(mosaic.bounds)] == [ round(b, 3) for b in mosaic_content["bounds"] ] assert mosaic.maxzoom == mosaic_content["maxzoom"] assert mosaic.minzoom == mosaic_content["minzoom"] assert list(mosaic.tiles.keys()) == list(mosaic_content["tiles"].keys()) # 5% tile cover filter mosaic = MosaicJSON.from_urls(assets, minimum_tile_cover=0.059) assert not list(mosaic.tiles.keys()) == list(mosaic_content["tiles"].keys()) # sort by tile cover mosaic = MosaicJSON.from_urls(assets, tile_cover_sort=True) assert list(mosaic.tiles.keys()) == list(mosaic_content["tiles"].keys()) assert not mosaic.tiles == mosaic_content["tiles"] assets = [asset1, asset2] mosaic = MosaicJSON.from_urls(assets) assert [round(b, 3) for b in list(mosaic.bounds)] == [ round(b, 3) for b in mosaic_content["bounds"] ] assert mosaic.maxzoom == mosaic_content["maxzoom"] with pytest.warns(None) as record: MosaicJSON.from_urls([asset1_small, asset2], minzoom=7, maxzoom=9) assert not len(record) # Multiple MaxZoom with pytest.warns(UserWarning): assets = [asset1_small, asset2] MosaicJSON.from_urls(assets) # Mixed datatype with pytest.raises(Exception): asset1_uint32 assets = [asset1_uint32, asset2] MosaicJSON.from_urls(assets) assets = [asset1, asset2] mosaic = MosaicJSON.from_urls(assets, asset_filter=_filter_and_sort, quiet=False) assert not mosaic.tiles == mosaic_content["tiles"]
def _create( body: str, minzoom: Union[str, int] = None, maxzoom: Union[str, int] = None, min_tile_cover: Union[str, float] = None, tile_cover_sort: Union[str, bool] = False, tile_format: str = None, tile_scale: Union[str, int] = 1, **kwargs: Any, ) -> Tuple[str, str, str]: minzoom = int(minzoom) if isinstance(minzoom, str) else minzoom maxzoom = int(maxzoom) if isinstance(maxzoom, str) else maxzoom min_tile_cover = ( float(min_tile_cover) if isinstance(min_tile_cover, str) else min_tile_cover ) mosaicid = get_hash( body=body, minzoom=minzoom, maxzoom=maxzoom, min_tile_cover=min_tile_cover, tile_cover_sort=tile_cover_sort, version=mosaic_version, ) try: with MosaicBackend(_create_mosaic_path(mosaicid), client=s3_client) as mosaic: meta = mosaic.metadata except: # noqa body = json.loads(body) with rasterio.Env(aws_session): mosaic_definition = MosaicJSON.from_urls( body, minzoom=minzoom, maxzoom=maxzoom, minimum_tile_cover=min_tile_cover, tile_cover_sort=tile_cover_sort, ) with MosaicBackend( _create_mosaic_path(mosaicid), mosaic_def=mosaic_definition, client=s3_client, ) as mosaic: mosaic.write() meta = mosaic.metadata if tile_format in ["pbf", "mvt"]: tile_url = f"{app.host}/{mosaicid}/{{z}}/{{x}}/{{y}}.{tile_format}" elif tile_format in ["png", "jpg", "webp", "tif", "npy"]: tile_url = ( f"{app.host}/{mosaicid}/{{z}}/{{x}}/{{y}}@{tile_scale}x.{tile_format}" ) else: tile_url = f"{app.host}/{mosaicid}/{{z}}/{{x}}/{{y}}@{tile_scale}x" qs = urllib.parse.urlencode(list(kwargs.items())) if qs: tile_url += f"?{qs}" meta = { "bounds": meta["bounds"], "center": meta["center"], "maxzoom": meta["maxzoom"], "minzoom": meta["minzoom"], "name": mosaicid, "tilejson": "2.1.0", "tiles": [tile_url], } return ("OK", "application/json", json.dumps(meta, separators=(",", ":")))
import base64 import json import os import re import urllib from typing import Any from unittest.mock import patch import pytest from cogeo_mosaic.backends.file import FileBackend from cogeo_mosaic.mosaic import MosaicJSON asset_above = os.path.join(os.path.dirname(__file__), "fixtures", "above_cog.tif") above_mosaic_content = MosaicJSON.from_urls([asset_above]) asset1 = os.path.join(os.path.dirname(__file__), "fixtures", "cog1.tif") asset2 = os.path.join(os.path.dirname(__file__), "fixtures", "cog2.tif") mosaic_content = MosaicJSON.from_urls([asset1, asset2]) mosaic_dict = mosaic_content.dict(exclude_none=True) request_json = os.path.join(os.path.dirname(__file__), "fixtures", "request.json") class MosaicMockReadRaise(FileBackend): """Mock.""" def __init__(self, *args, mosaic_def: MosaicJSON = None, **kwargs: Any): """Initialize FileBackend.""" assert args[0].startswith("s3://my-bucket")
def test_InMemoryReader(): """Test MemoryBackend.""" assets = [asset1, asset2] mosaicdef = MosaicJSON.from_urls(assets, quiet=False) with MosaicBackend(":memory:", mosaic_def=mosaicdef) as mosaic: assert isinstance(mosaic, MemoryBackend) assert mosaic.path == ":memory:" mosaic.write() mosaic._read() with MosaicBackend(None, mosaic_def=mosaicdef) as mosaic: assert isinstance(mosaic, MemoryBackend) assert mosaic.path == ":memory:" with MemoryBackend(mosaic_def=mosaicdef) as mosaic: (t, _), assets_used = mosaic.tile(150, 182, 9) assert t.shape (tR, _), assets_usedR = mosaic.tile(150, 182, 9, reverse=True) assert tR.shape assert not numpy.array_equal(t, tR) assert assets_used[0] == assets_usedR[-1] with pytest.raises(NoAssetFoundError): mosaic.tile(200, 182, 9) pts = mosaic.point(-73, 45) assert len(pts) == 2 assert pts[0][0].endswith(".tif") assert len(pts[0][1]) == 3 ptsR = mosaic.point(-73, 45, reverse=True) assert len(ptsR) == 2 assert ptsR[0][0] == pts[-1][0] pts = mosaic.point(-72.5, 46) assert len(pts) == 1 with pytest.raises(PointOutsideBounds): mosaic.point(-72.5, 46, allowed_exceptions=None) with pytest.raises(NoAssetFoundError): mosaic.point(-60, 45) assert mosaic.minzoom assert mosaic.maxzoom assert mosaic.bounds assert mosaic.center == mosaicdef.center with pytest.raises(NotImplementedError): mosaic.stats() with pytest.raises(NotImplementedError): mosaic.preview() with pytest.raises(NotImplementedError): mosaic.part() with pytest.raises(NotImplementedError): mosaic.feature() info = mosaic.info() assert list(info.dict()) == [ "bounds", "center", "minzoom", "maxzoom", "name", "quadkeys", ] assert mosaic.spatial_info mosaic_oneasset = MosaicJSON.from_urls([asset1], quiet=True) with MemoryBackend(mosaic_def=mosaic_oneasset) as mosaic: assert isinstance(mosaic, MemoryBackend) assert len(mosaic.get_assets(150, 182, 9)) == 1 features = get_footprints([asset2], quiet=True) mosaic.update(features) assets = mosaic.get_assets(150, 182, 9) assert len(assets) == 2 assert assets[0] == asset2 assert assets[1] == asset1
def test_file_backend(): """Test File backend.""" with MosaicBackend(mosaic_gz) as mosaic: assert mosaic._backend_name == "File" assert isinstance(mosaic, FileBackend) assert (mosaic.mosaicid == "24d43802c19ef67cc498c327b62514ecf70c2bbb1bbc243dda1ee075") assert mosaic.quadkey_zoom == 7 assert mosaic.minzoom == mosaic.mosaic_def.minzoom info = mosaic.info() assert not info["quadkeys"] assert list(info.dict()) == [ "bounds", "center", "minzoom", "maxzoom", "name", "quadkeys", ] info = mosaic.info(quadkeys=True) assert info["quadkeys"] assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [ "mosaicjson", "version", "minzoom", "maxzoom", "quadkey_zoom", "bounds", "center", ] assert mosaic.assets_for_tile(150, 182, 9) == ["cog1.tif", "cog2.tif"] assert mosaic.assets_for_point(-73, 45) == ["cog1.tif", "cog2.tif"] assert len(mosaic.get_assets(150, 182, 9)) == 2 assert len(mosaic.get_assets(147, 182, 12)) == 0 with MosaicBackend(mosaic_json) as mosaic: assert isinstance(mosaic, FileBackend) assert mosaic.quadkey_zoom == 7 with MosaicBackend(mosaic_jsonV1) as mosaic: assert isinstance(mosaic, FileBackend) assert mosaic.quadkey_zoom == 7 assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [ "mosaicjson", "version", "minzoom", "maxzoom", "bounds", "center", ] with pytest.raises(ValidationError): with MosaicBackend("afile.json", mosaic_def={}): pass runner = CliRunner() with runner.isolated_filesystem(): with MosaicBackend("mosaic.json", mosaic_def=mosaic_content) as mosaic: mosaic.write() assert mosaic.minzoom == mosaic_content["minzoom"] with open("mosaic.json") as f: m = json.loads(f.read()) assert m["quadkey_zoom"] == 7 with pytest.raises(MosaicExistsError): mosaic.write() mosaic.write(overwrite=True) with MosaicBackend("mosaic.json.gz", mosaic_def=mosaic_content) as mosaic: mosaic.write() with open("mosaic.json.gz", "rb") as f: m = json.loads(_decompress_gz(f.read())) assert m["quadkey_zoom"] == 7 mosaic_oneasset = MosaicJSON.from_urls([asset1], quiet=True) with MosaicBackend("umosaic.json.gz", mosaic_def=mosaic_oneasset) as mosaic: mosaic.write() assert len(mosaic.get_assets(150, 182, 9)) == 1 with MosaicBackend("umosaic.json.gz") as mosaic: features = get_footprints([asset2], quiet=True) mosaic.update(features) assets = mosaic.get_assets(150, 182, 9) assert len(assets) == 2 assert assets[0] == asset2 assert assets[1] == asset1
import base64 import json import os import re import urllib from typing import Any from unittest.mock import patch import pytest from cogeo_mosaic.backends.file import FileBackend from cogeo_mosaic.mosaic import MosaicJSON asset1 = os.path.join(os.path.dirname(__file__), "fixtures", "cog1.tif") asset2 = os.path.join(os.path.dirname(__file__), "fixtures", "cog2.tif") mosaic_content = MosaicJSON.from_urls([asset1, asset2]) mosaic_dict = mosaic_content.dict(exclude_none=True) request_json = os.path.join(os.path.dirname(__file__), "fixtures", "request.json") class MosaicMockReadRaise(FileBackend): """Mock.""" def __init__(self, *args, mosaic_def: MosaicJSON = None, **kwargs: Any): """Initialize FileBackend.""" assert args[0].startswith("s3://my-bucket") if mosaic_def is not None: self.mosaic_def = mosaic_def else: raise Exception("Nope Nope Nope")
"""tests cogeo_mosaic.overview.""" import json import os import rasterio from click.testing import CliRunner from rio_cogeo.profiles import cog_profiles from cogeo_mosaic.mosaic import MosaicJSON from cogeo_mosaic.overviews import create_low_level_cogs asset1 = os.path.join(os.path.dirname(__file__), "fixtures", "cog1.tif") asset2 = os.path.join(os.path.dirname(__file__), "fixtures", "cog2.tif") assets = [asset1, asset2] mosaic_content = MosaicJSON.from_urls(assets).dict(exclude_none=True) deflate_profile = cog_profiles.get("deflate") deflate_profile.update({"blockxsize": 256, "blockysize": 256}) def test_overview_valid(monkeypatch): """Should work as expected (create cogeo file).""" monkeypatch.setenv("GDAL_DISABLE_READDIR_ON_OPEN", "TRUE") monkeypatch.setenv("GDAL_TIFF_INTERNAL_MASK", "TRUE") monkeypatch.setenv("GDAL_TIFF_OVR_BLOCKSIZE", "128") runner = CliRunner() with runner.isolated_filesystem(): with open("mosaic.json", "w") as f: f.write(json.dumps(mosaic_content))
def test_MosaicTilerFactory(): """Test MosaicTilerFactory class.""" mosaic = MosaicTilerFactory( optional_headers=[ OptionalHeader.server_timing, OptionalHeader.x_assets ], router_prefix="mosaic", ) assert len(mosaic.router.routes) == 19 assert mosaic.tms_dependency == WebMercatorTMSParams app = FastAPI() app.include_router(mosaic.router, prefix="/mosaic") client = TestClient(app) with tmpmosaic() as mosaic_file: response = client.get( "/mosaic/", params={"url": mosaic_file}, ) assert response.status_code == 200 assert response.json()["mosaicjson"] response = client.get( "/mosaic", params={"url": mosaic_file}, ) assert response.status_code == 200 assert response.json()["mosaicjson"] response = client.get( "/mosaic/bounds", params={"url": mosaic_file}, ) assert response.status_code == 200 assert response.json()["bounds"] response = client.get( "/mosaic/info", params={"url": mosaic_file}, ) assert response.status_code == 200 assert response.json()["bounds"] response = client.get( "/mosaic/info.geojson", params={"url": mosaic_file}, ) assert response.status_code == 200 assert response.headers["content-type"] == "application/geo+json" assert response.json()["type"] == "Feature" response = client.get( "/mosaic/point/-74.53125,45.9956935", params={"url": mosaic_file}, ) assert response.status_code == 200 timing = response.headers["server-timing"] assert "mosaicread;dur" in timing assert "dataread;dur" in timing response = client.get("/mosaic/tiles/7/37/45", params={"url": mosaic_file}) assert response.status_code == 200 assert response.headers["X-Assets"] timing = response.headers["server-timing"] assert "mosaicread;dur" in timing assert "dataread;dur" in timing assert "postprocess;dur" in timing assert "format;dur" in timing response = client.get( "/mosaic/tilejson.json", params={ "url": mosaic_file, "tile_format": "png", "minzoom": 6, "maxzoom": 9, }, ) assert response.status_code == 200 body = response.json() assert ( "http://testserver/mosaic/tiles/WebMercatorQuad/{z}/{x}/{y}@1x.png?url=" in body["tiles"][0]) assert body["minzoom"] == 6 assert body["maxzoom"] == 9 response = client.get( "/mosaic/tilejson.json", params={ "url": mosaic_file, "tile_format": "png", "minzoom": 6, "maxzoom": 9, "TileMatrixSetId": "WebMercatorQuad", }, ) assert response.status_code == 200 body = response.json() assert ( "http://testserver/mosaic/tiles/WebMercatorQuad/{z}/{x}/{y}@1x.png?url=" in body["tiles"][0]) assert body["minzoom"] == 6 assert body["maxzoom"] == 9 assert "TileMatrixSetId" not in body["tiles"][0] response = client.get( "/mosaic/WMTSCapabilities.xml", params={ "url": mosaic_file, "tile_format": "png", "minzoom": 6, "maxzoom": 9, }, ) assert response.status_code == 200 assert response.headers["content-type"] == "application/xml" response = client.post( "/mosaic/validate", json=MosaicJSON.from_urls(assets).dict(), ) assert response.status_code == 200