Consolidate ImageMosaic acceptance tests

- 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.
This commit is contained in:
Gabriel Roldan 2025-07-10 16:28:20 -03:00
parent ba0ef2c323
commit 47ff586e2b
No known key found for this signature in database
GPG Key ID: 697E8F9DF72128E1
18 changed files with 1178 additions and 27 deletions

View File

@ -1,7 +1,7 @@
.PHONY: all .PHONY: all
all: install test build-image all: install test build-image
TAG=$(shell mvn help:evaluate -Dexpression=project.version -q -DforceStdout) TAG?=$(shell mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
COSIGN_PASSWORD := $(COSIGN_PASSWORD) COSIGN_PASSWORD := $(COSIGN_PASSWORD)
@ -158,14 +158,14 @@ verify-image:
.PHONY: build-acceptance .PHONY: build-acceptance
build-acceptance: build-acceptance:
docker build --tag=acceptance:$(TAG) acceptance_tests docker build --tag=geoservercloud/acceptance:latest acceptance_tests
.PHONY: acceptance-tests-datadir .PHONY: acceptance-tests-datadir
acceptance-tests-datadir: build-acceptance start-acceptance-tests-datadir run-acceptance-tests-datadir acceptance-tests-datadir: build-acceptance start-acceptance-tests-datadir run-acceptance-tests-datadir
.PHONY: start-acceptance-tests-datadir .PHONY: start-acceptance-tests-datadir
start-acceptance-tests-datadir: start-acceptance-tests-datadir:
(cd compose/ && ./acceptance_datadir up -d) (cd compose/ && TAG=$(TAG) ./acceptance_datadir up -d)
.PHONY: run-acceptance-tests-datadir .PHONY: run-acceptance-tests-datadir
run-acceptance-tests-datadir: run-acceptance-tests-datadir:
@ -173,14 +173,14 @@ run-acceptance-tests-datadir:
.PHONY: clean-acceptance-tests-datadir .PHONY: clean-acceptance-tests-datadir
clean-acceptance-tests-datadir: clean-acceptance-tests-datadir:
(cd compose/ && ./acceptance_datadir down -v) (cd compose/ && TAG=$(TAG) ./acceptance_datadir down -v)
.PHONY: acceptance-tests-pgconfig .PHONY: acceptance-tests-pgconfig
acceptance-tests-pgconfig: build-acceptance start-acceptance-tests-pgconfig run-acceptance-tests-pgconfig acceptance-tests-pgconfig: build-acceptance start-acceptance-tests-pgconfig run-acceptance-tests-pgconfig
.PHONY: start-acceptance-tests-pgconfig .PHONY: start-acceptance-tests-pgconfig
start-acceptance-tests-pgconfig: start-acceptance-tests-pgconfig:
(cd compose/ && ./acceptance_pgconfig up -d) (cd compose/ && TAG=$(TAG) ./acceptance_pgconfig up -d)
.PHONY: run-acceptance-tests-pgconfig .PHONY: run-acceptance-tests-pgconfig
run-acceptance-tests-pgconfig: run-acceptance-tests-pgconfig:
@ -188,7 +188,7 @@ run-acceptance-tests-pgconfig:
.PHONY: clean-acceptance-tests-pgconfig .PHONY: clean-acceptance-tests-pgconfig
clean-acceptance-tests-pgconfig: clean-acceptance-tests-pgconfig:
(cd compose/ && ./acceptance_pgconfig down -v) (cd compose/ && TAG=$(TAG) ./acceptance_pgconfig down -v)
.PHONY: acceptance-tests-jdbcconfig .PHONY: acceptance-tests-jdbcconfig
acceptance-tests-jdbcconfig: build-acceptance start-acceptance-tests-jdbcconfig run-acceptance-tests-jdbcconfig acceptance-tests-jdbcconfig: build-acceptance start-acceptance-tests-jdbcconfig run-acceptance-tests-jdbcconfig

View File

@ -2,17 +2,190 @@
## Requirements ## Requirements
[Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer) - Python 3.8+
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer) (recommended)
- Or a Python virtual environment
## Installation ## Installation
### Option 1: Using Poetry (recommended)
```shell ```shell
poetry install poetry install
``` ```
# Run the tests ### Option 2: Using Python virtual environment
First start the docker composition then run:
```shell ```shell
GEOSERVER_URL=http://localhost:9090/geoserver/cloud poetry run pytest -vvv . # Create virtual environment
python -m venv .venv
# Activate virtual environment
# On Linux/macOS:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate
# Install dependencies
pip install -e .
```
## Running the tests
### Option 1: Using make (runs full docker composition)
```shell
# Run tests with datadir backend
make acceptance-tests-datadir
# Run tests with pgconfig backend
make acceptance-tests-pgconfig
```
### Option 2: Manual execution
#### Run tests inside Docker container (recommended for all tests)
```shell
# Start GeoServer services
cd ../compose
./acceptance_datadir up -d # or ./acceptance_pgconfig up -d
# Optional: Start webui service if needed (not started by default in acceptance composition)
./acceptance_datadir scale webui=1
# Run all tests inside the container
./acceptance_datadir exec acceptance pytest . -vvv --color=yes
# Run specific tests inside the container
./acceptance_datadir exec acceptance pytest tests/test_cog.py -v --color=yes
```
#### Run tests from host machine (full functionality)
**Note:** This requires the geodatabase port to be exposed (port 5433). The acceptance composition now exposes this port automatically.
```shell
# Start GeoServer services (geodatabase port 5433 will be exposed)
cd ../compose
./acceptance_datadir up -d # or ./acceptance_pgconfig up -d
# Optional: Start webui service if needed
./acceptance_datadir scale webui=1
# From acceptance_tests directory, run tests from host
cd ../acceptance_tests
./run_tests_locally.sh tests/test_cog.py # Run COG tests
./run_tests_locally.sh tests/test_imagemosaic_cog.py # Run ImageMosaic tests
./run_tests_locally.sh tests/test_workspace.py # Run workspace tests
./run_tests_locally.sh # Run all tests
# Run specific test functions
./run_tests_locally.sh tests/test_imagemosaic_cog.py::test_create_imagemosaic_local_files
./run_tests_locally.sh tests/test_cog.py::test_create_cog_coverage
```
### Run specific tests with make
```shell
# To run specific tests with make, you can modify the Makefile or use the manual Docker approach above
```
## Debugging
If you need to debug the GeoServer services, you can run the acceptance test composition with local ports exposed:
```shell
cd ../compose
# Start the acceptance test compose with local ports
./acceptance_datadir -f localports.yml up -d
# Enable the webui service if needed
./acceptance_datadir -f localports.yml scale webui=1
# Shut down the rest service if you're going to launch it from your IDE
./acceptance_datadir -f localports.yml down rest
# Now you can run from the IDE with the `local` spring profile enabled
# and the required catalog backend profile (datadir/pgconfig)
```
### Accessing Sample Data
When debugging, you may need to access the sample data that's available in the containers. The sample data is extracted to `/mnt/geoserver_data/sampledata` inside the containers. To access it from your local development environment:
```shell
# Check what sample data is available
./acceptance_datadir exec wms find /mnt/geoserver_data/sampledata
# Copy sample data to your local machine for testing
docker cp $(./acceptance_datadir ps -q wms | head -1):/mnt/geoserver_data/sampledata ./local_sampledata
# Or mount the geoserver_data volume directly to a local directory
# Add this to your docker-compose override file:
# volumes:
# geoserver_data:
# driver: local
# driver_opts:
# type: none
# o: bind
# device: /path/to/local/sampledata
```
## Testing Different GeoServer Cloud Versions
You can test different versions of GeoServer Cloud without modifying the `.env` file by setting the TAG environment variable.
### Option 1: Using Make Commands (Recommended)
```shell
# Test with GeoServer Cloud 2.27.2-SNAPSHOT (datadir backend)
TAG=2.27.2-SNAPSHOT make start-acceptance-tests-datadir
cd acceptance_tests && ./run_tests_locally.sh tests/test_imagemosaic.py
TAG=2.27.2-SNAPSHOT make clean-acceptance-tests-datadir
# Test with GeoServer Cloud 2.26.2.0 (pgconfig backend)
TAG=2.26.2.0 make start-acceptance-tests-pgconfig
cd acceptance_tests && ./run_tests_locally.sh tests/test_imagemosaic.py
TAG=2.26.2.0 make clean-acceptance-tests-pgconfig
# Test with default version (from Maven project.version)
make start-acceptance-tests-datadir
cd acceptance_tests && ./run_tests_locally.sh
make clean-acceptance-tests-datadir
```
### Option 2: Manual Docker Compose Commands
```shell
# Test with GeoServer Cloud 2.27.1.0
cd ../compose
TAG=2.27.1.0 ./acceptance_datadir up -d
# Run your tests
cd ../acceptance_tests
./run_tests_locally.sh
# Test with GeoServer Cloud 2.26.2.0
cd ../compose
./acceptance_datadir down
TAG=2.26.2.0 ./acceptance_datadir up -d
# Run your tests again
cd ../acceptance_tests
./run_tests_locally.sh
# Return to default version (check .env file for current default)
cd ../compose
./acceptance_datadir down
./acceptance_datadir up -d
```
## Cleanup
```shell
# Stop and remove containers
cd ../compose
./acceptance_datadir down -v # or ./acceptance_pgconfig down -v
``` ```

