add: --ready flag for postgrest healthcheck

The `--ready` flag is a wrapper around the admin server
`/ready` request. This is done through using an http client
library in postgrest.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
This commit is contained in:
Taimoor Zaeem
2025-09-28 18:01:10 -05:00
committed by Steve Chavez
parent ab2cd766c2
commit a9a1763328
10 changed files with 273 additions and 6 deletions
+6
View File
@@ -95,3 +95,9 @@ def hpctixfile():
# astronomically low.
test = uuid.uuid4().hex[:12]
return tixfile.with_suffix(f".{test}.tix")
def get_admin_host_and_port_from_config(config):
admin_host = config.get("PGRST_ADMIN_SERVER_HOST", config["PGRST_SERVER_HOST"])
admin_port = config["PGRST_ADMIN_SERVER_PORT"]
return (admin_host, admin_port)
+2
View File
@@ -57,6 +57,7 @@ class PostgrestProcess:
admin: object
process: object
session: object
config: object
def read_stdout(self, nlines=1):
"Wait for line(s) on standard output."
@@ -143,6 +144,7 @@ def run(
process=process,
session=PostgrestSession(baseurl),
admin=PostgrestSession(adminurl),
config=env,
)
finally:
remaining_output = process.stdout.read()
+104
View File
@@ -1,12 +1,14 @@
"Unit tests for Input/Ouput of PostgREST seen as a black box."
from operator import attrgetter
import signal
import subprocess
import pytest
from syrupy.extensions.json import SingleFileSnapshotExtension
import yaml
from config import *
from postgrest import *
class ExtraNewLinesDumper(yaml.SafeDumper):
@@ -286,3 +288,105 @@ def test_jwt_secret_min_length(defaultenv):
error = cli(["--dump-config"], env=env, expect_error=True)
assert "The JWT secret must be at least 32 characters long." in error
@pytest.mark.parametrize("host", ["127.0.0.1", "::1"], ids=["IPv4", "IPv6"])
def test_cli_ready_flag_success(host, defaultenv):
"test PostgREST ready flag succeeds when ready"
port = freeport()
with run(env=defaultenv, host=host, port=port) as postgrest:
output = cli(["--ready"], env=postgrest.config)
(admin_host, admin_port) = get_admin_host_and_port_from_config(postgrest.config)
if is_ipv6(host):
assert f"OK: http://[{admin_host}]:{admin_port}/ready" in output
else:
assert f"OK: http://{admin_host}:{admin_port}/ready" in output
def test_cli_ready_flag_fail_when_schema_cache_not_loaded(defaultenv, metapostgrest):
"test PosgREST ready flag fail when schema cache not loaded"
role = "timeout_authenticator"
env = {
**defaultenv,
"PGUSER": role,
"PGRST_DB_ANON_ROLE": role,
"PGRST_INTERNAL_SCHEMA_CACHE_SLEEP": "500",
}
port = freeport()
with run(env=env, port=port) as postgrest:
# The schema cache query takes at least 500ms, due to PGRST_INTERNAL_SCHEMA_CACHE_SLEEP above.
# Make it impossible to load the schema cache, by setting statement timeout to 400ms.
set_statement_timeout(metapostgrest, role, 400)
# force a reconnection so the new role setting is picked up
postgrest.process.send_signal(signal.SIGUSR1)
postgrest.wait_until_scache_starts_loading()
output = cli(["--ready"], env=postgrest.config, expect_error=True)
(admin_host, admin_port) = get_admin_host_and_port_from_config(postgrest.config)
assert f"ERROR: http://{admin_host}:{admin_port}/ready" in output
def test_cli_ready_flag_fail_with_http_exception(defaultenv):
"test PostgREST ready flag fail when http exception occurs"
port = freeport()
# when healthcheck process sends the request to a wrong endpoint
with run(env=defaultenv, port=port) as postgrest:
# we set it to some freeport where admin is not running
postgrest.config["PGRST_ADMIN_SERVER_PORT"] = str(freeport())
output = cli(["--ready"], env=postgrest.config, expect_error=True)
(admin_host, admin_port) = get_admin_host_and_port_from_config(postgrest.config)
assert (
f"ERROR: connection refused to http://{admin_host}:{admin_port}/ready"
in output
)
# When client sends the request to invalid URL
with run(env=defaultenv, port=port) as postgrest:
postgrest.config["PGRST_ADMIN_SERVER_PORT"] = str(-1)
output = cli(["--ready"], env=postgrest.config, expect_error=True)
(admin_host, admin_port) = get_admin_host_and_port_from_config(postgrest.config)
assert f"ERROR: invalid url - http://{admin_host}:{admin_port}/ready" in output
def test_cli_ready_flag_fail_with_special_hostname(defaultenv):
"test PostgREST ready flag fail when http exception occurs"
port = freeport()
host = "*4"
with run(env=defaultenv, host=host, port=port) as postgrest:
output = cli(["--ready"], env=postgrest.config, expect_error=True)
assert (
f'ERROR: The `--ready` flag cannot be used when server-host is configured as "{host}". Please update your server-host config to "localhost".'
in output
)
def test_cli_ready_flag_fail_when_no_admin_server(defaultenv):
"test PostgREST ready flag fail when admin server not running"
with run(env=defaultenv) as postgrest:
# We set admin-server-port to <empty> to disable admin server
postgrest.config["PGRST_ADMIN_SERVER_PORT"] = ""
output = cli(["--ready"], env=postgrest.config, expect_error=True)
assert (
"ERROR: Admin server is not running. Please check admin-server-port config."
in output
)