geoservercloud 0.8.2.dev2__tar.gz → 0.8.3.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/PKG-INFO +1 -1
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/config.py +2 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/example.config.yaml +4 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_None_expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language__expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_de_expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_fr_expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_None_expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language__expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_de_expected.png +0 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_fr_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/localized_labels.sld +4 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/test_installed_fonts.py +20 -0
- geoservercloud-0.8.3.dev2/geoserver_acceptance_tests/tests/test_ogcapi_features.py +401 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/restclient.py +1 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/pyproject.toml +1 -1
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_None_expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language__expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_de_expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_fr_expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_None_expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language__expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_de_expected.png +0 -0
- geoservercloud-0.8.2.dev2/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_fr_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/LICENSE +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/README.md +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/.gitignore +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/README.md +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/cli.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/compose/example.compose.yaml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/compose/geodatabase/001_create_schemas.sql +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/data/sampledata.tgz +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/conftest.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_it_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language__expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_it_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_None_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_it_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_None_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language__expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_it_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/localized_no_default.sld +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/i18n/localized_with_default.sld +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/wfs/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/wfs/wfs_delete_payload.xml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/wfs/wfs_insert_payload.xml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/wms/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/resources/wms/getmap_expected.png +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_cascaded_stores.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_cog.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_datastore.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_get_version.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_gwc.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_i18n.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_imagemosaic.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_imagemosaic_cog.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_wfs.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_wms.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_workspace.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/utils.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/geoservercloud.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/geoservercloudsync.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/gridsets/2056.xml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/gridsets/21781.xml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/gridsets/3857.xml +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/abstractlayer.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/common.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/coverage.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/coverages.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/coveragestore.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/datastore.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/datastores.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/featuretype.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/featuretypes.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/layer.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/layergroup.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/layergroups.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/resourcedirectory.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/style.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/styles.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/wmslayer.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/wmssettings.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/wmsstore.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/workspace.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/workspaces.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/__init__.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/owsservice.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/restlogger.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/restservice.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/templates.py +0 -0
- {geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/utils.py +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
<ogc:PropertyName>label_fr</ogc:PropertyName>
|
|
26
26
|
</ogc:Function>
|
|
27
27
|
</Label>
|
|
28
|
+
<Font>
|
|
29
|
+
<CssParameter name="font-family">DejaVu Sans</CssParameter>
|
|
30
|
+
<CssParameter name="font-size">10</CssParameter>
|
|
31
|
+
</Font>
|
|
28
32
|
<Fill>
|
|
29
33
|
<CssParameter name="fill">#000000</CssParameter>
|
|
30
34
|
</Fill>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from geoservercloud import GeoServerCloud
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_installed_fonts(config: dict, geoserver: GeoServerCloud):
|
|
7
|
+
"""Verify that custom fonts are installed in GeoServer."""
|
|
8
|
+
|
|
9
|
+
response = geoserver.rest_service.rest_client.get(
|
|
10
|
+
"/rest/fonts",
|
|
11
|
+
headers={"Accept": "application/json"},
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
assert response.status_code == 200
|
|
15
|
+
|
|
16
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
17
|
+
fonts = data.get("fonts", [])
|
|
18
|
+
|
|
19
|
+
for font in config["expected_fonts"]:
|
|
20
|
+
assert font in fonts, f"Expected font '{font}' not found in installed fonts"
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OGC API Features acceptance tests for GeoServer.
|
|
3
|
+
|
|
4
|
+
Tests verify compliance with OGC API Features Core specification:
|
|
5
|
+
- Collections endpoint (list all feature types)
|
|
6
|
+
- Single collection metadata
|
|
7
|
+
- Items endpoint (GeoJSON features)
|
|
8
|
+
- Pagination (limit parameter)
|
|
9
|
+
- Spatial filtering (bbox parameter)
|
|
10
|
+
- Queryables endpoint
|
|
11
|
+
- Landing page
|
|
12
|
+
- Conformance classes
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
from collections.abc import Generator
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
from sqlalchemy import Connection
|
|
20
|
+
from sqlalchemy.sql import text
|
|
21
|
+
|
|
22
|
+
from geoservercloud import GeoServerCloud
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.fixture()
|
|
26
|
+
def ogcapi_workspace() -> str:
|
|
27
|
+
"""Fixture to provide a dedicated workspace name for OGC API tests."""
|
|
28
|
+
return "ogcapi_test_workspace"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture()
|
|
32
|
+
def ogcapi_datastore() -> str:
|
|
33
|
+
"""Fixture to provide a dedicated datastore name for OGC API tests."""
|
|
34
|
+
return "ogcapi_test_datastore"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture()
|
|
38
|
+
def ogcapi_schema() -> str:
|
|
39
|
+
"""Fixture to provide a dedicated schema name for OGC API tests."""
|
|
40
|
+
return "test_ogcapi_features"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.fixture()
|
|
44
|
+
def geoserver_ogcapi_workspace(
|
|
45
|
+
config: dict,
|
|
46
|
+
geoserver: GeoServerCloud,
|
|
47
|
+
ogcapi_workspace: str,
|
|
48
|
+
ogcapi_datastore: str,
|
|
49
|
+
ogcapi_schema: str,
|
|
50
|
+
db_session: Connection,
|
|
51
|
+
) -> Generator[GeoServerCloud, None, None]:
|
|
52
|
+
"""Fixture to provide a dedicated workspace and PG datastore for OGC API tests."""
|
|
53
|
+
db_session.execute(text(f"CREATE SCHEMA IF NOT EXISTS {ogcapi_schema}"))
|
|
54
|
+
db_session.commit()
|
|
55
|
+
geoserver.create_workspace(ogcapi_workspace, set_default_workspace=True)
|
|
56
|
+
geoserver.create_pg_datastore(
|
|
57
|
+
workspace_name=ogcapi_workspace,
|
|
58
|
+
datastore_name=ogcapi_datastore,
|
|
59
|
+
pg_host=config["db"]["pg_host"]["docker"],
|
|
60
|
+
pg_port=config["db"]["pg_port"]["docker"],
|
|
61
|
+
pg_db=config["db"]["pg_db"],
|
|
62
|
+
pg_user=config["db"]["pg_user"],
|
|
63
|
+
pg_password=config["db"]["pg_password"],
|
|
64
|
+
pg_schema=ogcapi_schema,
|
|
65
|
+
set_default_datastore=True,
|
|
66
|
+
)
|
|
67
|
+
yield geoserver
|
|
68
|
+
geoserver.delete_workspace(ogcapi_workspace)
|
|
69
|
+
db_session.execute(text(f"DROP SCHEMA IF EXISTS {ogcapi_schema} CASCADE"))
|
|
70
|
+
db_session.commit()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_ogcapi_collections_list(
|
|
74
|
+
ogcapi_workspace: str, geoserver_ogcapi_workspace: GeoServerCloud
|
|
75
|
+
):
|
|
76
|
+
"""
|
|
77
|
+
Test OGC API Features collections endpoint lists all feature types.
|
|
78
|
+
|
|
79
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections
|
|
80
|
+
"""
|
|
81
|
+
# Use the existing workspace and datastore from the geoserver fixture
|
|
82
|
+
feature_type1 = "cities"
|
|
83
|
+
feature_type2 = "roads"
|
|
84
|
+
|
|
85
|
+
# Create two feature types using the existing datastore
|
|
86
|
+
attributes1 = {
|
|
87
|
+
"geom": {"type": "Point", "required": True},
|
|
88
|
+
"name": {"type": "string", "required": True},
|
|
89
|
+
"population": {"type": "integer", "required": False},
|
|
90
|
+
}
|
|
91
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
92
|
+
feature_type1, attributes=attributes1, epsg=2056
|
|
93
|
+
)
|
|
94
|
+
assert status == 201
|
|
95
|
+
|
|
96
|
+
attributes2 = {
|
|
97
|
+
"geom": {"type": "Line", "required": True},
|
|
98
|
+
"name": {"type": "string", "required": True},
|
|
99
|
+
}
|
|
100
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
101
|
+
feature_type2, attributes=attributes2, epsg=2056
|
|
102
|
+
)
|
|
103
|
+
assert status == 201
|
|
104
|
+
|
|
105
|
+
# Test OGC API Features collections endpoint
|
|
106
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
107
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections?f=application/json"
|
|
108
|
+
)
|
|
109
|
+
assert response.status_code == 200
|
|
110
|
+
|
|
111
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
112
|
+
assert "collections" in data
|
|
113
|
+
collections = data["collections"]
|
|
114
|
+
|
|
115
|
+
# Find our collections
|
|
116
|
+
collection_ids = [c["id"] for c in collections]
|
|
117
|
+
assert feature_type1 in collection_ids
|
|
118
|
+
assert feature_type2 in collection_ids
|
|
119
|
+
|
|
120
|
+
# Verify collection metadata
|
|
121
|
+
cities_collection = next(c for c in collections if c["id"] == feature_type1)
|
|
122
|
+
assert "title" in cities_collection # GeoServer may return "Default title"
|
|
123
|
+
assert "extent" in cities_collection
|
|
124
|
+
assert "spatial" in cities_collection["extent"]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_ogcapi_single_collection(
|
|
128
|
+
ogcapi_workspace: str, geoserver_ogcapi_workspace: GeoServerCloud
|
|
129
|
+
):
|
|
130
|
+
"""
|
|
131
|
+
Test OGC API Features single collection metadata endpoint.
|
|
132
|
+
|
|
133
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections/{collectionId}
|
|
134
|
+
"""
|
|
135
|
+
feature_type = "single"
|
|
136
|
+
attributes = {
|
|
137
|
+
"geom": {"type": "Point", "required": True},
|
|
138
|
+
"name": {"type": "string", "required": True},
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Create feature type using the existing datastore
|
|
142
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
143
|
+
feature_type, attributes=attributes, epsg=2056
|
|
144
|
+
)
|
|
145
|
+
assert status == 201
|
|
146
|
+
|
|
147
|
+
# Test single collection endpoint
|
|
148
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
149
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections/{ogcapi_workspace}:{feature_type}?f=application/json"
|
|
150
|
+
)
|
|
151
|
+
assert response.status_code == 200
|
|
152
|
+
|
|
153
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
154
|
+
assert data["id"] == feature_type
|
|
155
|
+
assert "title" in data # GeoServer may return "Default title"
|
|
156
|
+
assert "extent" in data
|
|
157
|
+
assert "links" in data
|
|
158
|
+
|
|
159
|
+
# Verify links include items endpoint
|
|
160
|
+
links = data["links"]
|
|
161
|
+
items_links = [link for link in links if link["rel"] == "items"]
|
|
162
|
+
assert len(items_links) > 0
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_ogcapi_items_geojson(
|
|
166
|
+
ogcapi_workspace: str,
|
|
167
|
+
db_session: Connection,
|
|
168
|
+
geoserver_ogcapi_workspace: GeoServerCloud,
|
|
169
|
+
ogcapi_schema: str,
|
|
170
|
+
):
|
|
171
|
+
"""
|
|
172
|
+
Test OGC API Features items endpoint returns features as GeoJSON.
|
|
173
|
+
|
|
174
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections/{collectionId}/items
|
|
175
|
+
"""
|
|
176
|
+
feature_type = "items"
|
|
177
|
+
attributes = {
|
|
178
|
+
"geom": {"type": "Point", "required": True},
|
|
179
|
+
"name": {"type": "string", "required": True},
|
|
180
|
+
"category": {"type": "string", "required": False},
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# Create feature type using the existing datastore
|
|
184
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
185
|
+
feature_type, attributes=attributes, epsg=2056
|
|
186
|
+
)
|
|
187
|
+
assert status == 201
|
|
188
|
+
|
|
189
|
+
# Insert test features (using EPSG:2056 coordinates)
|
|
190
|
+
db_session.execute(
|
|
191
|
+
text(
|
|
192
|
+
f"INSERT INTO {ogcapi_schema}.{feature_type} (geom, name, category) VALUES "
|
|
193
|
+
"(public.ST_SetSRID(public.ST_MakePoint(2600000, 1200000), 2056), 'City A', 'city'), "
|
|
194
|
+
"(public.ST_SetSRID(public.ST_MakePoint(2601000, 1201000), 2056), 'City B', 'city'), "
|
|
195
|
+
"(public.ST_SetSRID(public.ST_MakePoint(2602000, 1202000), 2056), 'City C', 'city')"
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
db_session.commit()
|
|
199
|
+
|
|
200
|
+
# Test items endpoint
|
|
201
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
202
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections/{ogcapi_workspace}:{feature_type}/items?f=application/geo%2Bjson"
|
|
203
|
+
)
|
|
204
|
+
assert response.status_code == 200
|
|
205
|
+
|
|
206
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
207
|
+
assert data["type"] == "FeatureCollection"
|
|
208
|
+
assert "features" in data
|
|
209
|
+
assert len(data["features"]) == 3
|
|
210
|
+
|
|
211
|
+
# Verify feature structure
|
|
212
|
+
feature = data["features"][0]
|
|
213
|
+
assert feature["type"] == "Feature"
|
|
214
|
+
assert "geometry" in feature
|
|
215
|
+
assert feature["geometry"]["type"] == "Point"
|
|
216
|
+
assert "properties" in feature
|
|
217
|
+
assert "name" in feature["properties"]
|
|
218
|
+
assert feature["properties"]["category"] == "city"
|
|
219
|
+
|
|
220
|
+
# Note: CRS is implicit in GeoJSON (defaults to WGS84/EPSG:4326)
|
|
221
|
+
# Modern GeoJSON spec doesn't require explicit CRS field
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_ogcapi_items_with_limit(
|
|
225
|
+
ogcapi_workspace: str,
|
|
226
|
+
db_session: Connection,
|
|
227
|
+
geoserver_ogcapi_workspace: GeoServerCloud,
|
|
228
|
+
ogcapi_schema: str,
|
|
229
|
+
):
|
|
230
|
+
"""
|
|
231
|
+
Test OGC API Features items endpoint with limit parameter.
|
|
232
|
+
|
|
233
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections/{collectionId}/items?limit={n}
|
|
234
|
+
"""
|
|
235
|
+
feature_type = "pagination_test"
|
|
236
|
+
attributes = {
|
|
237
|
+
"geom": {"type": "Point", "required": True},
|
|
238
|
+
"name": {"type": "string", "required": True},
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# Create feature type using the existing datastore
|
|
242
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
243
|
+
feature_type, attributes=attributes, epsg=2056
|
|
244
|
+
)
|
|
245
|
+
assert status == 201
|
|
246
|
+
|
|
247
|
+
# Insert 5 features
|
|
248
|
+
for i in range(5):
|
|
249
|
+
db_session.execute(
|
|
250
|
+
text(
|
|
251
|
+
f"INSERT INTO {ogcapi_schema}.{feature_type} (geom, name) VALUES "
|
|
252
|
+
f"(public.ST_SetSRID(public.ST_MakePoint({2600000 + i * 1000}, {1200000 + i * 1000}), 2056), 'Feature {i}')"
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
db_session.commit()
|
|
256
|
+
|
|
257
|
+
# Test with limit=2
|
|
258
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
259
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections/{ogcapi_workspace}:{feature_type}/items?f=application/geo%2Bjson&limit=2"
|
|
260
|
+
)
|
|
261
|
+
assert response.status_code == 200
|
|
262
|
+
|
|
263
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
264
|
+
assert data["type"] == "FeatureCollection"
|
|
265
|
+
assert len(data["features"]) == 2
|
|
266
|
+
|
|
267
|
+
# Verify pagination links exist
|
|
268
|
+
assert "links" in data
|
|
269
|
+
links = data["links"]
|
|
270
|
+
next_links = [link for link in links if link["rel"] == "next"]
|
|
271
|
+
assert len(next_links) > 0, "Should have a 'next' link for pagination"
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def test_ogcapi_items_with_bbox(
|
|
275
|
+
ogcapi_workspace: str,
|
|
276
|
+
db_session: Connection,
|
|
277
|
+
geoserver_ogcapi_workspace: GeoServerCloud,
|
|
278
|
+
ogcapi_schema: str,
|
|
279
|
+
):
|
|
280
|
+
"""
|
|
281
|
+
Test OGC API Features items endpoint with bbox filter.
|
|
282
|
+
|
|
283
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections/{collectionId}/items?bbox={bbox}
|
|
284
|
+
"""
|
|
285
|
+
feature_type = "bbox"
|
|
286
|
+
attributes = {
|
|
287
|
+
"geom": {"type": "Point", "required": True},
|
|
288
|
+
"name": {"type": "string", "required": True},
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# Create feature type using the existing datastore
|
|
292
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
293
|
+
feature_type, attributes=attributes, epsg=2056
|
|
294
|
+
)
|
|
295
|
+
assert status == 201
|
|
296
|
+
|
|
297
|
+
# Insert features in different locations
|
|
298
|
+
db_session.execute(
|
|
299
|
+
text(
|
|
300
|
+
f"INSERT INTO {ogcapi_schema}.{feature_type} (geom, name) VALUES "
|
|
301
|
+
"(public.ST_SetSRID(public.ST_MakePoint(2600000, 1200000), 2056), 'Inside'), "
|
|
302
|
+
"(public.ST_SetSRID(public.ST_MakePoint(2700000, 1300000), 2056), 'Outside')"
|
|
303
|
+
)
|
|
304
|
+
)
|
|
305
|
+
db_session.commit()
|
|
306
|
+
|
|
307
|
+
# Test with bbox that includes only the first point
|
|
308
|
+
# bbox format: minx,miny,maxx,maxy (in WGS84 coordinates)
|
|
309
|
+
# First point is at ~(7.4386, 46.9511), second at ~(8.7745, 47.8428)
|
|
310
|
+
bbox = "7.3,46.8,7.6,47.0" # Only includes first point in WGS84
|
|
311
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
312
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections/{ogcapi_workspace}:{feature_type}/items"
|
|
313
|
+
f"?f=application/geo%2Bjson&bbox={bbox}"
|
|
314
|
+
)
|
|
315
|
+
assert response.status_code == 200
|
|
316
|
+
|
|
317
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
318
|
+
assert data["type"] == "FeatureCollection"
|
|
319
|
+
assert len(data["features"]) == 1
|
|
320
|
+
assert data["features"][0]["properties"]["name"] == "Inside"
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def test_ogcapi_queryables(
|
|
324
|
+
ogcapi_workspace: str, geoserver_ogcapi_workspace: GeoServerCloud
|
|
325
|
+
):
|
|
326
|
+
"""
|
|
327
|
+
Test OGC API Features queryables endpoint.
|
|
328
|
+
|
|
329
|
+
Endpoint: GET /{workspace}/ogc/features/v1/collections/{collectionId}/queryables
|
|
330
|
+
"""
|
|
331
|
+
feature_type = "queryables"
|
|
332
|
+
attributes = {
|
|
333
|
+
"geom": {"type": "Point", "required": True},
|
|
334
|
+
"name": {"type": "string", "required": True},
|
|
335
|
+
"age": {"type": "integer", "required": False},
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
# Create feature type using the existing datastore
|
|
339
|
+
content, status = geoserver_ogcapi_workspace.create_feature_type(
|
|
340
|
+
feature_type, attributes=attributes, epsg=2056
|
|
341
|
+
)
|
|
342
|
+
assert status == 201
|
|
343
|
+
|
|
344
|
+
# Test queryables endpoint
|
|
345
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
346
|
+
f"/{ogcapi_workspace}/ogc/features/v1/collections/{ogcapi_workspace}:{feature_type}/queryables"
|
|
347
|
+
# f"?f=application/json"
|
|
348
|
+
)
|
|
349
|
+
assert response.status_code == 200
|
|
350
|
+
|
|
351
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
352
|
+
# Queryables should list the attributes that can be used in filtering
|
|
353
|
+
assert "properties" in data or "queryables" in data
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def test_ogcapi_landing_page(ogcapi_workspace: str, geoserver_ogcapi_workspace):
|
|
357
|
+
"""
|
|
358
|
+
Test OGC API Features landing page endpoint.
|
|
359
|
+
|
|
360
|
+
Endpoint: GET /{workspace}/ogc/features/v1
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
# Test landing page
|
|
364
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
365
|
+
f"/{ogcapi_workspace}/ogc/features/v1?f=application/json"
|
|
366
|
+
)
|
|
367
|
+
assert response.status_code == 200
|
|
368
|
+
|
|
369
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
370
|
+
assert "links" in data
|
|
371
|
+
|
|
372
|
+
# Verify conformance and collections links exist
|
|
373
|
+
links = data["links"]
|
|
374
|
+
conformance_links = [link for link in links if link["rel"] == "conformance"]
|
|
375
|
+
collections_links = [link for link in links if link["rel"] == "data"]
|
|
376
|
+
|
|
377
|
+
assert len(conformance_links) > 0, "Should have a conformance link"
|
|
378
|
+
assert len(collections_links) > 0, "Should have a collections (data) link"
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def test_ogcapi_conformance(ogcapi_workspace: str, geoserver_ogcapi_workspace):
|
|
382
|
+
"""
|
|
383
|
+
Test OGC API Features conformance endpoint.
|
|
384
|
+
|
|
385
|
+
Endpoint: GET /{workspace}/ogc/features/v1/conformance
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
# Test conformance endpoint
|
|
389
|
+
response = geoserver_ogcapi_workspace.rest_service.rest_client.get(
|
|
390
|
+
f"/{ogcapi_workspace}/ogc/features/v1/conformance?f=application/json"
|
|
391
|
+
)
|
|
392
|
+
assert response.status_code == 200
|
|
393
|
+
|
|
394
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
395
|
+
assert "conformsTo" in data
|
|
396
|
+
|
|
397
|
+
# Verify it conforms to OGC API Features Core
|
|
398
|
+
conformance_classes = data["conformsTo"]
|
|
399
|
+
assert any(
|
|
400
|
+
"ogcapi-features" in cc or "features/core" in cc for cc in conformance_classes
|
|
401
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "geoservercloud"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.3.dev2"
|
|
4
4
|
description = "Lightweight Python client to interact with GeoServer Cloud REST API, GeoServer ACL and OGC services"
|
|
5
5
|
authors = ["Camptocamp <info@camptocamp.com>"]
|
|
6
6
|
license = "BSD-2-Clause"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/.gitignore
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/README.md
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/__init__.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_cog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_gwc.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_wfs.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/test_wms.py
RENAMED
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoserver_acceptance_tests/tests/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/geoservercloudsync.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/abstractlayer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/coveragestore.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/featuretype.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/featuretypes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/layergroups.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/resourcedirectory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/models/wmssettings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/owsservice.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/restlogger.py
RENAMED
|
File without changes
|
{geoservercloud-0.8.2.dev2 → geoservercloud-0.8.3.dev2}/geoservercloud/services/restservice.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|