View File

@ -0,0 +1,139 @@
#!/bin/bash
# Default GeoServer URL
GEOSERVER_URL=${GEOSERVER_URL:-"http://localhost:9090/geoserver/cloud"}
# Default database connection for local testing (requires geodatabase port exposed on 5433)
PGHOST=${PGHOST:-"localhost"}
PGPORT=${PGPORT:-"5433"}
PGDATABASE=${PGDATABASE:-"geodata"}
PGUSER=${PGUSER:-"geodata"}
PGPASSWORD=${PGPASSWORD:-"geodata"}
PGSCHEMA=${PGSCHEMA:-"test1"}
# Note: This script runs tests from the host machine and requires the geodatabase
# port to be exposed (5433). Start services with: ./acceptance_datadir up -d
# Help function
show_help() {
echo "Usage: $0 [OPTIONS] [TEST_PATH]"
echo ""
echo "Run GeoServer Cloud acceptance tests locally"
echo ""
echo "OPTIONS:"
echo " -h, --help Show this help message"
echo " -v, --verbose Run with verbose output (-vvv)"
echo " -q, --quiet Run with minimal output (-q)"
echo ""
echo "TEST_PATH:"
echo " Optional path to specific test file or test function"
echo " Examples:"
echo " $0 tests/test_cog.py"
echo " $0 tests/test_cog_imagemosaic.py::test_create_imagemosaic_cogs_http"
echo " $0 tests/test_workspace.py"
echo ""
echo "Environment variables:"
echo " GEOSERVER_URL GeoServer URL (default: http://localhost:9090/geoserver/cloud)"
echo " PGHOST Database host (default: localhost)"
echo " PGPORT Database port (default: 5433)"
echo ""
echo "Examples:"
echo " $0 # Run all tests"
echo " $0 tests/test_cog.py # Run COG tests only"
echo " $0 -v # Run all tests with verbose output"
echo " GEOSERVER_URL=http://localhost:8080/geoserver $0 # Use different URL"
}
# Parse command line arguments
VERBOSE_FLAG="-v"
TEST_PATH=""
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-v|--verbose)
VERBOSE_FLAG="-vvv"
shift
;;
-q|--quiet)
VERBOSE_FLAG="-q"
shift
;;
-*)
echo "Unknown option: $1" >&2
show_help >&2
exit 1
;;
*)
TEST_PATH="$1"
shift
;;
esac
done
# Set the target (all tests or specific test)
if [[ -n "$TEST_PATH" ]]; then
TARGET="$TEST_PATH"
else
TARGET="."
fi
echo "Running GeoServer Cloud acceptance tests..."
echo "GeoServer URL: $GEOSERVER_URL"
echo "Test target: $TARGET"
echo "Verbosity: $VERBOSE_FLAG"
echo ""
# Wait for GeoServer to be available
echo "Waiting for GeoServer to be available at $GEOSERVER_URL/rest/workspaces..."
max_attempts=60
attempt=0
while [ $attempt -lt $max_attempts ]; do
if curl -s -u admin:geoserver --fail "$GEOSERVER_URL/rest/workspaces" > /dev/null 2>&1; then
echo "✓ GeoServer is ready!"
break
fi
attempt=$((attempt + 1))
echo " Attempt $attempt/$max_attempts - waiting 5 seconds..."
sleep 5
done
if [ $attempt -eq $max_attempts ]; then
echo "✗ Timeout: GeoServer did not become available at $GEOSERVER_URL/rest/workspaces"
echo " Please ensure the services are running with: cd ../compose && ./acceptance_datadir up -d"
exit 1
fi
echo ""
# Check if we're using Poetry or virtual environment
if command -v poetry &> /dev/null && [[ -f "pyproject.toml" ]]; then
echo "Using Poetry to run tests..."
echo "Installing dependencies if needed..."
poetry install
export GEOSERVER_URL PGHOST PGPORT PGDATABASE PGUSER PGPASSWORD PGSCHEMA
poetry run pytest $VERBOSE_FLAG --color=yes $TARGET
elif [[ -n "$VIRTUAL_ENV" ]]; then
echo "Using activated virtual environment..."
# Check if pytest is available
if ! command -v pytest &> /dev/null; then
echo "Error: pytest not found in virtual environment"
echo "Please install dependencies: pip install -e ."
exit 1
fi
export GEOSERVER_URL PGHOST PGPORT PGDATABASE PGUSER PGPASSWORD PGSCHEMA
pytest $VERBOSE_FLAG --color=yes $TARGET
else
echo "Error: Please either:"
echo " 1. Install Poetry (https://python-poetry.org/docs/#installing-with-the-official-installer) and run this script again, or"
echo " 2. Create and activate a virtual environment:"
echo " python -m venv .venv"
echo " source .venv/bin/activate # Linux/macOS"
echo " pip install -e ."
echo " ./run_tests_locally.sh"
echo ""
exit 1
fi

