diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7cf1f03a..257c43e68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,11 +14,13 @@ jobs: strategy: matrix: os: - - ubuntu-latest - - windows-latest - - macos-latest - - macos-13 + - ubuntu-22.04 + - ubuntu-20.04 + - windows-2022 + - windows-2019 - macos-14 + - macos-13 + - macos-12 steps: - uses: actions/checkout@v4 @@ -26,6 +28,11 @@ jobs: uses: ./ id: postgres + - name: Run setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Run tests run: | python3 -m pip install --upgrade pip pytest psycopg furl @@ -57,6 +64,11 @@ jobs: port: 34837 id: postgres + - name: Run setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Run tests run: | python3 -m pip install --upgrade pip pytest psycopg furl diff --git a/action.yml b/action.yml index ee399a427..d63da77a1 100644 --- a/action.yml +++ b/action.yml @@ -64,6 +64,18 @@ runs: export PGDATA="$RUNNER_TEMP/pgdata" export PWFILE="$RUNNER_TEMP/pwfile" + DEFAULT_ENCODING="UTF-8" + DEFAULT_LOCALE="en_US.$DEFAULT_ENCODING" + + # Unfortunately, Windows Server 2019 doesn't understand locale + # specified in the format defined by the POSIX standard, i.e. + # _.. Therefore, we have to convert it + # into something it can swallow, i.e. -. + if [[ "$RUNNER_OS" == "Windows" && "$(wmic os get Caption)" == *"2019"* ]]; then + DEFAULT_LOCALE="${DEFAULT_LOCALE%%.*}" + DEFAULT_LOCALE="${DEFAULT_LOCALE//_/-}" + fi + # Unfortunately 'initdb' could only receive a password via file on disk # or prompt to enter on. Prompting is not an option since we're running # in non-interactive mode. @@ -82,8 +94,8 @@ runs: --username="${{ inputs.username }}" \ --pwfile="$PWFILE" \ --auth="scram-sha-256" \ - --encoding="UTF-8" \ - --locale="en_US.UTF-8" \ + --encoding="$DEFAULT_ENCODING" \ + --locale="$DEFAULT_LOCALE" \ --no-instructions # Do not create unix sockets since they are created by default in the diff --git a/test_action.py b/test_action.py index a1f4540ea..f84149f6b 100644 --- a/test_action.py +++ b/test_action.py @@ -12,6 +12,24 @@ ConnectionFactory = t.Callable[[str], psycopg.Connection] +@pytest.fixture(scope="function") +def is_windows() -> bool: + """Returns True if running on Windows.""" + + return os.name == "nt" + + +@pytest.fixture(scope="function") +def is_windows_server_2019(is_windows: bool) -> bool: + """Returns True if running on Windows Server 2019.""" + + if not is_windows: + return False + + windows_caption = subprocess.check_output(["wmic", "os", "get", "Caption"], text=True) + return "Windows Server 2019" in windows_caption + + @pytest.fixture(scope="function") def connection_uri() -> str: """Read and return connection URI from environment.""" @@ -57,35 +75,40 @@ def connection( raise RuntimeError("f{request.param}: unknown value") -def test_connection_uri(connection_uri): +def test_connection_uri(connection_uri: str): """Test that CONNECTION_URI matches EXPECTED_CONNECTION_URI.""" assert connection_uri == os.getenv("EXPECTED_CONNECTION_URI") -def test_service_name(service_name): +def test_service_name(service_name: str): """Test that SERVICE_NAME matches EXPECTED_SERVICE_NAME.""" assert service_name == os.getenv("EXPECTED_SERVICE_NAME") def test_server_encoding(connection: psycopg.Connection): - """Test that PostgreSQL's encoding is 'UTF-8'.""" + """Test that PostgreSQL's encoding matches the one we passed to initdb.""" assert connection.execute("SHOW SERVER_ENCODING").fetchone()[0] == "UTF8" -def test_locale(connection: psycopg.Connection): - """Test that PostgreSQL's locale is 'en_US.UTF-8'.""" +def test_locale(connection: psycopg.Connection, is_windows_server_2019: bool): + """Test that PostgreSQL's locale matches the one we paased to initdb.""" + + locale_exp = "en_US.UTF-8" + + if is_windows_server_2019: + locale_exp = "en-US" lc_collate = connection.execute("SHOW LC_COLLATE").fetchone()[0] lc_ctype = connection.execute("SHOW LC_CTYPE").fetchone()[0] - assert locale.normalize(lc_collate) == "en_US.UTF-8" - assert locale.normalize(lc_ctype) == "en_US.UTF-8" + assert locale.normalize(lc_collate) == locale_exp + assert locale.normalize(lc_ctype) == locale_exp -def test_environment_variables(): +def test_environment_variables(is_windows: bool): """Test that only expected 'PG*' variables are set.""" pg_environ = {k: v for k, v in os.environ.items() if k.startswith("PG")} @@ -96,7 +119,7 @@ def test_environment_variables(): pg_servicefile_exp = pathlib.Path(os.environ["RUNNER_TEMP"], "pgdata", "pg_service.conf") assert pg_servicefile.resolve() == pg_servicefile_exp.resolve() - if os.name == "nt": + if is_windows: pg_environ_exp = { "PGBIN": "", "PGDATA": "",