"""Tests for GIBSClient using respx mocks — no real HTTP calls.""" from io import BytesIO import httpx import respx from PIL import Image from mcgibs.client import GIBSClient from mcgibs.constants import WMTS_TILE_URL @respx.mock async def test_client_initialize(capabilities_xml): """Loading capabilities populates layer_index with all three sample layers.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) client = GIBSClient() await client.initialize() assert len(client.layer_index) == 3 assert "MODIS_Terra_CorrectedReflectance_TrueColor" in client.layer_index assert "AMSR2_Sea_Ice_Concentration_12km_Monthly" in client.layer_index assert "AIRS_L3_Surface_Air_Temperature_Daily_Day" in client.layer_index # Spot-check a parsed layer modis = client.layer_index["MODIS_Terra_CorrectedReflectance_TrueColor"] assert modis.title == "Corrected Reflectance (True Color, Terra/MODIS)" assert "image/jpeg" in modis.formats assert modis.time is not None assert modis.time.start == "2000-02-24" assert modis.has_colormap is False await client.close() @respx.mock async def test_client_fetch_layer_metadata(capabilities_xml, layer_metadata_json): """Fetching layer metadata enriches the layer with instrument/platform fields.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) layer_id = "MODIS_Terra_CorrectedReflectance_TrueColor" respx.get(url__regex=rf".*layer-metadata.*/{layer_id}\.json").mock( return_value=httpx.Response(200, text=layer_metadata_json) ) client = GIBSClient() await client.initialize() data = await client.fetch_layer_metadata(layer_id) assert data["instrument"] == "MODIS" assert data["platform"] == "Terra" assert data["ongoing"] is True # Verify the layer_index entry was enriched layer = client.get_layer(layer_id) assert layer is not None assert layer.instrument == "MODIS" assert layer.platform == "Terra" assert layer.measurement == "Corrected Reflectance" assert layer.day_night == "Day" # Second call should use cache data2 = await client.fetch_layer_metadata(layer_id) assert data2 is data await client.close() @respx.mock async def test_client_fetch_colormap(capabilities_xml, colormap_xml): """Parsing colormap XML produces entries and legend data.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) respx.get(url__regex=r".*colormaps/v1\.3/.*\.xml").mock( return_value=httpx.Response(200, text=colormap_xml) ) client = GIBSClient() await client.initialize() colormap_set = await client.fetch_colormap("AIRS_L3_Surface_Air_Temperature_Daily_Day") assert colormap_set is not None assert len(colormap_set.maps) == 2 data_map = colormap_set.data_map assert data_map is not None assert data_map.title == "Surface Air Temperature" assert data_map.units == "K" assert len(data_map.entries) == 14 assert data_map.legend_type == "continuous" # Verify the nodata map nodata_map = colormap_set.maps[1] assert any(e.nodata for e in nodata_map.entries) # Second fetch should be cached cached = await client.fetch_colormap("AIRS_L3_Surface_Air_Temperature_Daily_Day") assert cached is colormap_set await client.close() @respx.mock async def test_client_get_wms_image(capabilities_xml): """WMS GetMap returns raw image bytes when content-type is image/*.""" respx.get(url__regex=r".*WMTSCapabilities\.xml").mock( return_value=httpx.Response(200, text=capabilities_xml) ) # Build a tiny valid JPEG to return as the mock response buf = BytesIO() Image.new("RGB", (10, 10), "blue").save(buf, format="JPEG") fake_jpeg = buf.getvalue() respx.get(url__regex=r".*wms\.cgi.*").mock( return_value=httpx.Response( 200, content=fake_jpeg, headers={"content-type": "image/jpeg"}, ) ) client = GIBSClient() await client.initialize() from mcgibs.models import BBox bbox = BBox(west=-120.0, south=30.0, east=-110.0, north=40.0) result = await client.get_wms_image( "MODIS_Terra_CorrectedReflectance_TrueColor", "2025-06-01", bbox, ) assert isinstance(result, bytes) assert len(result) > 0 # Verify the returned bytes are valid JPEG (starts with FFD8) assert result[:2] == b"\xff\xd8" await client.close() def test_client_build_tile_url(): """build_tile_url produces the expected WMTS REST URL format.""" client = GIBSClient() url = client.build_tile_url( layer_id="MODIS_Terra_CorrectedReflectance_TrueColor", date="2025-06-01", zoom=3, row=2, col=4, tile_matrix_set="250m", ext="jpg", epsg="4326", ) assert "MODIS_Terra_CorrectedReflectance_TrueColor" in url assert "2025-06-01" in url assert "/250m/" in url assert "/3/" in url assert "/2/" in url assert "/4.jpg" in url assert "epsg4326" in url # Verify it matches the constant template expected = WMTS_TILE_URL.format( epsg="4326", layer_id="MODIS_Terra_CorrectedReflectance_TrueColor", date="2025-06-01", tile_matrix_set="250m", z=3, row=2, col=4, ext="jpg", ) assert url == expected