View File

@ -7,13 +7,13 @@ from geoservercloud import GeoServerCloud
GEOSERVER_URL = os.getenv("GEOSERVER_URL", "http://gateway:8080/geoserver/cloud") GEOSERVER_URL = os.getenv("GEOSERVER_URL", "http://gateway:8080/geoserver/cloud")
RESOURCE_DIR = Path(__file__).parent / "resources" RESOURCE_DIR = Path(__file__).parent / "resources"
# Database connection # Database connection - defaults for container, can be overridden for local testing
PGHOST = "geodatabase" PGHOST = os.getenv("PGHOST", "geodatabase")
PGPORT = 5432 PGPORT = int(os.getenv("PGPORT", "5432"))
PGDATABASE = "geodata" PGDATABASE = os.getenv("PGDATABASE", "geodata")
PGUSER = "geodata" PGUSER = os.getenv("PGUSER", "geodata")
PGPASSWORD = "geodata" PGPASSWORD = os.getenv("PGPASSWORD", "geodata")
PGSCHEMA = "test1" PGSCHEMA = os.getenv("PGSCHEMA", "test1")
WORKSPACE = "test_workspace" WORKSPACE = "test_workspace"
DATASTORE = "test_datastore" DATASTORE = "test_datastore"

View File

@ -0,0 +1,78 @@
import pytest
from geoservercloud import GeoServerCloud
from conftest import GEOSERVER_URL
def test_create_cog_coverage():
"""Test creating a COG coverage store and coverage"""
geoserver = GeoServerCloud(GEOSERVER_URL)
workspace = "cog"
store_name = "land_shallow_topo_21600_NW_cog"
coverage_name = "land_shallow_topo_NW"
# Delete and recreate workspace
geoserver.delete_workspace(workspace)
response = geoserver.create_workspace(workspace)
assert response.status_code == 201
# Create COG coverage store
store_xml = f"""<coverageStore>
<name>{store_name}</name>
<type>GeoTIFF</type>
<enabled>true</enabled>
<workspace><name>{workspace}</name></workspace>
<url>cog://https://test-data-cog-public.s3.amazonaws.com/public/land_shallow_topo_21600_NW_cog.tif</url>
<metadata>
<entry key="CogSettings.Key">
<cogSettings>
<rangeReaderSettings>HTTP</rangeReaderSettings>
</cogSettings>
</entry>
</metadata>
</coverageStore>"""
response = geoserver.post_request(
f"/rest/workspaces/{workspace}/coveragestores",
data=store_xml,
headers={"Content-Type": "application/xml"}
)
assert response.status_code == 201
# Create coverage
coverage_xml = f"""<coverage>
<name>{coverage_name}</name>
<nativeName>{store_name}</nativeName>
</coverage>"""
response = geoserver.post_request(
f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages",
data=coverage_xml,
headers={"Content-Type": "application/xml"}
)
assert response.status_code == 201
# Verify the coverage was created - try listing coverages first
list_response = geoserver.get_request(f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages.json")
if list_response.status_code != 200:
print(f"Coverage listing failed: {list_response.status_code} - {list_response.text}")
assert list_response.status_code == 200
# Check specific coverage
response = geoserver.get_request(f"/rest/workspaces/{workspace}/coveragestores/{store_name}/coverages/{coverage_name}.json")
assert response.status_code == 200
# Verify coverage properties
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
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/jpeg&SRS=EPSG:4326"
)
assert wms_response.status_code == 200
assert wms_response.headers.get("content-type").startswith("image/jpeg")
# Cleanup
geoserver.delete_workspace(workspace)

