From d0abe847434a318f4eebb8cd2a685fd940da49d7 Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:24:02 -0700 Subject: [PATCH] Fix OGC feature drilldown provider filtering Skip tile and other non-feature collections before requesting collection items. Add a regression covering the mixed-provider response reported in #515. --- GeoHealthCheck/plugins/probe/ogcfeat.py | 13 ++++++- tests/test_ogcfeat.py | 48 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/test_ogcfeat.py diff --git a/GeoHealthCheck/plugins/probe/ogcfeat.py b/GeoHealthCheck/plugins/probe/ogcfeat.py index 05005bae..dd38a519 100644 --- a/GeoHealthCheck/plugins/probe/ogcfeat.py +++ b/GeoHealthCheck/plugins/probe/ogcfeat.py @@ -59,6 +59,15 @@ def set_accept_header(oa_feat, content_type): oa_feat.headers['Accept'] = content_type +def supports_feature_items(collection): + item_type = collection.get('itemType') + if item_type is not None: + return item_type == 'feature' + + return any(link.get('rel') == 'items' + for link in collection.get('links', [])) + + class OGCFeatDrilldown(Probe): """ Probe for OGC API Features (OAFeat) endpoint "drilldown" or @@ -173,7 +182,9 @@ def perform_request(self): try: for collection in collections: coll_id = collection['id'] - coll_id = coll_id + + if not supports_feature_items(collection): + continue try: set_accept_header(oa_feat, type_for_link( diff --git a/tests/test_ogcfeat.py b/tests/test_ogcfeat.py new file mode 100644 index 00000000..a3dc1ef9 --- /dev/null +++ b/tests/test_ogcfeat.py @@ -0,0 +1,48 @@ +from types import SimpleNamespace +from unittest.mock import Mock, patch + +from GeoHealthCheck.plugins.probe.ogcfeat import OGCFeatDrilldown +from GeoHealthCheck.result import ProbeResult + + +def test_full_drilldown_skips_non_feature_collections(): + features = Mock() + features.headers = {} + features.links = [ + {'rel': 'conformance', 'type': 'application/json'}, + {'rel': 'data', 'type': 'application/json'}, + {'rel': 'service-desc', 'type': 'application/json'}, + ] + features.conformance.return_value = {} + features.collections.return_value = { + 'collections': [ + { + 'id': 'lakes', + 'itemType': 'tile', + 'links': [ + {'rel': 'self', 'type': 'application/json'}, + {'rel': 'items', 'type': 'application/geo+json'}, + ], + } + ] + } + features.api.return_value = { + 'components': {}, + 'paths': {}, + 'openapi': '3.0.0', + } + + probe = object.__new__(OGCFeatDrilldown) + probe._resource = SimpleNamespace(url='https://example.test') + probe._parameters = {'drilldown_level': 'full'} + probe.result = ProbeResult(probe, {}) + probe.get_request_headers = lambda: {'Accept': 'application/json'} + + with patch( + 'GeoHealthCheck.plugins.probe.ogcfeat.Features', + return_value=features): + probe.perform_request() + + features.collection.assert_not_called() + features.collection_items.assert_not_called() + assert probe.result.success