mirror of
https://github.com/geoserver/geoserver-cloud.git
synced 2025-12-08 20:16:08 +00:00
- Add comprehensive ImageMosaic test coverage: direct directory, manual granules, empty store workflows, and XML-based store creation - Fix file path handling: use direct paths instead of file:// URLs for local files - Update documentation to mention shared mount volume at /mnt/geoserver_data - Add version testing examples (TAG=2.27.1.0, TAG=2.26.2.0) to README Tests pass with datadir backend but show limitations with pgconfig backend. Provides comprehensive test coverage for realistic ImageMosaic workflows.
540 lines
21 KiB
Python
540 lines
21 KiB
Python
"""
|
|
ImageMosaic acceptance tests for GeoServer Cloud
|
|
|
|
Tests various workflows for creating ImageMosaic stores and layers:
|
|
- Direct directory creation (like web UI)
|
|
- Manual granule addition
|
|
- Empty store creation with directory/file harvesting
|
|
- XML-based store creation
|
|
|
|
All tests use sample data from a shared mount volume at /mnt/geoserver_data
|
|
that is accessible to both the test environment and GeoServer containers.
|
|
"""
|
|
import os
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
import pytest
|
|
from geoservercloud import GeoServerCloud
|
|
from conftest import GEOSERVER_URL
|
|
|
|
|
|
def test_create_imagemosaic_local_files():
|
|
"""Test creating an ImageMosaic using local sample data files via direct directory approach"""
|
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
|
workspace = "local_sampledata"
|
|
store_name = "ne_pyramid_store"
|
|
|
|
# Delete and recreate workspace
|
|
geoserver.delete_workspace(workspace)
|
|
response = geoserver.create_workspace(workspace)
|
|
assert response.status_code == 201
|
|
|
|
# Use direct directory approach (like web UI) instead of individual file URLs
|
|
directory_path = "/mnt/geoserver_data/sampledata/ne/pyramid/"
|
|
|
|
# Create ImageMosaic store directly from directory
|
|
response = geoserver.put_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/external.imagemosaic",
|
|
data=directory_path,
|
|
headers={"Content-Type": "text/plain"}
|
|
)
|
|
assert response.status_code in [201, 202], f"Failed to create ImageMosaic from directory: {response.text}"
|
|
|
|
# List available coverages (should be auto-discovered)
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.xml?list=all"
|
|
)
|
|
assert response.status_code == 200, f"Failed to list coverages: {response.text}"
|
|
|
|
# Extract the auto-discovered coverage name
|
|
response_text = response.text
|
|
import re
|
|
coverage_match = re.search(r'<coverageName>([^<]+)</coverageName>', response_text)
|
|
assert coverage_match, f"No coverage found in response: {response_text}"
|
|
|
|
coverage_name = coverage_match.group(1)
|
|
|
|
# Check if coverage was auto-created (likely scenario)
|
|
coverage_response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages/{coverage_name}.json"
|
|
)
|
|
|
|
if coverage_response.status_code == 200:
|
|
# Coverage was auto-created - this is the normal case
|
|
coverage_data = coverage_response.json()["coverage"]
|
|
assert coverage_data["name"] == coverage_name
|
|
assert coverage_data["nativeName"] == coverage_name
|
|
assert coverage_data["enabled"] == True
|
|
else:
|
|
# Coverage not auto-created, create it manually
|
|
coverage_xml = f"""<coverage>
|
|
<name>{coverage_name}</name>
|
|
<title>Natural Earth Pyramid Mosaic</title>
|
|
<nativeName>{coverage_name}</nativeName>
|
|
<enabled>true</enabled>
|
|
</coverage>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
|
|
data=coverage_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Failed to create coverage: {response.text}"
|
|
|
|
# Verify the coverage was created
|
|
response = geoserver.get_request(f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages/{coverage_name}.json")
|
|
assert response.status_code == 200
|
|
|
|
coverage_data = response.json()["coverage"]
|
|
assert coverage_data["name"] == coverage_name
|
|
assert coverage_data["nativeName"] == coverage_name
|
|
assert coverage_data["enabled"] == True
|
|
|
|
# Test WMS GetMap request (verify local file mosaic works)
|
|
wms_response = geoserver.get_request(
|
|
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage_name}&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
|
|
)
|
|
assert wms_response.status_code == 200, f"WMS GetMap failed: {wms_response.text}"
|
|
assert wms_response.headers.get("content-type").startswith("image/png")
|
|
|
|
# Cleanup
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
|
|
def test_create_imagemosaic_manual_granules():
|
|
"""Test creating an ImageMosaic by manually adding individual granules"""
|
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
|
workspace = "manual_granules"
|
|
store_name = "manual_granules_store"
|
|
coverage_name = "manual_granules_coverage"
|
|
|
|
# Delete and recreate workspace
|
|
geoserver.delete_workspace(workspace)
|
|
response = geoserver.create_workspace(workspace)
|
|
assert response.status_code == 201
|
|
|
|
# Create temporary directory for mosaic configuration
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
tmp_path = Path(tmp_dir)
|
|
|
|
# Create indexer.properties for manual granule addition
|
|
indexer_content = f"""MosaicCRS=EPSG\\:4326
|
|
Name={coverage_name}
|
|
PropertyCollectors=CRSExtractorSPI(crs),ResolutionExtractorSPI(resolution)
|
|
Schema=*the_geom:Polygon,location:String,crs:String,resolution:String
|
|
CanBeEmpty=true
|
|
AbsolutePath=true"""
|
|
|
|
indexer_file = tmp_path / "indexer.properties"
|
|
indexer_file.write_text(indexer_content)
|
|
|
|
# Create datastore.properties (using JNDI like in COG tests)
|
|
datastore_content = """SPI=org.geotools.data.postgis.PostgisNGJNDIDataStoreFactory
|
|
# JNDI data source
|
|
jndiReferenceName=java:comp/env/jdbc/postgis
|
|
|
|
#Boolean
|
|
# perform only primary filter on bbox
|
|
# Default Boolean.TRUE
|
|
Loose\\ bbox=true
|
|
|
|
#Boolean
|
|
# use prepared statements
|
|
#Default Boolean.FALSE
|
|
preparedStatements=false
|
|
"""
|
|
datastore_file = tmp_path / "datastore.properties"
|
|
datastore_file.write_text(datastore_content)
|
|
|
|
# Create ZIP file with both configuration files
|
|
zip_file = tmp_path / "manual-granules-config.zip"
|
|
with zipfile.ZipFile(zip_file, 'w') as zf:
|
|
zf.write(indexer_file, "indexer.properties")
|
|
zf.write(datastore_file, "datastore.properties")
|
|
|
|
# Create empty ImageMosaic store
|
|
with open(zip_file, 'rb') as f:
|
|
zip_data = f.read()
|
|
|
|
response = geoserver.put_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/file.imagemosaic?configure=none",
|
|
data=zip_data,
|
|
headers={"Content-Type": "application/zip"}
|
|
)
|
|
assert response.status_code == 201, f"Failed to create ImageMosaic store: {response.text}"
|
|
|
|
# Manually add individual granules from the sample data
|
|
granule_paths = [
|
|
"/mnt/geoserver_data/sampledata/ne/pyramid/NE1_LR_LC_SR_W_DR_1_1.tif",
|
|
"/mnt/geoserver_data/sampledata/ne/pyramid/NE1_LR_LC_SR_W_DR_1_2.tif",
|
|
"/mnt/geoserver_data/sampledata/ne/pyramid/NE1_LR_LC_SR_W_DR_2_1.tif",
|
|
"/mnt/geoserver_data/sampledata/ne/pyramid/NE1_LR_LC_SR_W_DR_2_2.tif"
|
|
]
|
|
|
|
for granule_path in granule_paths:
|
|
# Use direct file paths (without file:// protocol) for external.imagemosaic
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/external.imagemosaic",
|
|
data=granule_path,
|
|
headers={"Content-Type": "text/plain"}
|
|
)
|
|
assert response.status_code in [201, 202], f"Failed to add granule {granule_path}: {response.text}"
|
|
|
|
# Initialize the store (list available coverages)
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.xml?list=all"
|
|
)
|
|
assert response.status_code == 200, f"Failed to list coverages: {response.text}"
|
|
|
|
# Verify coverage name is available
|
|
response_text = response.text
|
|
assert f"<coverageName>{coverage_name}</coverageName>" in response_text, \
|
|
f"Coverage name '{coverage_name}' not found in response: {response_text}"
|
|
|
|
# Create layer/coverage
|
|
coverage_xml = f"""<coverage>
|
|
<name>{coverage_name}</name>
|
|
<title>Manual Granules Test Coverage</title>
|
|
<nativeName>{coverage_name}</nativeName>
|
|
<enabled>true</enabled>
|
|
</coverage>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
|
|
data=coverage_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Failed to create coverage: {response.text}"
|
|
|
|
# Verify the coverage was created successfully
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages/{coverage_name}.json"
|
|
)
|
|
assert response.status_code == 200, f"Failed to get coverage details: {response.text}"
|
|
|
|
coverage_data = response.json()["coverage"]
|
|
assert coverage_data["name"] == coverage_name
|
|
assert coverage_data["nativeName"] == coverage_name
|
|
assert coverage_data["enabled"] == True
|
|
|
|
# Test WMS GetMap request (verify manual granule addition works)
|
|
wms_response = geoserver.get_request(
|
|
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage_name}&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
|
|
)
|
|
assert wms_response.status_code == 200, f"WMS GetMap failed: {wms_response.text}"
|
|
assert wms_response.headers.get("content-type").startswith("image/png")
|
|
|
|
# Cleanup
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
|
|
def test_create_imagemosaic_empty_store_with_directory_harvest():
|
|
"""
|
|
Test creating an empty ImageMosaic store first, then harvesting granules from a directory.
|
|
This tests the workflow: create store -> harvest directory -> create layer.
|
|
"""
|
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
|
workspace = "directory_harvest"
|
|
store_name = "directory_harvest_store"
|
|
coverage_name = "directory_harvest_coverage"
|
|
|
|
# Clean up any existing workspace
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
# Step 1: Create workspace
|
|
response = geoserver.create_workspace(workspace)
|
|
assert response.status_code == 201, f"Failed to create workspace: {response.text}"
|
|
|
|
# Step 2: Create ImageMosaic store with configuration
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
tmp_path = Path(tmp_dir)
|
|
|
|
# Create indexer.properties
|
|
indexer_content = f"""MosaicCRS=EPSG\\:4326
|
|
Name={coverage_name}
|
|
PropertyCollectors=CRSExtractorSPI(crs),ResolutionExtractorSPI(resolution)
|
|
Schema=*the_geom:Polygon,location:String,crs:String,resolution:String
|
|
CanBeEmpty=true
|
|
AbsolutePath=true"""
|
|
|
|
indexer_file = tmp_path / "indexer.properties"
|
|
indexer_file.write_text(indexer_content)
|
|
|
|
# Create datastore.properties (using JNDI)
|
|
datastore_content = """SPI=org.geotools.data.postgis.PostgisNGJNDIDataStoreFactory
|
|
# JNDI data source
|
|
jndiReferenceName=java:comp/env/jdbc/postgis
|
|
|
|
#Boolean
|
|
# perform only primary filter on bbox
|
|
# Default Boolean.TRUE
|
|
Loose\\ bbox=true
|
|
|
|
#Boolean
|
|
# use prepared statements
|
|
#Default Boolean.FALSE
|
|
preparedStatements=false
|
|
"""
|
|
datastore_file = tmp_path / "datastore.properties"
|
|
datastore_file.write_text(datastore_content)
|
|
|
|
# Create ZIP file with both configuration files
|
|
zip_file = tmp_path / "mosaic-config.zip"
|
|
with zipfile.ZipFile(zip_file, 'w') as zf:
|
|
zf.write(indexer_file, "indexer.properties")
|
|
zf.write(datastore_file, "datastore.properties")
|
|
|
|
# Upload ZIP to create empty ImageMosaic store
|
|
with open(zip_file, 'rb') as f:
|
|
zip_data = f.read()
|
|
|
|
response = geoserver.put_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/file.imagemosaic?configure=none",
|
|
data=zip_data,
|
|
headers={"Content-Type": "application/zip"}
|
|
)
|
|
assert response.status_code == 201, f"Failed to create ImageMosaic store: {response.text}"
|
|
|
|
# Step 3: Harvest granules from directory
|
|
harvest_path = "/mnt/geoserver_data/sampledata/ne/pyramid/"
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/external.imagemosaic",
|
|
data=harvest_path,
|
|
headers={"Content-Type": "text/plain"}
|
|
)
|
|
assert response.status_code in [201, 202], f"Failed to harvest directory {harvest_path}: {response.text}"
|
|
|
|
# Step 4: List available coverages
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.xml?list=all"
|
|
)
|
|
assert response.status_code == 200, f"Failed to list coverages: {response.text}"
|
|
|
|
# Verify coverage name is available
|
|
response_text = response.text
|
|
assert f"<coverageName>{coverage_name}</coverageName>" in response_text, \
|
|
f"Coverage name '{coverage_name}' not found in response: {response_text}"
|
|
|
|
# Step 5: Create layer/coverage
|
|
coverage_xml = f"""<coverage>
|
|
<name>{coverage_name}</name>
|
|
<title>Directory Harvest Test Coverage</title>
|
|
<nativeName>{coverage_name}</nativeName>
|
|
<enabled>true</enabled>
|
|
</coverage>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
|
|
data=coverage_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Layer creation failed: {response.text}"
|
|
|
|
# Step 6: Verify the coverage was created successfully
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages/{coverage_name}.json"
|
|
)
|
|
assert response.status_code == 200, f"Failed to get coverage details: {response.text}"
|
|
|
|
coverage_data = response.json()["coverage"]
|
|
assert coverage_data["name"] == coverage_name
|
|
assert coverage_data["nativeName"] == coverage_name
|
|
assert coverage_data["enabled"] == True
|
|
|
|
# Step 7: Test WMS GetMap request
|
|
wms_response = geoserver.get_request(
|
|
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage_name}"
|
|
f"&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
|
|
)
|
|
assert wms_response.status_code == 200, f"WMS GetMap failed: {wms_response.text}"
|
|
assert wms_response.headers.get("content-type").startswith("image/png")
|
|
|
|
# Cleanup
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
|
|
def test_create_imagemosaic_empty_store_with_single_file_harvest():
|
|
"""
|
|
Test creating an empty ImageMosaic store first, then harvesting a single file.
|
|
This tests the workflow: create store -> harvest single file -> create layer.
|
|
"""
|
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
|
workspace = "single_file_harvest"
|
|
store_name = "single_file_harvest_store"
|
|
coverage_name = "single_file_harvest_coverage"
|
|
|
|
# Clean up any existing workspace
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
# Step 1: Create workspace
|
|
response = geoserver.create_workspace(workspace)
|
|
assert response.status_code == 201, f"Failed to create workspace: {response.text}"
|
|
|
|
# Step 2: Create ImageMosaic store
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
tmp_path = Path(tmp_dir)
|
|
|
|
# Create indexer.properties for single file
|
|
indexer_content = f"""MosaicCRS=EPSG\\:4326
|
|
Name={coverage_name}
|
|
PropertyCollectors=CRSExtractorSPI(crs),ResolutionExtractorSPI(resolution)
|
|
Schema=*the_geom:Polygon,location:String,crs:String,resolution:String
|
|
CanBeEmpty=true
|
|
AbsolutePath=true"""
|
|
|
|
indexer_file = tmp_path / "indexer.properties"
|
|
indexer_file.write_text(indexer_content)
|
|
|
|
# Create datastore.properties (using JNDI)
|
|
datastore_content = """SPI=org.geotools.data.postgis.PostgisNGJNDIDataStoreFactory
|
|
# JNDI data source
|
|
jndiReferenceName=java:comp/env/jdbc/postgis
|
|
|
|
#Boolean
|
|
# perform only primary filter on bbox
|
|
# Default Boolean.TRUE
|
|
Loose\\ bbox=true
|
|
|
|
#Boolean
|
|
# use prepared statements
|
|
#Default Boolean.FALSE
|
|
preparedStatements=false
|
|
"""
|
|
datastore_file = tmp_path / "datastore.properties"
|
|
datastore_file.write_text(datastore_content)
|
|
|
|
# Create ZIP file with both files
|
|
zip_file = tmp_path / "mosaic-single-config.zip"
|
|
with zipfile.ZipFile(zip_file, 'w') as zf:
|
|
zf.write(indexer_file, "indexer.properties")
|
|
zf.write(datastore_file, "datastore.properties")
|
|
|
|
# Upload ZIP to create ImageMosaic store
|
|
with open(zip_file, 'rb') as f:
|
|
zip_data = f.read()
|
|
|
|
response = geoserver.put_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/file.imagemosaic?configure=none",
|
|
data=zip_data,
|
|
headers={"Content-Type": "application/zip"}
|
|
)
|
|
assert response.status_code == 201, f"Failed to create ImageMosaic store: {response.text}"
|
|
|
|
# Step 3: Harvest single file
|
|
single_file_path = "/mnt/geoserver_data/sampledata/ne/NE1_LR_LC_SR_W_DR.tif"
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/external.imagemosaic",
|
|
data=single_file_path,
|
|
headers={"Content-Type": "text/plain"}
|
|
)
|
|
assert response.status_code in [201, 202], f"Failed to harvest file {single_file_path}: {response.text}"
|
|
|
|
# Step 4: List and create layer
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.xml?list=all"
|
|
)
|
|
assert response.status_code == 200, f"Failed to list coverages: {response.text}"
|
|
|
|
# Create layer/coverage
|
|
coverage_xml = f"""<coverage>
|
|
<name>{coverage_name}</name>
|
|
<title>Single File Harvest Test Coverage</title>
|
|
<nativeName>{coverage_name}</nativeName>
|
|
<enabled>true</enabled>
|
|
</coverage>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
|
|
data=coverage_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Layer creation failed: {response.text}"
|
|
|
|
# Verify WMS works
|
|
wms_response = geoserver.get_request(
|
|
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage_name}"
|
|
f"&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
|
|
)
|
|
assert wms_response.status_code == 200, f"WMS GetMap failed: {wms_response.text}"
|
|
assert wms_response.headers.get("content-type").startswith("image/png")
|
|
|
|
# Cleanup
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
|
|
def test_create_imagemosaic_via_xml_store_creation():
|
|
"""
|
|
Test creating an ImageMosaic store via XML store creation (not file upload).
|
|
This tests direct store creation pointing to a directory.
|
|
"""
|
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
|
workspace = "xml_store_creation"
|
|
store_name = "xml_store_creation_store"
|
|
|
|
# Clean up any existing workspace
|
|
geoserver.delete_workspace(workspace)
|
|
|
|
# Step 1: Create workspace
|
|
response = geoserver.create_workspace(workspace)
|
|
assert response.status_code == 201, f"Failed to create workspace: {response.text}"
|
|
|
|
# Step 2: Create ImageMosaic store via XML store creation
|
|
store_xml = f"""<coverageStore>
|
|
<name>{store_name}</name>
|
|
<workspace>
|
|
<name>{workspace}</name>
|
|
</workspace>
|
|
<type>ImageMosaic</type>
|
|
<enabled>true</enabled>
|
|
<url>/mnt/geoserver_data/sampledata/ne/pyramid/</url>
|
|
</coverageStore>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores",
|
|
data=store_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Store creation via XML failed: {response.text}"
|
|
|
|
# Step 3: List available coverages
|
|
response = geoserver.get_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.xml?list=all"
|
|
)
|
|
assert response.status_code == 200, f"Failed to list coverages: {response.text}"
|
|
assert "coverageName" in response.text, f"No coverage found in response: {response.text}"
|
|
|
|
# Extract coverage name
|
|
import re
|
|
coverage_match = re.search(r'<coverageName>([^<]+)</coverageName>', response.text)
|
|
assert coverage_match, f"Could not extract coverage name from: {response.text}"
|
|
coverage_name = coverage_match.group(1)
|
|
|
|
# Create layer
|
|
coverage_xml = f"""<coverage>
|
|
<name>{coverage_name}</name>
|
|
<title>XML Store Creation Test Coverage</title>
|
|
<nativeName>{coverage_name}</nativeName>
|
|
<enabled>true</enabled>
|
|
</coverage>"""
|
|
|
|
response = geoserver.post_request(
|
|
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
|
|
data=coverage_xml,
|
|
headers={"Content-Type": "text/xml"}
|
|
)
|
|
assert response.status_code == 201, f"Layer creation failed: {response.text}"
|
|
|
|
# Verify WMS works
|
|
wms_response = geoserver.get_request(
|
|
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage_name}"
|
|
f"&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
|
|
)
|
|
assert wms_response.status_code == 200, f"WMS GetMap failed: {wms_response.text}"
|
|
assert wms_response.headers.get("content-type").startswith("image/png")
|
|
|
|
# Cleanup
|
|
geoserver.delete_workspace(workspace)
|