geoservercloud 0.8.10.dev6__tar.gz → 0.8.11.dev1__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.
Files changed (97) hide show
  1. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/PKG-INFO +1 -1
  2. geoservercloud-0.8.11.dev1/geoserver_acceptance_tests/tests/test_gwc.py +295 -0
  3. geoservercloud-0.8.11.dev1/geoserver_acceptance_tests/tests/test_rest_resource.py +110 -0
  4. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/pyproject.toml +1 -1
  5. geoservercloud-0.8.10.dev6/geoserver_acceptance_tests/tests/test_gwc.py +0 -45
  6. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/LICENSE +0 -0
  7. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/README.md +0 -0
  8. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/.gitignore +0 -0
  9. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/README.md +0 -0
  10. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/__init__.py +0 -0
  11. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/ci.config.yaml +0 -0
  12. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/cli.py +0 -0
  13. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/compose/ci.compose.yaml +0 -0
  14. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/compose/example.compose.yaml +0 -0
  15. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/compose/geodatabase/001_create_schemas.sql +0 -0
  16. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/config.py +0 -0
  17. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/data/sampledata.tgz +0 -0
  18. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/example.config.yaml +0 -0
  19. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/__init__.py +0 -0
  20. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/conftest.py +0 -0
  21. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/__init__.py +0 -0
  22. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/__init__.py +0 -0
  23. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_None_expected.png +0 -0
  24. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language__expected.png +0 -0
  25. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_de_expected.png +0 -0
  26. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_fr_expected.png +0 -0
  27. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_it_expected.png +0 -0
  28. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_None_expected.png +0 -0
  29. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language__expected.png +0 -0
  30. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_it_expected.png +0 -0
  31. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_None_expected.png +0 -0
  32. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language__expected.png +0 -0
  33. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_de_expected.png +0 -0
  34. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_fr_expected.png +0 -0
  35. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_it_expected.png +0 -0
  36. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_None_expected.png +0 -0
  37. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language__expected.png +0 -0
  38. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_it_expected.png +0 -0
  39. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/localized_labels.sld +0 -0
  40. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/localized_no_default.sld +0 -0
  41. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/i18n/localized_with_default.sld +0 -0
  42. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/wfs/__init__.py +0 -0
  43. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/wfs/wfs_delete_payload.xml +0 -0
  44. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/wfs/wfs_insert_payload.xml +0 -0
  45. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/wms/__init__.py +0 -0
  46. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/resources/wms/getmap_expected.png +0 -0
  47. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_cascaded_stores.py +0 -0
  48. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_cog.py +0 -0
  49. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_datastore.py +0 -0
  50. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_get_version.py +0 -0
  51. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_i18n.py +0 -0
  52. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_imagemosaic.py +0 -0
  53. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_imagemosaic_cog.py +0 -0
  54. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_installed_fonts.py +0 -0
  55. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_ogcapi_features.py +0 -0
  56. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_s3_credentials_chain.py +0 -0
  57. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_wfs.py +0 -0
  58. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_wms.py +0 -0
  59. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/test_workspace.py +0 -0
  60. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoserver_acceptance_tests/tests/utils.py +0 -0
  61. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/__init__.py +0 -0
  62. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/geoservercloud.py +0 -0
  63. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/geoservercloudsync.py +0 -0
  64. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/gridsets/2056.xml +0 -0
  65. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/gridsets/21781.xml +0 -0
  66. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/gridsets/3857.xml +0 -0
  67. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/__init__.py +0 -0
  68. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/abstractlayer.py +0 -0
  69. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/common.py +0 -0
  70. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/coverage.py +0 -0
  71. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/coverages.py +0 -0
  72. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/coveragestore.py +0 -0
  73. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/datastore.py +0 -0
  74. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/datastores.py +0 -0
  75. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/featuretype.py +0 -0
  76. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/featuretypes.py +0 -0
  77. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/gwclayer.py +0 -0
  78. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/layer.py +0 -0
  79. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/layergroup.py +0 -0
  80. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/layergroups.py +0 -0
  81. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/resourcedirectory.py +0 -0
  82. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/s3blobstore.py +0 -0
  83. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/style.py +0 -0
  84. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/styles.py +0 -0
  85. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/wmslayer.py +0 -0
  86. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/wmssettings.py +0 -0
  87. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/wmsstore.py +0 -0
  88. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/wmtsstore.py +0 -0
  89. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/workspace.py +0 -0
  90. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/models/workspaces.py +0 -0
  91. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/services/__init__.py +0 -0
  92. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/services/owsservice.py +0 -0
  93. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/services/restclient.py +0 -0
  94. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/services/restlogger.py +0 -0
  95. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/services/restservice.py +0 -0
  96. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/templates.py +0 -0
  97. {geoservercloud-0.8.10.dev6 → geoservercloud-0.8.11.dev1}/geoservercloud/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: geoservercloud