View File

@ -0,0 +1,539 @@
"""
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)

View File

@ -0,0 +1,184 @@
import os
import tempfile
import zipfile
from pathlib import Path
import pytest
from geoservercloud import GeoServerCloud
from conftest import GEOSERVER_URL
def _create_imagemosaic(geoserver, workspace, coverage, granules, indexer_content, title="ImageMosaic Coverage"):
"""Helper function to create an ImageMosaic with COG granules"""
# Delete and recreate workspace
geoserver.delete_workspace(workspace)
response = geoserver.create_workspace(workspace)
assert response.status_code == 201
# Create temporary directory for mosaic files
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
# Create indexer.properties
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
zip_file = tmp_path / f"{coverage}.zip"
with zipfile.ZipFile(zip_file, 'w') as zf:
zf.write(indexer_file, "indexer.properties")
zf.write(datastore_file, "datastore.properties")
# Create timeregex.properties if needed for time-based PropertyCollector
if "timeregex" in indexer_content:
# Regex pattern to extract date from MODIS filename format: 2018.01.01
timeregex_content = "regex=(?<=\\.)([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})(?=\\.),format=yyyy.MM.dd"
timeregex_file = tmp_path / "timeregex.properties"
timeregex_file.write_text(timeregex_content)
zf.write(timeregex_file, "timeregex.properties")
# Create empty imagemosaic
with open(zip_file, 'rb') as f:
zip_data = f.read()
response = geoserver.put_request(
f"/rest/workspaces/{workspace}/coveragestores/{coverage}/file.imagemosaic?configure=none",
data=zip_data,
headers={"Content-Type": "application/zip"}
)
assert response.status_code == 201
# Add granules
for uri in granules:
response = geoserver.post_request(
f"/rest/workspaces/{workspace}/coveragestores/{coverage}/remote.imagemosaic",
data=uri,
headers={"Content-Type": "text/plain"}
)
# Accept both 202 (Accepted) and 201 (Created) as valid responses
assert response.status_code in [201, 202]
# Initialize the store (list available coverages)
response = geoserver.get_request(
f"/rest/workspaces/{workspace}/coveragestores/{coverage}/coverages.xml?list=all"
)
assert response.status_code == 200
# Verify coverage name in response
response_text = response.text
assert f"<coverageName>{coverage}</coverageName>" in response_text
# Configure the coverage
coverage_xml = f"""<coverage>
<name>{coverage}</name>
<title>{title}</title>
<nativeName>{coverage}</nativeName>
<enabled>true</enabled>
</coverage>"""
response = geoserver.post_request(
f"/rest/workspaces/{workspace}/coveragestores/{coverage}/coverages",
data=coverage_xml,
headers={"Content-Type": "text/xml"}
)
assert response.status_code == 201
# Verify the coverage was created
response = geoserver.get_request(f"/rest/workspaces/{workspace}/coveragestores/{coverage}/coverages/{coverage}.json")
assert response.status_code == 200
# Verify coverage properties
coverage_data = response.json()["coverage"]
assert coverage_data["name"] == coverage
assert coverage_data["nativeName"] == coverage
assert coverage_data["enabled"] == True
assert coverage_data["title"] == title
# Test WMS GetMap request
wms_response = geoserver.get_request(
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage}&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326"
)
assert wms_response.status_code == 200
assert wms_response.headers.get("content-type").startswith("image/png")
return coverage_data
def test_create_imagemosaic_landshallow_topo():
"""Test creating an ImageMosaic coverage store with multiple COG granules"""
geoserver = GeoServerCloud(GEOSERVER_URL)
workspace = "s3cog_public"
coverage = "land_shallow_topo_http"
# HTTP granules
granules = [
"https://test-data-cog-public.s3.amazonaws.com/public/land_shallow_topo_21600_NE_cog.tif",
"https://test-data-cog-public.s3.amazonaws.com/public/land_shallow_topo_21600_NW_cog.tif",
"https://test-data-cog-public.s3.amazonaws.com/public/land_shallow_topo_21600_SE_cog.tif",
"https://test-data-cog-public.s3.amazonaws.com/public/land_shallow_topo_21600_SW_cog.tif",
]
# Create indexer.properties
indexer_content = f"""Cog=true
CogRangeReader=it.geosolutions.imageioimpl.plugins.cog.HttpRangeReader
Schema=*the_geom:Polygon,location:String
CanBeEmpty=true
Name={coverage}"""
_create_imagemosaic(geoserver, workspace, coverage, granules, indexer_content, "Land Shallow Topo HTTP")
# Cleanup
geoserver.delete_workspace(workspace)
@pytest.mark.skip(reason="Takes too long - enable for full testing")
def test_create_imagemosaic_modis():
"""Test creating a MODIS ImageMosaic coverage with time dimension (reproduces official tutorial)"""
geoserver = GeoServerCloud(GEOSERVER_URL)
workspace = "modis_cog"
coverage = "modisvi"
# MODIS COG datasets from NASA EarthData
modis_granules = [
"https://modis-vi-nasa.s3-us-west-2.amazonaws.com/MOD13A1.006/2018.01.01.tif",
"https://modis-vi-nasa.s3-us-west-2.amazonaws.com/MOD13A1.006/2018.01.17.tif",
]
# Create indexer.properties (based on MODIS tutorial)
indexer_content = f"""Cog=true
PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)
TimeAttribute=time
Schema=*the_geom:Polygon,location:String,time:java.util.Date
CanBeEmpty=true
Name={coverage}"""
coverage_data = _create_imagemosaic(geoserver, workspace, coverage, modis_granules, indexer_content, "MODIS Vegetation Index")
# Additional test for time-based query (since MODIS has time dimension)
time_wms_response = geoserver.get_request(
f"/wms?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&LAYERS={workspace}:{coverage}&STYLES=&BBOX=-180,-90,180,90&WIDTH=256&HEIGHT=256&FORMAT=image/png&SRS=EPSG:4326&TIME=2018-01-01"
)
assert time_wms_response.status_code == 200
assert time_wms_response.headers.get("content-type").startswith("image/png")
# Cleanup
#geoserver.delete_workspace(workspace)

View File

@ -8,6 +8,8 @@ services:
restart: always restart: always
volumes: volumes:
- ./acceptance_pg_entrypoint:/docker-entrypoint-initdb.d:ro - ./acceptance_pg_entrypoint:/docker-entrypoint-initdb.d:ro
ports:
- "5433:5432" # Expose on port 5433 to avoid conflict with local PostgreSQL
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U geodata"] test: ["CMD-SHELL", "pg_isready -U geodata"]
interval: 30s interval: 30s
@ -22,7 +24,7 @@ services:
memory: 512M memory: 512M
acceptance: acceptance:
image: acceptance:${TAG} image: geoservercloud/acceptance:latest
user: ${GS_USER} user: ${GS_USER}
depends_on: depends_on:
geodatabase: geodatabase:

View File

@ -3,7 +3,8 @@
GSUID=$(id -u) GSUID=$(id -u)
GSGID=$(id -g) GSGID=$(id -g)
GS_USER=$GSUID:$GSGID COMPOSE_PROJECT_NAME=gscloud-acceptance-datadir \ GS_USER="$GSUID:$GSGID" \
COMPOSE_PROJECT_NAME=gscloud-acceptance-datadir \
docker compose \ docker compose \
-f compose.yml \ -f compose.yml \
-f catalog-datadir.yml \ -f catalog-datadir.yml \

View File

@ -1,5 +1,9 @@
#/bin/bash #/bin/bash
GSUID=$(id -u)
GSGID=$(id -g)
GS_USER="$GSUID:$GSGID" \
COMPOSE_PROJECT_NAME=gscloud-acceptance-jdbcconfig \ COMPOSE_PROJECT_NAME=gscloud-acceptance-jdbcconfig \
docker compose \ docker compose \
-f compose.yml \ -f compose.yml \

View File

@ -1,5 +1,9 @@
#/bin/bash #/bin/bash
GSUID=$(id -u)
GSGID=$(id -g)
GS_USER="$GSUID:$GSGID" \
COMPOSE_PROJECT_NAME=gscloud-acceptance-pgconfig \ COMPOSE_PROJECT_NAME=gscloud-acceptance-pgconfig \
docker compose \ docker compose \
-f compose.yml \ -f compose.yml \

View File

@ -28,8 +28,8 @@ x-geoserver-env: &geoserver_environment
services: services:
init-datadir: init-datadir:
image: alpine:3.18.4 image: alpine:3.18.4
user: ${GS_USER} user: root
command: sh -c "cd /opt/app/data_directory; if [ ! -f global.xml ]; then tar xvzf /tmp/datadir.tgz; fi" command: sh -c "cd /opt/app/data_directory; if [ ! -f global.xml ]; then tar xvzf /tmp/datadir.tgz; fi; chown -R ${GS_USER} /opt/app/data_directory"
volumes: volumes:
- data_directory:/opt/app/data_directory - data_directory:/opt/app/data_directory
- ./catalog-datadir.tgz:/tmp/datadir.tgz - ./catalog-datadir.tgz:/tmp/datadir.tgz

View File

@ -1,9 +1,12 @@
volumes:
# geowebcache tiles shared volume
geowebcache_data:
# geoserver data files shared volume (not datadir, data)
geoserver_data:
include: include:
- ./infra.yml - ./infra.yml
volumes:
geowebcache_data:
x-gs-dependencies: &gs-dependencies x-gs-dependencies: &gs-dependencies
rabbitmq: rabbitmq:
condition: service_healthy condition: service_healthy
@ -17,8 +20,19 @@ x-gs-dependencies: &gs-dependencies
postgis: postgis:
condition: service_started condition: service_started
required: true required: true
init-test-data:
condition: service_completed_successfully
required: true
services: services:
init-test-data:
image: alpine:3.18.4
user: root
volumes:
- geoserver_data:/mnt/geoserver_data
- geowebcache_data:/mnt/geowebcache_data
- ./sampledata.tgz:/tmp/sampledata.tgz
command: sh -c "chown -R ${GS_USER} /mnt/geoserver_data /mnt/geowebcache_data && cd /mnt/geoserver_data && if [ ! -d sampledata ]; then tar xvzf /tmp/sampledata.tgz && chown -R ${GS_USER} sampledata; fi"
acl: acl:
image: ${ACL_REPOSITORY}/geoserver-acl:${ACL_TAG} image: ${ACL_REPOSITORY}/geoserver-acl:${ACL_TAG}

View File

@ -1,3 +1,7 @@
#/bin/sh #/bin/sh
GSUID=$(id -u)
GSGID=$(id -g)
GS_USER="$GSUID:$GSGID" \
docker compose -f compose.yml -f catalog-datadir.yml $@ docker compose -f compose.yml -f catalog-datadir.yml $@

View File

@ -1,3 +1,7 @@
#/bin/sh #/bin/sh
GSUID=$(id -u)
GSGID=$(id -g)
GS_USER="$GSUID:$GSGID" \
docker compose -f compose.yml -f catalog-jdbcconfig.yml $@ docker compose -f compose.yml -f catalog-jdbcconfig.yml $@

View File

@ -1,3 +1,7 @@
#/bin/sh #/bin/sh
GSUID=$(id -u)
GSGID=$(id -g)
GS_USER="$GSUID:$GSGID" \
docker compose -f compose.yml -f catalog-pgconfig.yml $@ docker compose -f compose.yml -f catalog-pgconfig.yml $@

BIN
compose/sampledata.tgz Normal file

Binary file not shown.

View File

@ -1,13 +1,14 @@
# Define reusable volume mounts as an anchor # Define reusable volume mounts as an anchor
x-geoserver-volume-mounts: &geoserver_volumes x-geoserver-volume-mounts: &geoserver_volumes
- geowebcache_data:/data/geowebcache - geowebcache_data:/mnt/geowebcache_data
- geoserver_data:/mnt/geoserver_data
# Define reusable environment variables # Define reusable environment variables
x-geoserver-env: &geoserver_environment x-geoserver-env: &geoserver_environment
SPRING_PROFILES_ACTIVE: "${GEOSERVER_DEFAULT_PROFILES}" SPRING_PROFILES_ACTIVE: "${GEOSERVER_DEFAULT_PROFILES}"
# Enable the PostGIS JNDI datasource (for development purposes) # Enable the PostGIS JNDI datasource (for development purposes)
JNDI_POSTGIS_ENABLED: true JNDI_POSTGIS_ENABLED: true
GEOWEBCACHE_CACHE_DIR: /data/geowebcache GEOWEBCACHE_CACHE_DIR: /mnt/geowebcache_data
JAVA_OPTS: "${JAVA_OPTS_GEOSERVER}" JAVA_OPTS: "${JAVA_OPTS_GEOSERVER}"
services: services: