diff --git a/.github/actions/setup-postgresql-windows/action.yml b/.github/actions/setup-postgresql-windows/action.yml new file mode 100644 index 00000000..fab18778 --- /dev/null +++ b/.github/actions/setup-postgresql-windows/action.yml @@ -0,0 +1,95 @@ +name: 'Setup Postgresql and Postgis on Windows' + +description: 'Installs PostgreSQL and PostGIS for Windows and configures it for CI tests' + +inputs: + postgresql-version: + description: 'Version of PostgreSQL to install' + required: true + +runs: + using: "composite" + + steps: + - name: Set up PostgreSQL variables + shell: pwsh + run: | + $version = "${{ inputs.postgresql-version }}" + $root = "C:\Program Files\PostgreSQL\$version" + $bin = "$root\bin" + + echo "PGROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "PGBIN=$bin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + echo "$bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Decide Postgis version (Windows) + id: postgis-ver + shell: pwsh + run: | + echo "PowerShell version: ${PSVersionTable.PSVersion}" + $PG_VERSION = Split-Path $env:PGROOT -Leaf + $postgis_page = "https://download.osgeo.org/postgis/windows/pg$PG_VERSION" + echo "Detecting PostGIS version from $postgis_page for PostgreSQL $PG_VERSION" + $pgis_bundle = (Invoke-WebRequest -Uri $postgis_page -ErrorAction Stop).Links.Where({$_.href -match "^postgis.*zip$"}).href + if (!$pgis_bundle) { + Write-Error "Could not find latest PostGIS version in $postgis_page that would match ^postgis.*zip$ pattern" + exit 1 + } + $pgis_bundle = [IO.Path]::ChangeExtension($pgis_bundle, [NullString]::Value) + $pgis_bundle_url = "$postgis_page/$pgis_bundle.zip" + Add-Content $env:GITHUB_OUTPUT "postgis_file=$pgis_bundle" + Add-Content $env:GITHUB_OUTPUT "postgis_bundle_url=$pgis_bundle_url" + + - uses: actions/cache@v4 + with: + path: | + C:/postgis.zip + key: postgis-cache-${{ steps.postgis-ver.outputs.postgis_file }} + + - name: Download postgis + shell: pwsh + run: | + if (!(Test-Path "C:\postgis.zip")){(new-object net.webclient).DownloadFile($env:PGIS_BUNDLE_URL, "c:\postgis.zip")} + if (Test-path "c:\postgis_archive"){Remove-Item "c:\postgis_archive" -Recurse -Force} + 7z x c:\postgis.zip -oc:\postgis_archive + env: + PGIS_BUNDLE_URL: ${{ steps.postgis-ver.outputs.postgis_bundle_url }} + + - name: Install postgis + shell: bash + run: | + echo "Root: $PGROOT, Bin: $PGBIN" + cp -r c:/postgis_archive/postgis-bundle-*/* "$PGROOT" + + - name: Start PostgreSQL on Windows + run: | + $pgService = Get-Service -Name postgresql* + Set-Service -InputObject $pgService -Status running -StartupType automatic + Start-Process -FilePath "$env:PGBIN\pg_isready" -Wait -PassThru + shell: pwsh + + - name: Adapt postgresql configuration + shell: pwsh + env: + PGPASSWORD: root + run: | + & "$env:PGBIN\psql" -U postgres -d postgres -c "ALTER SYSTEM SET fsync = 'off';" + & "$env:PGBIN\psql" -U postgres -d postgres -c "ALTER SYSTEM SET synchronous_commit = 'off';" + & "$env:PGBIN\psql" -U postgres -d postgres -c "ALTER SYSTEM SET full_page_writes = 'off';" + & "$env:PGBIN\psql" -U postgres -d postgres -c "ALTER SYSTEM SET shared_buffers = '1GB';" + & "$env:PGBIN\psql" -U postgres -d postgres -c "ALTER SYSTEM SET port = 5432;" + + Restart-Service -Name postgresql* + Start-Process -FilePath "$env:PGBIN\pg_isready" -Wait -PassThru + + - name: Setup database users + shell: pwsh + env: + PGPASSWORD: root + run: | + & "$env:PGBIN\createuser" -U postgres -S www-data + & "$env:PGBIN\createuser" -U postgres -s runner + + + diff --git a/.github/actions/setup-postgresql/action.yml b/.github/actions/setup-postgresql/action.yml index 7a9590c1..b868546b 100644 --- a/.github/actions/setup-postgresql/action.yml +++ b/.github/actions/setup-postgresql/action.yml @@ -1,5 +1,7 @@ name: 'Setup Postgresql and Postgis' +description: 'Installs PostgreSQL and PostGIS and configures it for CI tests' + inputs: postgresql-version: description: 'Version of PostgreSQL to install' diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index ff89bfbf..487753a7 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -140,6 +140,65 @@ jobs: ../venv/bin/python -m pytest test/bdd --nominatim-purge working-directory: Nominatim + tests-windows: + needs: create-archive + runs-on: windows-latest + + steps: + - uses: actions/download-artifact@v4 + with: + name: full-source + + - name: Unpack Nominatim + run: tar xf nominatim-src.tar.bz2 + + - uses: ./Nominatim/.github/actions/setup-postgresql-windows + with: + postgresql-version: 17 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.14' + + - name: Install Spatialite + run: | + Invoke-WebRequest -Uri "https://www.gaia-gis.it/gaia-sins/windows-bin-amd64/mod_spatialite-5.1.0-win-amd64.7z" -OutFile "spatialite.7z" + 7z x spatialite.7z -o"C:\spatialite" + echo "C:\spatialite\mod_spatialite-5.1.0-win-amd64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Install osm2pgsql + run: | + Invoke-WebRequest -Uri "https://osm2pgsql.org/download/windows/osm2pgsql-latest-x64.zip" -OutFile "osm2pgsql.zip" + Expand-Archive -Path "osm2pgsql.zip" -DestinationPath "C:\osm2pgsql" + $BinDir = Get-ChildItem -Path "C:\osm2pgsql" -Recurse -Filter "osm2pgsql.exe" | Select-Object -ExpandProperty DirectoryName | Select-Object -First 1 + if (-not $BinDir) { + Write-Error "Could not find osm2pgsql.exe" + exit 1 + } + echo "$BinDir" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + $FullExePath = Join-Path $BinDir "osm2pgsql.exe" + echo "NOMINATIM_OSM2PGSQL_BINARY=$FullExePath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - name: Set UTF-8 encoding + run: | + echo "PYTHONUTF8=1" >> $env:GITHUB_ENV + [System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + + - name: Install PyICU from wheel + run: | + python -m pip install https://github.com/cgohlke/pyicu-build/releases/download/v2.16.0/pyicu-2.16-cp314-cp314-win_amd64.whl + + - name: Install test prerequisites + run: | + python -m pip install -U pip + python -m pip install pytest pytest-asyncio "psycopg[binary]!=3.3.0" python-dotenv pyyaml jinja2 psutil sqlalchemy pytest-bdd falcon starlette uvicorn asgi_lifespan aiosqlite osmium mwparserfromhell + + - name: Python unit tests + run: | + python -m pytest test/python -k "not (import_osm or run_osm2pgsql)" + working-directory: Nominatim + install: runs-on: ubuntu-latest needs: create-archive diff --git a/test/python/config/test_config.py b/test/python/config/test_config.py index 555bc4e7..4908fd9a 100644 --- a/test/python/config/test_config.py +++ b/test/python/config/test_config.py @@ -200,14 +200,15 @@ def test_get_path_empty(make_config): assert not config.get_path('TOKENIZER_CONFIG') -def test_get_path_absolute(make_config, monkeypatch): +def test_get_path_absolute(make_config, monkeypatch, tmp_path): config = make_config() - monkeypatch.setenv('NOMINATIM_FOOBAR', '/dont/care') + p = (tmp_path / "does_not_exist").resolve() + monkeypatch.setenv('NOMINATIM_FOOBAR', str(p)) result = config.get_path('FOOBAR') assert isinstance(result, Path) - assert str(result) == '/dont/care' + assert str(result) == str(p) def test_get_path_relative(make_config, monkeypatch, tmp_path): diff --git a/test/python/conftest.py b/test/python/conftest.py index 38bf70a6..cfd3a7c3 100644 --- a/test/python/conftest.py +++ b/test/python/conftest.py @@ -6,8 +6,12 @@ # For a full list of authors see the git log. import itertools import sys +import asyncio from pathlib import Path +if sys.platform == 'win32': + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + import psycopg from psycopg import sql as pysql import pytest