3
- Version: 0.8.10.dev6
3
+ Version: 0.8.11.dev1
4
4
  Summary: Lightweight Python client to interact with GeoServer Cloud REST API, GeoServer ACL and OGC services
5
5
  License: BSD-2-Clause
6
6
  Author: Camptocamp
@@ -0,0 +1,295 @@
1
+ import time
2
+
3
+ import pytest
4
+
5
+ from geoservercloud import GeoServerCloud
6
+
7
+
8
+ def test_tile_cache(geoserver_factory):
9
+ workspace = "test_gwc"
10
+ wmts_store = "test_gwc_store"
11
+ wmts_layer = "ch.swisstopo.swissimage"
12
+ geoserver: GeoServerCloud = geoserver_factory(workspace)
13
+
14
+ content, status = geoserver.create_wmts_store(
15
+ workspace,
16
+ wmts_store,
17
+ capabilities="https://wmts.geo.admin.ch/EPSG/4326/1.0.0/WMTSCapabilities.xml",
18
+ )
19
+ assert status == 201
20
+ assert content == wmts_store
21
+
22
+ content, status = geoserver.create_wmts_layer(workspace, wmts_store, wmts_layer)
23
+ assert status == 201
24
+ assert content == wmts_layer
25
+
26
+ # with automatic tile caching enabled the tile layer is created with the
27
+ # WMTS layer; wait for it before publishing over it, GeoServer Cloud
28
+ # propagates the new layer between services asynchronously
29
+ assert wait_for_tile_layer_status(geoserver, workspace, wmts_layer, 200) == 200
30
+
31
+ content, status = geoserver.publish_gwc_layer(workspace, wmts_layer)
32
+ assert status == 200
33
+ assert content in ["", "layer saved"]
34
+
35
+ response = geoserver.get_tile(
36
+ format="image/png",
37
+ layer=f"{workspace}:{wmts_layer}",
38
+ tile_matrix_set="EPSG:4326",
39
+ tile_matrix="EPSG:4326:9",
40
+ row=122,
41
+ column=534,
42
+ )
43
+ assert response.info().get("Content-Type") == "image/png"
44
+ assert response.info().get("Geowebcache-Cache-Result") == "MISS"
45
+
46
+ response = geoserver.get_tile(
47
+ format="image/png",
48
+ layer=f"{workspace}:{wmts_layer}",
49
+ tile_matrix_set="EPSG:4326",
50
+ tile_matrix="EPSG:4326:9",
51
+ row=122,
52
+ column=534,
53
+ )
54
+ assert response.info().get("Geowebcache-Cache-Result") == "HIT"
55
+
56
+
57
+ def wait_for_tile_layer_status(
58
+ geoserver, workspace, layer, expected_status, timeout=30
59
+ ):
60
+ """Poll the GWC REST API until the tile layer reaches the expected status.
61
+
62
+ GeoServer Cloud propagates catalog changes between services asynchronously;
63
+ against a monolithic GeoServer the first poll already settles.
64
+ """
65
+ deadline = time.monotonic() + timeout
66
+ status = None
67
+ while time.monotonic() < deadline:
68
+ _, status = geoserver.get_gwc_layer(workspace, layer)
69
+ if status == expected_status:
70
+ return status
71
+ time.sleep(0.5)
72
+ return status
73
+
74
+
75
+ @pytest.mark.db
76
+ def test_automatic_tile_layer_lifecycle(config, geoserver_factory):
77
+ """Tile layers must follow REST catalog changes when automatic caching is on.
78
+
79
+ Regression test for https://github.com/geoserver/geoserver-cloud/issues/519
80
+ """
81
+ workspace = datastore = "test_gwc_auto"
82
+ feature_type = "auto_cached_layer"
83
+ renamed = "auto_cached_layer_renamed"
84
+ geoserver: GeoServerCloud = geoserver_factory(workspace)
85
+
86
+ _, code = geoserver.create_pg_datastore(
87
+ workspace_name=workspace,
88
+ datastore_name=datastore,
89
+ pg_host=config["db"]["pg_host"]["docker"],
90
+ pg_port=config["db"]["pg_port"]["docker"],
91
+ pg_db=config["db"]["pg_db"],
92
+ pg_user=config["db"]["pg_user"],
93
+ pg_password=config["db"]["pg_password"],
94
+ pg_schema=config["db"]["pg_schema"],
95
+ set_default_datastore=True,
96
+ )
97
+ assert code == 201
98
+
99
+ attributes = {
100
+ "geom": {"type": "Point", "required": True},
101
+ "id": {"type": "integer", "required": True},
102
+ }
103
+ _, code = geoserver.create_feature_type(
104
+ feature_type, attributes=attributes, epsg=4326, workspace_name=workspace
105
+ )
106
+ assert code == 201
107
+
108
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
109
+
110
+ response = geoserver.rest_service.rest_client.put(
111
+ f"/rest/workspaces/{workspace}/datastores/{datastore}/featuretypes/{feature_type}.json",
112
+ json={"featureType": {"name": renamed}},
113
+ )
114
+ assert response.status_code == 200
115
+
116
+ assert wait_for_tile_layer_status(geoserver, workspace, renamed, 200) == 200
117
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
118
+
119
+ _, code = geoserver.delete_feature_type(workspace, datastore, renamed)
120
+ assert code == 200
121
+
122
+ assert wait_for_tile_layer_status(geoserver, workspace, renamed, 404) == 404
123
+
124
+
125
+ @pytest.mark.db
126
+ def test_tile_layer_follows_workspace_rename(config, geoserver_factory):
127
+ """Renaming a workspace must rename all its tile layers (prefixed names).
128
+
129
+ Regression test for https://github.com/geoserver/geoserver-cloud/issues/519
130
+ """
131
+ workspace = datastore = "test_gwc_wsrename"
132
+ renamed_workspace = "test_gwc_wsrenamed"
133
+ feature_type = "ws_rename_layer"
134
+ geoserver: GeoServerCloud = geoserver_factory(workspace)
135
+
136
+ _, code = geoserver.create_pg_datastore(
137
+ workspace_name=workspace,
138
+ datastore_name=datastore,
139
+ pg_host=config["db"]["pg_host"]["docker"],
140
+ pg_port=config["db"]["pg_port"]["docker"],
141
+ pg_db=config["db"]["pg_db"],
142
+ pg_user=config["db"]["pg_user"],
143
+ pg_password=config["db"]["pg_password"],
144
+ pg_schema=config["db"]["pg_schema"],
145
+ set_default_datastore=True,
146
+ )
147
+ assert code == 201
148
+
149
+ attributes = {"geom": {"type": "Point", "required": True}}
150
+ _, code = geoserver.create_feature_type(
151
+ feature_type, attributes=attributes, epsg=4326, workspace_name=workspace
152
+ )
153
+ assert code == 201
154
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
155
+
156
+ response = geoserver.rest_service.rest_client.put(
157
+ f"/rest/workspaces/{workspace}.json",
158
+ json={"workspace": {"name": renamed_workspace}},
159
+ )
160
+ assert response.status_code == 200
161
+
162
+ try:
163
+ assert (
164
+ wait_for_tile_layer_status(geoserver, renamed_workspace, feature_type, 200)
165
+ == 200
166
+ )
167
+ assert (
168
+ wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
169
+ )
170
+ finally:
171
+ # rename back to the original name for the workspace cleanup finalizer
172
+ geoserver.rest_service.rest_client.put(
173
+ f"/rest/workspaces/{renamed_workspace}.json",
174
+ json={"workspace": {"name": workspace}},
175
+ )
176
+
177
+
178
+ @pytest.mark.db
179
+ def test_tile_layer_rename_after_tile_layer_recreated_through_gwc(
180
+ config, geoserver_factory
181
+ ):
182
+ """Layer renames must reach every service even when the service handling the
183
+ rename has not touched the tile layer since another service last changed it.
184
+
185
+ The tile layer is deleted and recreated through the GWC service, then the
186
+ feature type is renamed through the REST API. The tile layer must follow the
187
+ rename regardless of which service changed it last.
188
+ """
189
+ workspace = datastore = "test_gwc_coldrename"
190
+ feature_type = "cold_rename_layer"
191
+ renamed = "cold_rename_layer_renamed"
192
+ geoserver: GeoServerCloud = geoserver_factory(workspace)
193
+
194
+ _, code = geoserver.create_pg_datastore(
195
+ workspace_name=workspace,
196
+ datastore_name=datastore,
197
+ pg_host=config["db"]["pg_host"]["docker"],
198
+ pg_port=config["db"]["pg_port"]["docker"],
199
+ pg_db=config["db"]["pg_db"],
200
+ pg_user=config["db"]["pg_user"],
201
+ pg_password=config["db"]["pg_password"],
202
+ pg_schema=config["db"]["pg_schema"],
203
+ set_default_datastore=True,
204
+ )
205
+ assert code == 201
206
+
207
+ attributes = {"geom": {"type": "Point", "required": True}}
208
+ _, code = geoserver.create_feature_type(
209
+ feature_type, attributes=attributes, epsg=4326, workspace_name=workspace
210
+ )
211
+ assert code == 201
212
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
213
+
214
+ # recreate the tile layer through the GWC service
215
+ _, code = geoserver.delete_gwc_layer(workspace, feature_type)
216
+ assert code == 200
217
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
218
+ _, code = geoserver.publish_gwc_layer(workspace, feature_type)
219
+ assert code == 200
220
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
221
+
222
+ # rename the feature type through the REST API
223
+ response = geoserver.rest_service.rest_client.put(
224
+ f"/rest/workspaces/{workspace}/datastores/{datastore}/featuretypes/{feature_type}.json",
225
+ json={"featureType": {"name": renamed}},
226
+ )
227
+ assert response.status_code == 200
228
+
229
+ assert wait_for_tile_layer_status(geoserver, workspace, renamed, 200) == 200
230
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
231
+
232
+ _, code = geoserver.delete_feature_type(workspace, datastore, renamed)
233
+ assert code == 200
234
+
235
+
236
+ @pytest.mark.db
237
+ def test_workspace_rename_after_tile_layer_recreated_through_gwc(
238
+ config, geoserver_factory
239
+ ):
240
+ """Workspace renames must rename tile layers even when the service handling
241
+ the rename has not touched them since another service last changed them.
242
+ """
243
+ workspace = datastore = "test_gwc_coldws"
244
+ renamed_workspace = "test_gwc_coldws_renamed"
245
+ feature_type = "cold_ws_layer"
246
+ geoserver: GeoServerCloud = geoserver_factory(workspace)
247
+
248
+ _, code = geoserver.create_pg_datastore(
249
+ workspace_name=workspace,
250
+ datastore_name=datastore,
251
+ pg_host=config["db"]["pg_host"]["docker"],
252
+ pg_port=config["db"]["pg_port"]["docker"],
253
+ pg_db=config["db"]["pg_db"],
254
+ pg_user=config["db"]["pg_user"],
255
+ pg_password=config["db"]["pg_password"],
256
+ pg_schema=config["db"]["pg_schema"],
257
+ set_default_datastore=True,
258
+ )
259
+ assert code == 201
260
+
261
+ attributes = {"geom": {"type": "Point", "required": True}}
262
+ _, code = geoserver.create_feature_type(
263
+ feature_type, attributes=attributes, epsg=4326, workspace_name=workspace
264
+ )
265
+ assert code == 201
266
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
267
+
268
+ # recreate the tile layer through the GWC service
269
+ _, code = geoserver.delete_gwc_layer(workspace, feature_type)
270
+ assert code == 200
271
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
272
+ _, code = geoserver.publish_gwc_layer(workspace, feature_type)
273
+ assert code == 200
274
+ assert wait_for_tile_layer_status(geoserver, workspace, feature_type, 200) == 200
275
+
276
+ # rename the workspace through the REST API
277
+ response = geoserver.rest_service.rest_client.put(
278
+ f"/rest/workspaces/{workspace}.json",
279
+ json={"workspace": {"name": renamed_workspace}},
280
+ )
281
+ assert response.status_code == 200
282
+
283
+ try:
284
+ assert (
285
+ wait_for_tile_layer_status(geoserver, renamed_workspace, feature_type, 200)
286
+ == 200
287
+ )
288
+ assert (
289
+ wait_for_tile_layer_status(geoserver, workspace, feature_type, 404) == 404
290
+ )
291
+ finally:
292
+ geoserver.rest_service.rest_client.put(
293
+ f"/rest/workspaces/{renamed_workspace}.json",
294
+ json={"workspace": {"name": workspace}},
295
+ )
@@ -0,0 +1,110 @@
1
+ """Acceptance tests for the REST resource API (/rest/resource/**).
2
+
3
+ Regression coverage for https://github.com/geoserver/geoserver-cloud/issues/913:
4
+ requests whose path contains "/gwc" anywhere, such as /rest/resource/gwc-gs.xml,
5
+ used to fail with a 500 NPE ("Cannot invoke String.substring(int) because path
6
+ is null") or a 404 for existing resources, because the servlet filters that
7
+ rebuild getPathInfo() in GeoServer Cloud mistook them for GeoWebCache requests.
8
+ """
9
+
10
+ import pytest
11
+
12
+ from geoservercloud import GeoServerCloud
13
+
14
+ RESOURCE_API = "/rest/resource"
15
+
16
+
17
+ @pytest.fixture
18
+ def rest_client(geoserver: GeoServerCloud):
19
+ return geoserver.rest_service.rest_client
20
+
21
+
22
+ @pytest.fixture
23
+ def resource_directory(rest_client, request):
24
+ """Factory for a resource directory deleted (recursively) on teardown."""
25
+
26
+ def _create(directory_name):
27
+ request.addfinalizer(
28
+ lambda: rest_client.delete(f"{RESOURCE_API}/{directory_name}")
29
+ )
30
+ return directory_name
31
+
32
+ return _create
33
+
34
+
35
+ def test_get_gwc_config_file(rest_client):
36
+ """GET an existing file whose name contains "gwc": the exact request from issue #913."""
37
+ response = rest_client.get(f"{RESOURCE_API}/gwc-gs.xml")
38
+ assert response.status_code == 200
39
+ assert "<GeoServerGWCConfig>" in response.text
40
+
41
+
42
+ def test_root_listing_contains_gwc_config_file(rest_client):
43
+ response = rest_client.get(RESOURCE_API, params={"format": "json"})
44
+ assert response.status_code == 200
45
+ assert "gwc-gs.xml" in response.text
46
+
47
+
48
+ def test_nonexistent_gwc_prefixed_path_returns_404(rest_client):
49
+ """Missing resources must report 404, not a 500 NPE (issue #913)."""
50
+ response = rest_client.get(f"{RESOURCE_API}/gwcfoo")
51
+ assert response.status_code == 404
52
+
53
+
54
+ def test_roundtrip_in_gwc_named_directory(rest_client, resource_directory):
55
+ """Create, list, read and delete inside a directory whose name starts with "gwc"."""
56
+ directory = resource_directory("gwc913dir")
57
+ file_path = f"{RESOURCE_API}/{directory}/child.txt"
58
+
59
+ put_text_resource(rest_client, file_path, "issue #913 directory probe")
60
+
61
+ listing = rest_client.get(f"{RESOURCE_API}/{directory}", params={"format": "json"})
62
+ assert listing.status_code == 200
63
+ assert "child.txt" in listing.text
64
+
65
+ assert_file_roundtrip(rest_client, file_path, "issue #913 directory probe")
66
+
67
+
68
+ def test_roundtrip_on_gwc_prefixed_file_name(rest_client, resource_directory):
69
+ """Create, read and delete a file whose name starts with "gwc" (issue #913)."""
70
+ directory = resource_directory("resource_api_913")
71
+ file_path = f"{RESOURCE_API}/{directory}/gwc-913-probe.txt"
72
+
73
+ put_text_resource(rest_client, file_path, "issue #913 file name probe")
74
+ assert_file_roundtrip(rest_client, file_path, "issue #913 file name probe")
75
+
76
+
77
+ def test_roundtrip_on_plain_file_name(rest_client, resource_directory):
78
+ """Baseline coverage of the resource API on a path without "gwc" in it."""
79
+ directory = resource_directory("resource_api_plain")
80
+ file_path = f"{RESOURCE_API}/{directory}/probe.txt"
81
+
82
+ put_text_resource(rest_client, file_path, "plain resource probe")
83
+
84
+ metadata = rest_client.get(
85
+ file_path, params={"operation": "metadata", "format": "json"}
86
+ )
87
+ assert metadata.status_code == 200
88
+ assert "probe.txt" in metadata.text
89
+
90
+ assert_file_roundtrip(rest_client, file_path, "plain resource probe")
91
+
92
+
93
+ def put_text_resource(rest_client, file_path, contents):
94
+ response = rest_client.put(
95
+ file_path, data=contents, headers={"Content-Type": "text/plain"}
96
+ )
97
+ assert response.status_code in (200, 201)
98
+
99
+
100
+ def assert_file_roundtrip(rest_client, file_path, contents):
101
+ """The file must be readable, deletable, and report 404 once deleted."""
102
+ response = rest_client.get(file_path)
103
+ assert response.status_code == 200
104
+ assert response.text == contents
105
+
106
+ response = rest_client.delete(file_path)
107
+ assert response.status_code == 200
108
+
109
+ response = rest_client.get(file_path)
110
+ assert response.status_code == 404
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "geoservercloud"
3
- version = "0.8.10.dev6"
3
+ version = "0.8.11.dev1"
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"
@@ -1,45 +0,0 @@
1
- from geoservercloud import GeoServerCloud
2
-
3
-
4
- def test_tile_cache(geoserver_factory):
5
- workspace = "test_gwc"
6
- wmts_store = "test_gwc_store"
7
- wmts_layer = "ch.swisstopo.swissimage"
8
- geoserver: GeoServerCloud = geoserver_factory(workspace)
9
-
10
- content, status = geoserver.create_wmts_store(
11
- workspace,
12
- wmts_store,
13
- capabilities="https://wmts.geo.admin.ch/EPSG/4326/1.0.0/WMTSCapabilities.xml",
14
- )
15
- assert status == 201
16
- assert content == wmts_store
17
-
18
- content, status = geoserver.create_wmts_layer(workspace, wmts_store, wmts_layer)
19
- assert status == 201
20
- assert content == wmts_layer
21
-
22
- content, status = geoserver.publish_gwc_layer(workspace, wmts_layer)
23
- assert status == 200
24
- assert content in ["", "layer saved"]
25
-
26
- response = geoserver.get_tile(
27
- format="image/png",
28
- layer=f"{workspace}:{wmts_layer}",
29
- tile_matrix_set="EPSG:4326",
30
- tile_matrix="EPSG:4326:9",
31
- row=122,
32
- column=534,
33
- )
34
- assert response.info().get("Content-Type") == "image/png"
35
- assert response.info().get("Geowebcache-Cache-Result") == "MISS"
36
-
37
- response = geoserver.get_tile(
38
- format="image/png",
39
- layer=f"{workspace}:{wmts_layer}",
40
- tile_matrix_set="EPSG:4326",
41
- tile_matrix="EPSG:4326:9",
42
- row=122,
43
- column=534,
44
- )
45
- assert response.info().get("Geowebcache-Cache-Result") == "HIT"