Add more acceptance tests
2
Makefile
@ -97,4 +97,4 @@ acceptance-tests: build-acceptance
|
|||||||
|
|
||||||
.PHONY: stop-acceptance-tests
|
.PHONY: stop-acceptance-tests
|
||||||
stop-acceptance-tests: build-acceptance
|
stop-acceptance-tests: build-acceptance
|
||||||
(cd compose/ && TAG=$(TAG) GS_USER=$(UID):$(GID) docker compose $(COMPOSE_ACCEPTANCE_DATADIR_OPTIONS) down -v)
|
(cd compose/ && TAG=$(TAG) GS_USER=$(UID):$(GID) docker compose $(COMPOSE_ACCEPTANCE_DATADIR_OPTIONS) down -v)
|
||||||
|
|||||||
@ -9,7 +9,9 @@ packages = [{ include = "tests" }]
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10"
|
python = "^3.10"
|
||||||
pytest = "^8.3.3"
|
pytest = "^8.3.3"
|
||||||
|
psycopg2-binary = "^2.9.9"
|
||||||
geoservercloud = "^0.2.5"
|
geoservercloud = "^0.2.5"
|
||||||
|
sqlalchemy = "^2.0.35"
|
||||||
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
@ -1,12 +1,60 @@
|
|||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import sqlalchemy
|
||||||
from geoservercloud import GeoServerCloud
|
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"
|
||||||
|
# Database connection
|
||||||
|
PGHOST = "geodatabase"
|
||||||
|
PGPORT = 5432
|
||||||
|
PGDATABASE = "geodata"
|
||||||
|
PGUSER = "geodata"
|
||||||
|
PGPASSWORD = "geodata"
|
||||||
|
PGSCHEMA = "test1"
|
||||||
|
WORKSPACE = "test_workspace"
|
||||||
|
DATASTORE = "test_datastore"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def engine():
|
||||||
|
yield sqlalchemy.create_engine(
|
||||||
|
f"postgresql://{PGUSER}:{PGPASSWORD}@{PGHOST}:{PGPORT}/{PGDATABASE}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def db_session(engine):
|
||||||
|
with engine.connect() as connection:
|
||||||
|
connection.execute(
|
||||||
|
sqlalchemy.sql.text(f"CREATE SCHEMA IF NOT EXISTS {PGSCHEMA}")
|
||||||
|
)
|
||||||
|
connection.execute(sqlalchemy.sql.text(f"SET SEARCH_PATH = {PGSCHEMA}"))
|
||||||
|
connection.commit()
|
||||||
|
yield connection
|
||||||
|
connection.execute(
|
||||||
|
sqlalchemy.sql.text(f"DROP SCHEMA IF EXISTS {PGSCHEMA} CASCADE")
|
||||||
|
)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def geoserver():
|
def geoserver():
|
||||||
yield GeoServerCloud(GEOSERVER_URL)
|
geoserver = GeoServerCloud(GEOSERVER_URL)
|
||||||
|
geoserver.recreate_workspace(WORKSPACE, set_default_workspace=True)
|
||||||
|
geoserver.create_pg_datastore(
|
||||||
|
workspace=WORKSPACE,
|
||||||
|
datastore=DATASTORE,
|
||||||
|
pg_host=PGHOST,
|
||||||
|
pg_port=PGPORT,
|
||||||
|
pg_db=PGDATABASE,
|
||||||
|
pg_user=PGUSER,
|
||||||
|
pg_password=PGPASSWORD,
|
||||||
|
pg_schema=PGSCHEMA,
|
||||||
|
set_default_datastore=True,
|
||||||
|
)
|
||||||
|
geoserver.publish_workspace(WORKSPACE)
|
||||||
|
yield geoserver
|
||||||
|
geoserver.delete_workspace(WORKSPACE)
|
||||||
|
|||||||
15
acceptance_tests/tests/lib/utils.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def write_actual_image(response, tag):
|
||||||
|
file = Path(f"/tmp/{tag}_actual.png")
|
||||||
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(file, "wb") as fs:
|
||||||
|
fs.write(response.read())
|
||||||
|
|
||||||
|
|
||||||
|
def compare_images(dir, tag):
|
||||||
|
actual = f"/tmp/{tag}_actual.png"
|
||||||
|
expected = f"{dir}/{tag}_expected.png"
|
||||||
|
with open(actual, "rb") as fs1, open(expected, "rb") as fs2:
|
||||||
|
assert fs1.read() == fs2.read()
|
||||||
BIN
acceptance_tests/tests/resources/getmap_expected.png
Normal file
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 670 B |
36
acceptance_tests/tests/resources/localized_labels.sld
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StyledLayerDescriptor version="1.0.0"
|
||||||
|
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
|
||||||
|
xmlns="http://www.opengis.net/sld"
|
||||||
|
xmlns:ogc="http://www.opengis.net/ogc"
|
||||||
|
xmlns:se="http://www.opengis.net/se"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<NamedLayer>
|
||||||
|
<Name>localized_labels</Name>
|
||||||
|
<UserStyle>
|
||||||
|
<Name>localized_labels</Name>
|
||||||
|
<FeatureTypeStyle>
|
||||||
|
<Rule>
|
||||||
|
<Name>Localized labels</Name>
|
||||||
|
<TextSymbolizer>
|
||||||
|
<Label>
|
||||||
|
<ogc:Function name="Recode">
|
||||||
|
<ogc:Function name="language"/>
|
||||||
|
<ogc:Literal/>
|
||||||
|
<ogc:PropertyName>label_default</ogc:PropertyName>
|
||||||
|
<ogc:Literal>de</ogc:Literal>
|
||||||
|
<ogc:PropertyName>label_de</ogc:PropertyName>
|
||||||
|
<ogc:Literal>fr</ogc:Literal>
|
||||||
|
<ogc:PropertyName>label_fr</ogc:PropertyName>
|
||||||
|
</ogc:Function>
|
||||||
|
</Label>
|
||||||
|
<Fill>
|
||||||
|
<CssParameter name="fill">#000000</CssParameter>
|
||||||
|
</Fill>
|
||||||
|
</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
</FeatureTypeStyle>
|
||||||
|
</UserStyle>
|
||||||
|
</NamedLayer>
|
||||||
|
</StyledLayerDescriptor>
|
||||||
37
acceptance_tests/tests/resources/localized_no_default.sld
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StyledLayerDescriptor version="1.0.0"
|
||||||
|
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
|
||||||
|
xmlns="http://www.opengis.net/sld"
|
||||||
|
xmlns:ogc="http://www.opengis.net/ogc"
|
||||||
|
xmlns:se="http://www.opengis.net/se"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<NamedLayer>
|
||||||
|
<Name>localized_style</Name>
|
||||||
|
<UserStyle>
|
||||||
|
<Name>localized_no_default</Name>
|
||||||
|
<FeatureTypeStyle>
|
||||||
|
<Rule>
|
||||||
|
<Name>Localized, no default value</Name>
|
||||||
|
<Title>
|
||||||
|
<Localized lang="en">English</Localized>
|
||||||
|
<Localized lang="de">Deutsch</Localized>
|
||||||
|
<Localized lang="fr">Français</Localized>
|
||||||
|
<Localized lang="it">Italiano</Localized>
|
||||||
|
</Title>
|
||||||
|
<PointSymbolizer>
|
||||||
|
<Graphic>
|
||||||
|
<Mark>
|
||||||
|
<WellKnownName>circle</WellKnownName>
|
||||||
|
<Fill>
|
||||||
|
<CssParameter name="fill">#FF0000</CssParameter>
|
||||||
|
</Fill>
|
||||||
|
</Mark>
|
||||||
|
<Size>6</Size>
|
||||||
|
</Graphic>
|
||||||
|
</PointSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
</FeatureTypeStyle>
|
||||||
|
</UserStyle>
|
||||||
|
</NamedLayer>
|
||||||
|
</StyledLayerDescriptor>
|
||||||
37
acceptance_tests/tests/resources/localized_with_default.sld
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StyledLayerDescriptor version="1.0.0"
|
||||||
|
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
|
||||||
|
xmlns="http://www.opengis.net/sld"
|
||||||
|
xmlns:ogc="http://www.opengis.net/ogc"
|
||||||
|
xmlns:se="http://www.opengis.net/se"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<NamedLayer>
|
||||||
|
<Name>localized_style</Name>
|
||||||
|
<UserStyle>
|
||||||
|
<Name>localized_with_default</Name>
|
||||||
|
<FeatureTypeStyle>
|
||||||
|
<Rule>
|
||||||
|
<Name>Localized, with default value</Name>
|
||||||
|
<Title>
|
||||||
|
Default label<Localized lang="en">English</Localized>
|
||||||
|
<Localized lang="de">Deutsch</Localized>
|
||||||
|
<Localized lang="fr">Français</Localized>
|
||||||
|
<Localized lang="it">Italiano</Localized>
|
||||||
|
</Title>
|
||||||
|
<PointSymbolizer>
|
||||||
|
<Graphic>
|
||||||
|
<Mark>
|
||||||
|
<WellKnownName>circle</WellKnownName>
|
||||||
|
<Fill>
|
||||||
|
<CssParameter name="fill">#FF0000</CssParameter>
|
||||||
|
</Fill>
|
||||||
|
</Mark>
|
||||||
|
<Size>6</Size>
|
||||||
|
</Graphic>
|
||||||
|
</PointSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
</FeatureTypeStyle>
|
||||||
|
</UserStyle>
|
||||||
|
</NamedLayer>
|
||||||
|
</StyledLayerDescriptor>
|
||||||
16
acceptance_tests/tests/resources/wfs_payload.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Transaction xmlns="http://www.opengis.net/wfs" service="WFS" version="1.1.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
|
||||||
|
<Insert>
|
||||||
|
<test_wfs xmlns="test_wfs">
|
||||||
|
<geom>
|
||||||
|
<Point xmlns="http://www.opengis.net/gml" srsName="EPSG:2056">
|
||||||
|
<pos srsDimension="2">2600000.0 1200000.0</pos>
|
||||||
|
</Point>
|
||||||
|
</geom>
|
||||||
|
<timestamp>2024-05-13T08:14:48.763Z</timestamp>
|
||||||
|
<id>10</id>
|
||||||
|
<title>Title</title>
|
||||||
|
</test_wfs>
|
||||||
|
</Insert>
|
||||||
|
</Transaction>
|
||||||
24
acceptance_tests/tests/test_datastore.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from conftest import PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, PGSCHEMA
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_get_and_delete_datastore(geoserver):
|
||||||
|
workspace = datastore = "test_create_pg_datastore"
|
||||||
|
geoserver.create_workspace(workspace)
|
||||||
|
response = geoserver.create_pg_datastore(
|
||||||
|
workspace=workspace,
|
||||||
|
datastore=datastore,
|
||||||
|
pg_host=PGHOST,
|
||||||
|
pg_port=PGPORT,
|
||||||
|
pg_db=PGDATABASE,
|
||||||
|
pg_user=PGUSER,
|
||||||
|
pg_password=PGPASSWORD,
|
||||||
|
pg_schema=PGSCHEMA,
|
||||||
|
set_default_datastore=True,
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
response = geoserver.get_request(
|
||||||
|
f"/rest/workspaces/{workspace}/datastores/{datastore}.json"
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
response = geoserver.delete_workspace(workspace)
|
||||||
|
assert response.status_code == 200
|
||||||
47
acceptance_tests/tests/test_gwc.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
WORKSPACE = "test_gwc"
|
||||||
|
WMTS_STORE = "test_gwc_store"
|
||||||
|
WMTS_LAYER = "ch.swisstopo.swissimage"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_with_gwc_layers(geoserver):
|
||||||
|
geoserver.create_workspace(WORKSPACE)
|
||||||
|
geoserver.create_wmts_store(
|
||||||
|
WORKSPACE,
|
||||||
|
WMTS_STORE,
|
||||||
|
capabilities="https://wmts.geo.admin.ch/EPSG/4326/1.0.0/WMTSCapabilities.xml",
|
||||||
|
)
|
||||||
|
geoserver.create_wmts_layer(WORKSPACE, WMTS_STORE, WMTS_LAYER)
|
||||||
|
geoserver.get_request(
|
||||||
|
f"/rest/workspaces/{WORKSPACE}/wmtsstores/{WMTS_STORE}/layers/{WMTS_LAYER}.json"
|
||||||
|
)
|
||||||
|
response = geoserver.publish_gwc_layer(WORKSPACE, WMTS_LAYER)
|
||||||
|
assert response.status_code == 200
|
||||||
|
yield geoserver
|
||||||
|
geoserver.delete_workspace(WORKSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
def test_tile_cache(geoserver_with_gwc_layers):
|
||||||
|
|
||||||
|
response = geoserver_with_gwc_layers.get_tile(
|
||||||
|
format="image/png",
|
||||||
|
layer=f"{WORKSPACE}:{WMTS_LAYER}",
|
||||||
|
tile_matrix_set="EPSG:4326",
|
||||||
|
tile_matrix="EPSG:4326:9",
|
||||||
|
row=122,
|
||||||
|
column=534,
|
||||||
|
)
|
||||||
|
assert response.info().get("Content-Type") == "image/png"
|
||||||
|
assert response.info().get("Geowebcache-Cache-Result") == "MISS"
|
||||||
|
|
||||||
|
response = geoserver_with_gwc_layers.get_tile(
|
||||||
|
format="image/png",
|
||||||
|
layer=f"{WORKSPACE}:{WMTS_LAYER}",
|
||||||
|
tile_matrix_set="EPSG:4326",
|
||||||
|
tile_matrix="EPSG:4326:9",
|
||||||
|
row=122,
|
||||||
|
column=534,
|
||||||
|
)
|
||||||
|
assert response.info().get("Geowebcache-Cache-Result") == "HIT"
|
||||||
417
acceptance_tests/tests/test_i18n.py
Executable file
@ -0,0 +1,417 @@
|
|||||||
|
#!/bin/env python
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from conftest import RESOURCE_DIR, WORKSPACE
|
||||||
|
from lib.utils import compare_images, write_actual_image
|
||||||
|
from requests.exceptions import JSONDecodeError
|
||||||
|
from sqlalchemy.sql import text
|
||||||
|
|
||||||
|
|
||||||
|
def international_title(default=True, de=True, fr=True, it=True, rm=True):
|
||||||
|
title = {}
|
||||||
|
if default:
|
||||||
|
title["default"] = "Default title"
|
||||||
|
if de:
|
||||||
|
title["de"] = "Punkte"
|
||||||
|
if fr:
|
||||||
|
title["fr"] = "Points"
|
||||||
|
if it:
|
||||||
|
title["it"] = "Punti"
|
||||||
|
if rm:
|
||||||
|
title["rm"] = "Puncts"
|
||||||
|
return title
|
||||||
|
|
||||||
|
|
||||||
|
def assert_legend(geoserver, style, language, expected_label):
|
||||||
|
response = geoserver.get_legend_graphic(
|
||||||
|
"i18n_legend",
|
||||||
|
format="application/json",
|
||||||
|
language=language,
|
||||||
|
style=style,
|
||||||
|
workspace=WORKSPACE,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
label = response.json()["Legend"][0]["rules"][0]["title"]
|
||||||
|
assert label == expected_label
|
||||||
|
except (KeyError, JSONDecodeError):
|
||||||
|
print(f"Invalid response for language '{language}:'\n{response.content}")
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_with_i18n_layers(geoserver):
|
||||||
|
|
||||||
|
# Create feature type with all languages
|
||||||
|
layer1 = "layer_all_languages"
|
||||||
|
title1 = international_title(default=True, de=True, fr=True, it=True, rm=True)
|
||||||
|
geoserver.create_feature_type(layer1, title=title1, epsg=2056)
|
||||||
|
|
||||||
|
# Create feature type without Rumantsch
|
||||||
|
layer2 = "layer_no_rumantsch"
|
||||||
|
title2 = international_title(default=True, de=True, fr=True, it=True, rm=False)
|
||||||
|
geoserver.create_feature_type(layer2, title=title2, epsg=2056)
|
||||||
|
|
||||||
|
# Create feature type without default language nor Rumantsch
|
||||||
|
layer3 = "layer_no_default_no_rumantsch"
|
||||||
|
title3 = international_title(default=False, de=True, fr=True, it=True, rm=False)
|
||||||
|
geoserver.create_feature_type(layer3, title=title3, epsg=2056)
|
||||||
|
|
||||||
|
yield geoserver
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_default_locale_it(geoserver_with_i18n_layers):
|
||||||
|
geoserver_with_i18n_layers.set_default_locale_for_service(WORKSPACE, "it")
|
||||||
|
yield geoserver_with_i18n_layers
|
||||||
|
geoserver_with_i18n_layers.unset_default_locale_for_service(WORKSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_i18n_legend_layer(geoserver):
|
||||||
|
geoserver.create_workspace(WORKSPACE, set_default_workspace=True)
|
||||||
|
geoserver.create_feature_type("i18n_legend", epsg=2056)
|
||||||
|
geoserver.create_style_from_file(
|
||||||
|
"localized_with_default.sld",
|
||||||
|
f"{RESOURCE_DIR}/localized_with_default.sld",
|
||||||
|
workspace=WORKSPACE,
|
||||||
|
)
|
||||||
|
geoserver.create_style_from_file(
|
||||||
|
"localized_no_default.sld",
|
||||||
|
f"{RESOURCE_DIR}/localized_no_default.sld",
|
||||||
|
workspace=WORKSPACE,
|
||||||
|
)
|
||||||
|
yield geoserver
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def geoserver_i18n_legend_layer_and_default_locale_it(geoserver_i18n_legend_layer):
|
||||||
|
geoserver_i18n_legend_layer.set_default_locale_for_service(WORKSPACE, "it")
|
||||||
|
yield geoserver_i18n_legend_layer
|
||||||
|
geoserver_i18n_legend_layer.unset_default_locale_for_service(WORKSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_i18n_label_layer(geoserver, db_session):
|
||||||
|
feature_type = "i18n_labels"
|
||||||
|
style = "localized_labels"
|
||||||
|
file = f"{RESOURCE_DIR}/{style}.sld"
|
||||||
|
attributes = {
|
||||||
|
"geom": {"type": "Point", "required": True},
|
||||||
|
"label_default": {"type": "string", "required": False},
|
||||||
|
"label_de": {"type": "string", "required": False},
|
||||||
|
"label_fr": {"type": "string", "required": False},
|
||||||
|
}
|
||||||
|
geoserver.create_feature_type(feature_type, attributes=attributes, epsg=2056)
|
||||||
|
geoserver.create_style_from_file(style, file, workspace=WORKSPACE)
|
||||||
|
# Feature with labels in German, French and a default value
|
||||||
|
db_session.execute(
|
||||||
|
text(
|
||||||
|
f"INSERT INTO {feature_type} (geom, label_default, label_de, label_fr) VALUES "
|
||||||
|
"(public.ST_SetSRID(public.ST_MakePoint(2600000, 1200000), 2056), 'Default label', 'Deutsches Label', 'Étiquette française')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Feature with labels in German, French and no default value
|
||||||
|
db_session.execute(
|
||||||
|
text(
|
||||||
|
f"INSERT INTO {feature_type} (geom, label_de, label_fr) VALUES "
|
||||||
|
"(public.ST_SetSRID(public.ST_MakePoint(2700000, 1300000), 2056), 'Deutsches Label', 'Étiquette française')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
db_session.commit()
|
||||||
|
yield geoserver
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def geoserver_i18n_label_default_locale_fr(geoserver_i18n_label_layer):
|
||||||
|
geoserver_i18n_label_layer.set_default_locale_for_service(WORKSPACE, "fr")
|
||||||
|
yield geoserver_i18n_label_layer
|
||||||
|
geoserver_i18n_label_layer.unset_default_locale_for_service(WORKSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_titles",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"de",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Punkte",
|
||||||
|
"layer_no_rumantsch": "Punkte",
|
||||||
|
"layer_no_default_no_rumantsch": "Punkte",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"de,fr",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Punkte",
|
||||||
|
"layer_no_rumantsch": "Punkte",
|
||||||
|
"layer_no_default_no_rumantsch": "Punkte",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"fr,de",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Points",
|
||||||
|
"layer_no_rumantsch": "Points",
|
||||||
|
"layer_no_default_no_rumantsch": "Points",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"rm",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Puncts",
|
||||||
|
"layer_no_rumantsch": "Default title",
|
||||||
|
"layer_no_default_no_rumantsch": "DID NOT FIND i18n CONTENT FOR THIS ELEMENT",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"en",
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Default title",
|
||||||
|
"layer_no_rumantsch": "Default title",
|
||||||
|
"layer_no_default_no_rumantsch": "Punkte",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"foobar",
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_i18n_layers(geoserver_with_i18n_layers, language, expected_titles):
|
||||||
|
capabilities = geoserver_with_i18n_layers.get_wms_layers(WORKSPACE, language)
|
||||||
|
layers = capabilities.get("Layer")
|
||||||
|
if type(layers) is list:
|
||||||
|
for expected_layer, expected_title in expected_titles.items():
|
||||||
|
actual_layer = next(
|
||||||
|
(layer for layer in layers if layer["Name"] == expected_layer), {}
|
||||||
|
)
|
||||||
|
assert actual_layer.get("Title") == expected_title
|
||||||
|
else:
|
||||||
|
print(capabilities)
|
||||||
|
assert expected_titles == {}
|
||||||
|
assert "ServiceExceptionReport" in capabilities
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_titles",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"de",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Punkte",
|
||||||
|
"layer_no_rumantsch": "Punkte",
|
||||||
|
"layer_no_default_no_rumantsch": "Punkte",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"rm",
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Puncts",
|
||||||
|
"layer_no_rumantsch": "Default title",
|
||||||
|
"layer_no_default_no_rumantsch": "DID NOT FIND i18n CONTENT FOR THIS ELEMENT",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"en",
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
"layer_all_languages": "Punti",
|
||||||
|
"layer_no_rumantsch": "Punti",
|
||||||
|
"layer_no_default_no_rumantsch": "Punti",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.skip(reason="Default locale is ignored in gs-cloud 1.6.1")
|
||||||
|
def test_i18n_layers_default_locale(
|
||||||
|
geoserver_default_locale_it, language, expected_titles
|
||||||
|
):
|
||||||
|
layers = geoserver_default_locale_it.get_wms_layers(WORKSPACE, language)
|
||||||
|
if type(layers) is list:
|
||||||
|
for expected_layer, expected_title in expected_titles.items():
|
||||||
|
actual_layer = next(
|
||||||
|
(layer for layer in layers if layer["Name"] == expected_layer), {}
|
||||||
|
)
|
||||||
|
print(actual_layer["Name"])
|
||||||
|
assert actual_layer.get("Title") == expected_title
|
||||||
|
else:
|
||||||
|
print(layers)
|
||||||
|
assert expected_titles == {}
|
||||||
|
assert "ServiceExceptionReport" in layers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_label",
|
||||||
|
[
|
||||||
|
("en", "English"),
|
||||||
|
("de", "Deutsch"),
|
||||||
|
("fr", "Français"),
|
||||||
|
("it", "Italiano"),
|
||||||
|
("rm", "Default label"),
|
||||||
|
(None, "Default label"),
|
||||||
|
("ru", "Default label"),
|
||||||
|
("foobar", "Default label"),
|
||||||
|
("it,fr,de", "Default label"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_i18n_legend_with_default_value(
|
||||||
|
geoserver_i18n_legend_layer, language, expected_label
|
||||||
|
):
|
||||||
|
assert_legend(
|
||||||
|
geoserver_i18n_legend_layer,
|
||||||
|
"localized_with_default",
|
||||||
|
language,
|
||||||
|
expected_label,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_label",
|
||||||
|
[
|
||||||
|
("it", "Italiano"),
|
||||||
|
("rm", ""),
|
||||||
|
(None, ""),
|
||||||
|
("ru", ""),
|
||||||
|
("foobar", ""),
|
||||||
|
("it,fr,de", ""),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_i18n_legend_no_default_value(
|
||||||
|
geoserver_i18n_legend_layer, language, expected_label
|
||||||
|
):
|
||||||
|
|
||||||
|
assert_legend(
|
||||||
|
geoserver_i18n_legend_layer,
|
||||||
|
"localized_no_default",
|
||||||
|
language,
|
||||||
|
expected_label,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_label",
|
||||||
|
[
|
||||||
|
("en", "English"),
|
||||||
|
("de", "Deutsch"),
|
||||||
|
("fr", "Français"),
|
||||||
|
("it", "Italiano"),
|
||||||
|
("rm", "Default label"),
|
||||||
|
(None, "Default label"),
|
||||||
|
("ru", "Default label"),
|
||||||
|
("foobar", "Default label"),
|
||||||
|
("it,fr,de", "Default label"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_i18n_legend_with_default_value_and_default_locale(
|
||||||
|
geoserver_i18n_legend_layer_and_default_locale_it, language, expected_label
|
||||||
|
):
|
||||||
|
assert_legend(
|
||||||
|
geoserver_i18n_legend_layer_and_default_locale_it,
|
||||||
|
"localized_with_default",
|
||||||
|
language,
|
||||||
|
expected_label,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"language,expected_label",
|
||||||
|
[
|
||||||
|
("it", "Italiano"),
|
||||||
|
("rm", ""),
|
||||||
|
(None, ""),
|
||||||
|
("ru", ""),
|
||||||
|
("foobar", ""),
|
||||||
|
("it,fr,de", ""),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_i18n_legend_no_default_value_default_locale(
|
||||||
|
geoserver_i18n_legend_layer_and_default_locale_it, language, expected_label
|
||||||
|
):
|
||||||
|
|
||||||
|
assert_legend(
|
||||||
|
geoserver_i18n_legend_layer_and_default_locale_it,
|
||||||
|
"localized_no_default",
|
||||||
|
language,
|
||||||
|
expected_label,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language", ["de", "fr", "it", None, ""])
|
||||||
|
def test_i18n_labels(geoserver_i18n_label_layer, language):
|
||||||
|
|
||||||
|
response = geoserver_i18n_label_layer.get_map(
|
||||||
|
layers=["i18n_labels"],
|
||||||
|
bbox=(2599999.5, 1199999.5, 2600000.5, 1200000.5),
|
||||||
|
size=(300, 100),
|
||||||
|
format="image/png",
|
||||||
|
transparent=False,
|
||||||
|
styles=["localized_labels"],
|
||||||
|
language=language,
|
||||||
|
)
|
||||||
|
|
||||||
|
file_root = f"labels/no_default_locale/default_value/language_{language}"
|
||||||
|
write_actual_image(response, file_root)
|
||||||
|
compare_images(RESOURCE_DIR, file_root)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language", ["it", "", None])
|
||||||
|
def test_i18n_labels_no_default_value(geoserver_i18n_label_layer, language):
|
||||||
|
|
||||||
|
response = geoserver_i18n_label_layer.get_map(
|
||||||
|
layers=["i18n_labels"],
|
||||||
|
bbox=(2699999.5, 1299999.5, 2700000.5, 1300000.5),
|
||||||
|
size=(300, 100),
|
||||||
|
format="image/png",
|
||||||
|
transparent=False,
|
||||||
|
styles=["localized_labels"],
|
||||||
|
language=language,
|
||||||
|
)
|
||||||
|
|
||||||
|
file_root = f"labels/no_default_locale/no_default_value/language_{language}"
|
||||||
|
write_actual_image(response, file_root)
|
||||||
|
compare_images(RESOURCE_DIR, file_root)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language", ["de", "fr", "it", None, ""])
|
||||||
|
def test_i18n_labels_default_locale(geoserver_i18n_label_default_locale_fr, language):
|
||||||
|
|
||||||
|
response = geoserver_i18n_label_default_locale_fr.get_map(
|
||||||
|
layers=["i18n_labels"],
|
||||||
|
bbox=(2599999.5, 1199999.5, 2600000.5, 1200000.5),
|
||||||
|
size=(300, 100),
|
||||||
|
format="image/png",
|
||||||
|
transparent=False,
|
||||||
|
styles=["localized_labels"],
|
||||||
|
language=language,
|
||||||
|
)
|
||||||
|
|
||||||
|
file_root = f"labels/default_locale/default_value/language_{language}"
|
||||||
|
write_actual_image(response, file_root)
|
||||||
|
compare_images(RESOURCE_DIR, file_root)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language", ["it", "", None])
|
||||||
|
def test_i18n_labels_no_default_value_default_locale(
|
||||||
|
geoserver_i18n_label_default_locale_fr, language
|
||||||
|
):
|
||||||
|
|
||||||
|
response = geoserver_i18n_label_default_locale_fr.get_map(
|
||||||
|
layers=["i18n_labels"],
|
||||||
|
bbox=(2699999.5, 1299999.5, 2700000.5, 1300000.5),
|
||||||
|
size=(300, 100),
|
||||||
|
format="image/png",
|
||||||
|
transparent=False,
|
||||||
|
styles=["localized_labels"],
|
||||||
|
language=language,
|
||||||
|
)
|
||||||
|
|
||||||
|
file_root = f"labels/default_locale/no_default_value/language_{language}"
|
||||||
|
write_actual_image(response, file_root)
|
||||||
|
compare_images(RESOURCE_DIR, file_root)
|
||||||
76
acceptance_tests/tests/test_wfs.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
from conftest import (
|
||||||
|
PGDATABASE,
|
||||||
|
PGHOST,
|
||||||
|
PGPASSWORD,
|
||||||
|
PGPORT,
|
||||||
|
PGSCHEMA,
|
||||||
|
PGUSER,
|
||||||
|
RESOURCE_DIR,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_wfs(geoserver):
|
||||||
|
workspace = datastore = feature_type = "test_wfs"
|
||||||
|
attributes = {
|
||||||
|
"geom": {
|
||||||
|
"type": "Point",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "datetime",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response = geoserver.create_workspace(workspace, set_default_workspace=True)
|
||||||
|
assert response.status_code == 201
|
||||||
|
response = geoserver.create_pg_datastore(
|
||||||
|
workspace=workspace,
|
||||||
|
datastore=datastore,
|
||||||
|
pg_host=PGHOST,
|
||||||
|
pg_port=PGPORT,
|
||||||
|
pg_db=PGDATABASE,
|
||||||
|
pg_user=PGUSER,
|
||||||
|
pg_password=PGPASSWORD,
|
||||||
|
pg_schema=PGSCHEMA,
|
||||||
|
set_default_datastore=True,
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
response = geoserver.create_feature_type(
|
||||||
|
feature_type, attributes=attributes, epsg=2056
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
# Post a feature through a WFS request
|
||||||
|
with open(f"{RESOURCE_DIR}/wfs_payload.xml") as file:
|
||||||
|
data = file.read()
|
||||||
|
response = geoserver.post_request(f"/{workspace}/wfs/", data=data)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
# GetFeature request
|
||||||
|
feature_collection = geoserver.get_feature(workspace, feature_type)
|
||||||
|
assert type(feature_collection) is dict
|
||||||
|
assert type(feature_collection.get("features")) is list
|
||||||
|
feature = feature_collection["features"][0]
|
||||||
|
properties = feature.get("properties")
|
||||||
|
assert properties.get("id") == 10
|
||||||
|
assert properties.get("title") == "Title"
|
||||||
|
assert properties.get("timestamp") == "2024-05-13T08:14:48.763Z"
|
||||||
|
assert feature.get("geometry", {}) == {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [2600000, 1200000],
|
||||||
|
}
|
||||||
|
assert feature_collection.get("crs") == {
|
||||||
|
"type": "name",
|
||||||
|
"properties": {"name": "urn:ogc:def:crs:EPSG::2056"},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = geoserver.delete_workspace(workspace)
|
||||||
|
assert response.status_code == 200
|
||||||
128
acceptance_tests/tests/test_wms.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from conftest import (
|
||||||
|
PGDATABASE,
|
||||||
|
PGHOST,
|
||||||
|
PGPASSWORD,
|
||||||
|
PGPORT,
|
||||||
|
PGSCHEMA,
|
||||||
|
PGUSER,
|
||||||
|
RESOURCE_DIR,
|
||||||
|
)
|
||||||
|
from lib.utils import compare_images, write_actual_image
|
||||||
|
from sqlalchemy.sql import text
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_and_feature_type_and_get_map(db_session, geoserver):
|
||||||
|
workspace = datastore = feature_type = "test_create_feature_type"
|
||||||
|
geoserver.create_workspace(workspace, set_default_workspace=True)
|
||||||
|
geoserver.create_pg_datastore(
|
||||||
|
workspace=workspace,
|
||||||
|
datastore=datastore,
|
||||||
|
pg_host=PGHOST,
|
||||||
|
pg_port=PGPORT,
|
||||||
|
pg_db=PGDATABASE,
|
||||||
|
pg_user=PGUSER,
|
||||||
|
pg_password=PGPASSWORD,
|
||||||
|
pg_schema=PGSCHEMA,
|
||||||
|
set_default_datastore=True,
|
||||||
|
)
|
||||||
|
response = geoserver.create_feature_type(
|
||||||
|
feature_type,
|
||||||
|
epsg=2056,
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
# Create feature
|
||||||
|
db_session.execute(
|
||||||
|
text(
|
||||||
|
f"INSERT INTO {feature_type} (geom) VALUES (public.ST_SetSRID(public.ST_MakePoint(2600000, 1200000), 2056))"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
# GetMap request
|
||||||
|
response = geoserver.get_map(
|
||||||
|
layers=[feature_type],
|
||||||
|
bbox=(2599999.5, 1199999.5, 2600000.5, 1200000.5),
|
||||||
|
size=(40, 40),
|
||||||
|
format="image/png",
|
||||||
|
transparent=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
file_root = f"getmap"
|
||||||
|
write_actual_image(response, file_root)
|
||||||
|
compare_images(RESOURCE_DIR, file_root)
|
||||||
|
|
||||||
|
geoserver.delete_workspace(workspace)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_feature_info(db_session, geoserver):
|
||||||
|
workspace = datastore = feature_type = "test_get_feature_info"
|
||||||
|
attributes = {
|
||||||
|
"geom": {
|
||||||
|
"type": "Point",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response = geoserver.create_workspace(workspace, set_default_workspace=True)
|
||||||
|
assert response.status_code == 201
|
||||||
|
response = geoserver.create_pg_datastore(
|
||||||
|
workspace=workspace,
|
||||||
|
datastore=datastore,
|
||||||
|
pg_host=PGHOST,
|
||||||
|
pg_port=PGPORT,
|
||||||
|
pg_db=PGDATABASE,
|
||||||
|
pg_user=PGUSER,
|
||||||
|
pg_password=PGPASSWORD,
|
||||||
|
pg_schema=PGSCHEMA,
|
||||||
|
set_default_datastore=True,
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
response = geoserver.create_feature_type(
|
||||||
|
feature_type, attributes=attributes, epsg=2056
|
||||||
|
)
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
# Create feature
|
||||||
|
db_session.execute(
|
||||||
|
text(
|
||||||
|
f"INSERT INTO {feature_type} (geom, label) VALUES "
|
||||||
|
"(public.ST_SetSRID(public.ST_MakePoint(2600000, 1200000), 2056), 'Label')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
# Test that layer is published
|
||||||
|
response = geoserver.get_request(f"/rest/layers/{workspace}:{feature_type}.json")
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
# GetFeatureInfo request
|
||||||
|
response = geoserver.get_feature_info(
|
||||||
|
layers=[feature_type],
|
||||||
|
bbox=(2599999.5, 1199999.5, 2600000.5, 1200000.5),
|
||||||
|
size=(40, 40),
|
||||||
|
info_format="application/json",
|
||||||
|
xy=(20, 20),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.read().decode("utf-8"))
|
||||||
|
|
||||||
|
feature = data.get("features", [])[0]
|
||||||
|
assert feature
|
||||||
|
assert feature.get("properties").get("label") == "Label"
|
||||||
|
assert feature.get("geometry") == {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [2600000, 1200000],
|
||||||
|
}
|
||||||
|
assert data.get("crs") == {
|
||||||
|
"type": "name",
|
||||||
|
"properties": {"name": "urn:ogc:def:crs:EPSG::2056"},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = geoserver.delete_workspace(workspace)
|
||||||
|
assert response.status_code == 200
|
||||||
@ -1,3 +1,4 @@
|
|||||||
\c geodata
|
\c geodata
|
||||||
CREATE SCHEMA IF NOT EXISTS test1;
|
CREATE SCHEMA IF NOT EXISTS test1;
|
||||||
CREATE SCHEMA IF NOT EXISTS test2;
|
CREATE SCHEMA IF NOT EXISTS test2;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||||
|
|||||||