Complete implementation of all modules: - constants.py: GIBS API endpoints, projections, TileMatrixSet defs - models.py: Pydantic models for layers, colormaps, geocoding - geo.py: Nominatim geocoding with rate limiting and caching - capabilities.py: WMTS GetCapabilities XML parser with search - colormaps.py: Colormap v1.3 parser with natural-language summaries - client.py: Async GIBS HTTP client wrapping all API interactions - server.py: FastMCP 3.0 tools, resources, and prompts 11 MCP tools, 3 resources, 2 prompts. 47 tests, all passing.
105 lines
3.9 KiB
Python
105 lines
3.9 KiB
Python
"""Tests for WMTS GetCapabilities XML parsing and layer search."""
|
|
|
|
from mcgibs.capabilities import parse_capabilities, search_layers
|
|
|
|
|
|
def test_parse_capabilities_layer_count(capabilities_xml: str):
|
|
"""parse_capabilities should return exactly 3 layers from the sample XML."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
assert len(layers) == 3
|
|
|
|
|
|
def test_parse_capabilities_true_color_layer(capabilities_xml: str):
|
|
"""MODIS true color layer should have correct title, formats, and tile matrix sets."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
layer = layers["MODIS_Terra_CorrectedReflectance_TrueColor"]
|
|
|
|
assert layer.title == "Corrected Reflectance (True Color, Terra/MODIS)"
|
|
assert layer.formats == ["image/jpeg"]
|
|
assert layer.tile_matrix_sets == ["250m"]
|
|
|
|
|
|
def test_parse_capabilities_time_dimension(capabilities_xml: str):
|
|
"""True color layer time dimension should have correct start, end, period, and default."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
layer = layers["MODIS_Terra_CorrectedReflectance_TrueColor"]
|
|
|
|
assert layer.time is not None
|
|
assert layer.time.start == "2000-02-24"
|
|
assert layer.time.end == "2025-12-01"
|
|
assert layer.time.period == "P1D"
|
|
assert layer.time.default == "2025-12-01"
|
|
|
|
|
|
def test_parse_capabilities_bbox(capabilities_xml: str):
|
|
"""All sample layers have a global bounding box of -180,-90 to 180,90."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
layer = layers["MODIS_Terra_CorrectedReflectance_TrueColor"]
|
|
|
|
assert layer.bbox is not None
|
|
assert layer.bbox.west == -180.0
|
|
assert layer.bbox.south == -90.0
|
|
assert layer.bbox.east == 180.0
|
|
assert layer.bbox.north == 90.0
|
|
|
|
|
|
def test_parse_capabilities_colormap_detection(capabilities_xml: str):
|
|
"""AMSR2 layer should have a colormap; true color layer should not."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
|
|
amsr2 = layers["AMSR2_Sea_Ice_Concentration_12km_Monthly"]
|
|
assert amsr2.has_colormap is True
|
|
|
|
true_color = layers["MODIS_Terra_CorrectedReflectance_TrueColor"]
|
|
assert true_color.has_colormap is False
|
|
|
|
|
|
def test_parse_capabilities_legend_url(capabilities_xml: str):
|
|
"""AMSR2 layer should have a legend URL pointing to the PNG legend image."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
amsr2 = layers["AMSR2_Sea_Ice_Concentration_12km_Monthly"]
|
|
|
|
assert amsr2.legend_url == (
|
|
"https://gibs.earthdata.nasa.gov/legends/AMSR2_Sea_Ice_Concentration_12km.png"
|
|
)
|
|
|
|
|
|
def test_search_layers_keyword(capabilities_xml: str):
|
|
"""Searching for 'sea ice' should return the AMSR2 sea ice layer."""
|
|
index = parse_capabilities(capabilities_xml)
|
|
results = search_layers(index, "sea ice")
|
|
|
|
assert len(results) >= 1
|
|
identifiers = [r.identifier for r in results]
|
|
assert "AMSR2_Sea_Ice_Concentration_12km_Monthly" in identifiers
|
|
|
|
|
|
def test_search_layers_no_results(capabilities_xml: str):
|
|
"""Searching for a nonexistent term should return an empty list."""
|
|
index = parse_capabilities(capabilities_xml)
|
|
results = search_layers(index, "nonexistent")
|
|
|
|
assert results == []
|
|
|
|
|
|
def test_search_layers_limit(capabilities_xml: str):
|
|
"""Search with limit=1 should return at most 1 result."""
|
|
index = parse_capabilities(capabilities_xml)
|
|
# Use a broad query that could match multiple layers
|
|
results = search_layers(index, "temperature", limit=1)
|
|
|
|
assert len(results) <= 1
|
|
|
|
|
|
def test_parse_capabilities_resource_url(capabilities_xml: str):
|
|
"""True color layer should have the expected ResourceURL template."""
|
|
layers = parse_capabilities(capabilities_xml)
|
|
layer = layers["MODIS_Terra_CorrectedReflectance_TrueColor"]
|
|
|
|
expected = (
|
|
"https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/"
|
|
"MODIS_Terra_CorrectedReflectance_TrueColor/default/"
|
|
"{Time}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpg"
|
|
)
|
|
assert layer.resource_url_template == expected
|