diff --git a/geoserver_acceptance_tests/tests/test_ogcapi_features.py b/geoserver_acceptance_tests/tests/test_ogcapi_features.py
index 6353d01..3e9b55c 100644
--- a/geoserver_acceptance_tests/tests/test_ogcapi_features.py
+++ b/geoserver_acceptance_tests/tests/test_ogcapi_features.py
@@ -14,6 +14,7 @@
import json
from collections.abc import Generator
+from xml.etree import ElementTree
import pytest
from sqlalchemy import Connection
@@ -21,6 +22,37 @@
from geoservercloud import GeoServerCloud
+WFS_SETTINGS_PATH = "/rest/services/wfs/settings"
+
+PROPERTY_SELECTION_CONFORMANCE = (
+ "http://www.opengis.net/spec/ogcapi-features-6/1.0/conf/properties-features"
+)
+
+XML_HEADERS = {"Content-Type": "application/xml"}
+
+CONFORMANCE_SETTINGS = """
+
+
+
+
+ true
+ true
+
+
+
+
+"""
+
+DEFAULT_CONFORMANCE_SETTINGS = """
+
+
+
+
+
+
+
+"""
+
@pytest.fixture()
def ogcapi_workspace() -> str:
@@ -399,3 +431,88 @@ def test_ogcapi_conformance(ogcapi_workspace: str, geoserver_ogcapi_workspace):
assert any(
"ogcapi-features" in cc or "features/core" in cc for cc in conformance_classes
)
+
+
+@pytest.fixture()
+def wfs_ogcapi_conformance(geoserver: GeoServerCloud) -> Generator[None, None, None]:
+ """Leaves the OGC API Features conformance settings back at their defaults."""
+ yield
+ geoserver.rest_service.rest_client.put(
+ f"{WFS_SETTINGS_PATH}.xml",
+ headers=XML_HEADERS,
+ data=DEFAULT_CONFORMANCE_SETTINGS,
+ )
+
+
+def read_conformance_settings(geoserver: GeoServerCloud) -> ElementTree.Element:
+ """
+ Returns the ogcapiFeatures conformance element of the WFS settings, failing if
+ the REST API answered with the object rendered as a string instead.
+ """
+ response = geoserver.rest_service.rest_client.get(f"{WFS_SETTINGS_PATH}.xml")
+ assert response.status_code == 200
+
+ settings = ElementTree.fromstring(response.content)
+ entry = settings.find("./metadata/entry[@key='ogcapiFeatures']")
+ assert entry is not None, "the ogcapiFeatures metadata entry is missing"
+ assert not (entry.text or "").strip(), (
+ "the conformance object was stored as a string instead of an object: "
+ f"{entry.text!r}"
+ )
+
+ conformance = entry.find("ogcapiFeatures")
+ assert conformance is not None, "the ogcapiFeatures metadata entry has no object"
+ return conformance
+
+
+def test_wfs_settings_rest_roundtrip_preserves_ogcapi_conformance(
+ geoserver: GeoServerCloud, wfs_ogcapi_conformance: None
+):
+ """
+ Reading the WFS settings and writing the same document back must not replace the OGC API Features conformance
+ object with the string returned by its toString(), which later breaks the service with a ClassCastException.
+
+ See https://github.com/geoserver/geoserver-cloud/issues/872
+ """
+ geoserver.rest_service.rest_client.put(
+ f"{WFS_SETTINGS_PATH}.xml", headers=XML_HEADERS, data=CONFORMANCE_SETTINGS
+ )
+
+ conformance = read_conformance_settings(geoserver)
+ assert conformance.findtext("core") == "true"
+ assert conformance.findtext("propertySelection") == "true"
+
+ # the round trip from the issue: read the settings and write them back unchanged
+ settings = geoserver.rest_service.rest_client.get(f"{WFS_SETTINGS_PATH}.xml")
+ geoserver.rest_service.rest_client.put(
+ f"{WFS_SETTINGS_PATH}.xml", headers=XML_HEADERS, data=settings.content
+ )
+
+ conformance = read_conformance_settings(geoserver)
+ assert conformance.findtext("core") == "true"
+ assert conformance.findtext("propertySelection") == "true"
+
+
+def test_ogcapi_conformance_after_wfs_settings_rest_roundtrip(
+ geoserver: GeoServerCloud, wfs_ogcapi_conformance: None
+):
+ """
+ The OGC API Features service must still answer after the WFS settings went through a REST round trip.
+
+ See https://github.com/geoserver/geoserver-cloud/issues/872
+ """
+ geoserver.rest_service.rest_client.put(
+ f"{WFS_SETTINGS_PATH}.xml", headers=XML_HEADERS, data=CONFORMANCE_SETTINGS
+ )
+ settings = geoserver.rest_service.rest_client.get(f"{WFS_SETTINGS_PATH}.xml")
+ geoserver.rest_service.rest_client.put(
+ f"{WFS_SETTINGS_PATH}.xml", headers=XML_HEADERS, data=settings.content
+ )
+
+ response = geoserver.rest_service.rest_client.get(
+ "/ogc/features/v1/conformance", params={"f": "application/json"}
+ )
+ assert response.status_code == 200
+
+ conformance_classes = json.loads(response.content.decode("utf-8"))["conformsTo"]
+ assert PROPERTY_SELECTION_CONFORMANCE in conformance_classes