import sys import pytest import testinfra import test_quadlet # noqa: F401 """ Verify that the postgresql Quadlet is correctly installed and configured on a fresh VM boot. """ class TestPostgresqlQuadlet(test_quadlet.TestQuadlet): expected_services = [ { "name": "postgresql-server.service", "state": "active", "exists": True }, { "name": "postgresql-init.service", "state": "inactive", "exists": True }, { "name": "postgresql-upgrade.service", "state": "inactive", "exists": True }, { "name": "postgresql-backup.service", "state": "inactive", "exists": True }, { "name": "postgresql-set-major.service", "state": "inactive", "exists": True }, { "name": "postgresql-backup.timer", "state": "active", "exists": True }, { "name": "postgresql.target", "state": "active", "exists": True }, ] expected_sockets = [ { "uri": "tcp://127.0.0.1:5432", "state": "listening" }, { "uri": "tcp://0.0.0.0:5432", "state": "closed" }, { "uri": "tcp://:::5432", "state": "closed" }, ] expected_ports = [ { "number": 5432, "protocol": "tcp", "state": "closed" }, { "number": 22, "protocol": "tcp", "state": "open" }, ] expected_files = [ { "path": "/var/lib/quadlets/postgresql", "type": "directory", "owner": "postgresql", "group": "itix-svc", "mode": 0o755 }, { "path": "/etc/quadlets/postgresql/config.env", "type": "file", "owner": "root", "group": "root", "mode": 0o600 }, { "path": "/var/lib/virtiofs/data/postgresql", "type": "directory", "owner": "postgresql", "group": "itix-svc", "mode": 0o700 }, { "path": "/var/lib/virtiofs/data/postgresql/backup", "type": "directory", "owner": "postgresql", "group": "itix-svc", "mode": 0o700 }, { "path": "/var/lib/quadlets/postgresql/.initialized", "type": "file", "owner": "root", "group": "root", "mode": 0o644 }, ] expected_podman_images = [ ] expected_podman_containers = [ { "name": "postgresql-server", "state": "present", "pid1": { "owner": "10004", "group": "10000", "commandline": "postgres -h 127.0.0.1" } }, ] expected_main_service = "postgresql.target" expected_main_service_timeout = 300 expected_pg_major = 0 # TODO: set this variable in subclasses def _run_sql(self, fcos_host, query: str, check: bool = True, database: str = "postgres") -> str: """Execute *sql* via ``podman exec`` on the running postgresql-server container. Uses the Unix socket at /var/run/postgresql inside the container (mapped from /run/quadlets/postgresql on the host). The pg_hba.conf generated by the official postgres image grants trust access on local sockets, so no password is required. Returns: Stripped stdout of the psql command. """ result = fcos_host.run( f"podman exec postgresql-server psql -U postgres -d {database} --csv -t -c %s", query ) if check: assert result.exit_status == 0, f"SQL query \"{query}\" failed with exit code {result.exit_status}: {result.stderr}" return result.stdout.strip() def test_postgresql_major_version_items(self, fcos_host): """The major version from the config must be reflected in the filesystem and in the running Podman image.""" self.check_expected_files(fcos_host, [ { "path": f"/var/lib/quadlets/postgresql/{self.expected_pg_major}", "type": "directory", "owner": "postgresql", "group": "itix-svc", "mode": 0o755 }, ]) self.check_expected_podman_images(fcos_host, [ { "name": "docker.io/library/postgres", "tag": f"{self.expected_pg_major}-alpine", "state": "present" }, ]) def test_latest_symlink_exists(self, fcos_host): """The 'latest' symlink must point to the active major-version directory.""" link = fcos_host.file("/var/lib/quadlets/postgresql/latest") assert link.exists assert link.is_symlink assert link.linked_to == f"/var/lib/quadlets/postgresql/{self.expected_pg_major}" def test_postgresql_accepts_connections(self, fcos_host): """PostgreSQL must respond to a trivial SQL query.""" output = self._run_sql(fcos_host, "SELECT 1 AS probe") assert output == "1", f"Unexpected output from SQL query: {output}" def test_postgresql_version_matches_config(self, fcos_host): """The running PostgreSQL server must report the version from PG_MAJOR_DEFAULT.""" output = self._run_sql(fcos_host, "SHOW server_version") assert output.startswith(f"{self.expected_pg_major}."), f"Expected PostgreSQL server version to start with {self.expected_pg_major}, but got {output}"