improve io-tests
Tests are now run through unix socket by default allowing parallel execution. Test setup configuration is done via environment variables instead of config files.
This commit is contained in:
+15
-1
@@ -160,7 +160,21 @@ $ nix-shell --run postgrest-test-spec-all
|
|||||||
|
|
||||||
# Run the tests against a specific version of PostgreSQL (use tab-completion in
|
# Run the tests against a specific version of PostgreSQL (use tab-completion in
|
||||||
# nix-shell to see all available versions):
|
# nix-shell to see all available versions):
|
||||||
$ nix-shell --run postgrest-test-spec-postgresql-9.5
|
$ nix-shell --run postgrest-test-spec-postgresql-13
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The io-test that test PostgREST as a black box with inputs and outputs can be
|
||||||
|
run with `postgrest-test-io`. The test runner under the hood is
|
||||||
|
[pytest](https://docs.pytest.org/) and you can pass it the usual options:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Filter the tests to run by name, including all that contain 'config':
|
||||||
|
postgrest-test-io -k config
|
||||||
|
|
||||||
|
# Run tests in parallel using xdist, specifying the number of processes:
|
||||||
|
postgrest-test-io -n auto
|
||||||
|
postgrest-test-io -n 8
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -90,11 +90,12 @@ let
|
|||||||
|
|
||||||
ioTestPython =
|
ioTestPython =
|
||||||
python3.withPackages (ps: [
|
python3.withPackages (ps: [
|
||||||
|
ps.pyjwt
|
||||||
ps.pytest
|
ps.pytest
|
||||||
|
ps.pytest_xdist
|
||||||
|
ps.pyyaml
|
||||||
ps.requests
|
ps.requests
|
||||||
ps.requests-unixsocket
|
ps.requests-unixsocket
|
||||||
ps.pyjwt
|
|
||||||
ps.pyyaml
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
testIO =
|
testIO =
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
db-pool = 1
|
db-pool = 1
|
||||||
db-pool-timeout = 1
|
db-pool-timeout = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
|
|
||||||
app.settings.external_api_secret = "0123456789abcdef"
|
app.settings.external_api_secret = "0123456789abcdef"
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
|
|
||||||
# Read secret from a file: /dev/stdin (alias for standard input)
|
# Read secret from a file: /dev/stdin (alias for standard input)
|
||||||
jwt-secret = "@/dev/stdin"
|
jwt-secret = "@/dev/stdin"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
db-uri = "@/dev/stdin"
|
db-uri = "@/dev/stdin"
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
jwt-secret = "reallyreallyreallyreallyverysafe"
|
jwt-secret = "reallyreallyreallyreallyverysafe"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
jwt-role-claim-key = "$(ROLE_CLAIM_KEY)"
|
jwt-role-claim-key = "$(ROLE_CLAIM_KEY)"
|
||||||
jwt-secret = "reallyreallyreallyreallyverysafe"
|
jwt-secret = "reallyreallyreallyreallyverysafe"
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
|
|
||||||
# Read secret from a file: /dev/stdin (alias for standard input)
|
# Read secret from a file: /dev/stdin (alias for standard input)
|
||||||
jwt-secret = "@/dev/stdin"
|
jwt-secret = "@/dev/stdin"
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
db-schemas = "test"
|
db-schemas = "test"
|
||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
|
|
||||||
app.settings.name_var = "John"
|
app.settings.name_var = "John"
|
||||||
jwt-secret = "invalidinvalidinvalidinvalidinvalid"
|
jwt-secret = "invalidinvalidinvalidinvalidinvalid"
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
db-pool = 1
|
db-pool = 1
|
||||||
server-host = "127.0.0.1"
|
|
||||||
server-port = 49421
|
|
||||||
jwt-secret = "reallyreallyreallyreallyverysafe"
|
jwt-secret = "reallyreallyreallyreallyverysafe"
|
||||||
|
|||||||
+95
-69
@@ -3,11 +3,14 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
|
import shutil
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
@@ -21,7 +24,7 @@ import yaml
|
|||||||
BASEDIR = pathlib.Path(os.path.realpath(__file__)).parent
|
BASEDIR = pathlib.Path(os.path.realpath(__file__)).parent
|
||||||
CONFIGSDIR = BASEDIR / "configs"
|
CONFIGSDIR = BASEDIR / "configs"
|
||||||
FIXTURES = yaml.load((BASEDIR / "fixtures.yaml").read_text(), Loader=yaml.Loader)
|
FIXTURES = yaml.load((BASEDIR / "fixtures.yaml").read_text(), Loader=yaml.Loader)
|
||||||
BASEURL = "http://127.0.0.1:49421"
|
POSTGREST_BIN = shutil.which("postgrest")
|
||||||
SECRET = "reallyreallyreallyreallyverysafe"
|
SECRET = "reallyreallyreallyreallyverysafe"
|
||||||
|
|
||||||
|
|
||||||
@@ -41,7 +44,9 @@ class PostgrestSession(requests_unixsocket.Session):
|
|||||||
self.baseurl = baseurl
|
self.baseurl = baseurl
|
||||||
|
|
||||||
def request(self, method, url, *args, **kwargs):
|
def request(self, method, url, *args, **kwargs):
|
||||||
fullurl = urllib.parse.urljoin(self.baseurl, url)
|
# Not using urllib.parse.urljoin to compose the url, as it doesn't play
|
||||||
|
# well with our 'http+unix://' unix domain socket urls.
|
||||||
|
fullurl = self.baseurl + url
|
||||||
return super(PostgrestSession, self).request(method, fullurl, *args, **kwargs)
|
return super(PostgrestSession, self).request(method, fullurl, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@@ -58,25 +63,27 @@ def dburi():
|
|||||||
return os.getenv("PGRST_DB_URI").encode("utf-8")
|
return os.getenv("PGRST_DB_URI").encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
def mkenv(moreenv):
|
@pytest.fixture
|
||||||
"""
|
def defaultenv():
|
||||||
Create env from os.environ and moreenv, while
|
"Default environment for PostgREST."
|
||||||
filtering None values to allow overriding "unset".
|
return {
|
||||||
"""
|
"PGRST_DB_URI": os.environ["PGRST_DB_URI"],
|
||||||
env = {**os.environ, **(moreenv or {})}
|
"PGRST_DB_SCHEMAS": os.environ["PGRST_DB_SCHEMAS"],
|
||||||
return {k: v for k, v in env.items() if v is not None}
|
"PGRST_DB_ANON_ROLE": os.environ["PGRST_DB_ANON_ROLE"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def dumpconfig(configpath=None, moreenv=None, stdin=None):
|
def dumpconfig(configpath=None, env=None, stdin=None):
|
||||||
"Dump the config as parsed by PostgREST."
|
"Dump the config as parsed by PostgREST."
|
||||||
|
command = [POSTGREST_BIN, "--dump-config"]
|
||||||
|
|
||||||
command = ["postgrest", "--dump-config"]
|
|
||||||
if configpath:
|
if configpath:
|
||||||
command += [configpath]
|
command.append(configpath)
|
||||||
|
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
command, env=mkenv(moreenv), stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
command, env=env or {}, stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||||
)
|
)
|
||||||
|
|
||||||
process.stdin.write(stdin or b"")
|
process.stdin.write(stdin or b"")
|
||||||
result = process.communicate()[0]
|
result = process.communicate()[0]
|
||||||
process.kill()
|
process.kill()
|
||||||
@@ -87,27 +94,44 @@ def dumpconfig(configpath=None, moreenv=None, stdin=None):
|
|||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def run(configpath, stdin=None, moreenv=None, socket=None):
|
def run(configpath=None, stdin=None, env=None, port=None):
|
||||||
"Run PostgREST and yield an endpoint that is ready for connections."
|
"Run PostgREST and yield an endpoint that is ready for connections."
|
||||||
|
|
||||||
if socket:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
baseurl = "http+unix://" + urllib.parse.quote_plus(str(socket))
|
if port:
|
||||||
else:
|
env["PGRST_SERVER_PORT"] = str(port)
|
||||||
baseurl = BASEURL
|
env["PGRST_SERVER_HOST"] = "localhost"
|
||||||
|
baseurl = f"http://localhost:{port}"
|
||||||
|
else:
|
||||||
|
socketfile = pathlib.Path(tmpdir) / "postgrest.sock"
|
||||||
|
env["PGRST_SERVER_UNIX_SOCKET"] = str(socketfile)
|
||||||
|
baseurl = "http+unix://" + urllib.parse.quote_plus(str(socketfile))
|
||||||
|
|
||||||
command = ["postgrest", configpath]
|
command = [POSTGREST_BIN]
|
||||||
process = subprocess.Popen(command, stdin=subprocess.PIPE, env=mkenv(moreenv))
|
|
||||||
|
|
||||||
try:
|
if configpath:
|
||||||
process.stdin.write(stdin or b"")
|
command.append(configpath)
|
||||||
process.stdin.close()
|
|
||||||
|
|
||||||
wait_until_ready(baseurl)
|
process = subprocess.Popen(command, stdin=subprocess.PIPE, env=env or {})
|
||||||
|
|
||||||
yield PostgrestProcess(process=process, session=PostgrestSession(baseurl))
|
try:
|
||||||
finally:
|
process.stdin.write(stdin or b"")
|
||||||
process.kill()
|
process.stdin.close()
|
||||||
process.wait()
|
|
||||||
|
wait_until_ready(baseurl)
|
||||||
|
|
||||||
|
yield PostgrestProcess(process=process, session=PostgrestSession(baseurl))
|
||||||
|
finally:
|
||||||
|
process.kill()
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
|
||||||
|
def freeport():
|
||||||
|
"Find a free port on localhost."
|
||||||
|
with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||||
|
s.bind(("", 0))
|
||||||
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
return s.getsockname()[1]
|
||||||
|
|
||||||
|
|
||||||
def wait_until_ready(url):
|
def wait_until_ready(url):
|
||||||
@@ -153,8 +177,7 @@ def test_expected_config(expectedconfig):
|
|||||||
expected = expectedconfig.read_text()
|
expected = expectedconfig.read_text()
|
||||||
config = CONFIGSDIR / expectedconfig.name
|
config = CONFIGSDIR / expectedconfig.name
|
||||||
|
|
||||||
unset = {"PGRST_DB_URI": None, "PGRST_DB_ANON_ROLE": None, "PGRST_DB_SCHEMAS": None}
|
assert dumpconfig(config) == expected
|
||||||
assert dumpconfig(config, moreenv=unset) == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_expected_config_from_environment():
|
def test_expected_config_from_environment():
|
||||||
@@ -164,7 +187,7 @@ def test_expected_config_from_environment():
|
|||||||
env = {k: str(v) for k, v in yaml.load(envfile, Loader=yaml.Loader).items()}
|
env = {k: str(v) for k, v in yaml.load(envfile, Loader=yaml.Loader).items()}
|
||||||
|
|
||||||
expected = (CONFIGSDIR / "expected" / "no-defaults.config").read_text()
|
expected = (CONFIGSDIR / "expected" / "no-defaults.config").read_text()
|
||||||
assert dumpconfig(moreenv=env) == expected
|
assert dumpconfig(env=env) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -172,7 +195,7 @@ def test_expected_config_from_environment():
|
|||||||
[conf for conf in CONFIGSDIR.iterdir() if conf.suffix == ".config"],
|
[conf for conf in CONFIGSDIR.iterdir() if conf.suffix == ".config"],
|
||||||
ids=attrgetter("name"),
|
ids=attrgetter("name"),
|
||||||
)
|
)
|
||||||
def test_stable_config(tmp_path, config):
|
def test_stable_config(tmp_path, config, defaultenv):
|
||||||
"""
|
"""
|
||||||
A dumped, re-read and re-dumped config should match the dumped config.
|
A dumped, re-read and re-dumped config should match the dumped config.
|
||||||
|
|
||||||
@@ -184,30 +207,27 @@ def test_stable_config(tmp_path, config):
|
|||||||
# Set environment variables that some of the configs expect. Using a
|
# Set environment variables that some of the configs expect. Using a
|
||||||
# complex ROLE_CLAIM_KEY to make sure quoting works.
|
# complex ROLE_CLAIM_KEY to make sure quoting works.
|
||||||
env = {
|
env = {
|
||||||
|
**defaultenv,
|
||||||
"ROLE_CLAIM_KEY": '."https://www.example.com/roles"[0].value',
|
"ROLE_CLAIM_KEY": '."https://www.example.com/roles"[0].value',
|
||||||
"POSTGREST_TEST_SOCKET": "/tmp/postgrest.sock",
|
"POSTGREST_TEST_SOCKET": "/tmp/postgrest.sock",
|
||||||
|
"POSTGREST_TEST_PORT": "80",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Some configs expect input from stdin, at least on base64.
|
# Some configs expect input from stdin, at least on base64.
|
||||||
stdin = b"Y29ubmVjdGlvbl9zdHJpbmc="
|
stdin = b"Y29ubmVjdGlvbl9zdHJpbmc="
|
||||||
|
|
||||||
dumped = dumpconfig(config, moreenv=env, stdin=stdin)
|
dumped = dumpconfig(config, env=env, stdin=stdin)
|
||||||
|
|
||||||
tmpconfigpath = tmp_path / "config"
|
tmpconfigpath = tmp_path / "config"
|
||||||
tmpconfigpath.write_text(dumped)
|
tmpconfigpath.write_text(dumped)
|
||||||
redumped = dumpconfig(tmpconfigpath, moreenv=env)
|
redumped = dumpconfig(tmpconfigpath, env=env)
|
||||||
|
|
||||||
assert dumped == redumped
|
assert dumped == redumped
|
||||||
|
|
||||||
|
|
||||||
def test_socket_connection(tmp_path):
|
def test_port_connection(defaultenv):
|
||||||
"Connections via unix domain sockets should work."
|
"Connections via a port on localhost should work."
|
||||||
socket = tmp_path / "postgrest.sock"
|
with run(env=defaultenv, port=freeport()):
|
||||||
env = {
|
|
||||||
"POSTGREST_TEST_SOCKET": str(socket),
|
|
||||||
}
|
|
||||||
|
|
||||||
with run(CONFIGSDIR / "unix-socket.config", socket=socket, moreenv=env):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -216,7 +236,7 @@ def test_socket_connection(tmp_path):
|
|||||||
[path for path in (BASEDIR / "secrets").iterdir() if path.suffix != ".jwt"],
|
[path for path in (BASEDIR / "secrets").iterdir() if path.suffix != ".jwt"],
|
||||||
ids=attrgetter("name"),
|
ids=attrgetter("name"),
|
||||||
)
|
)
|
||||||
def test_read_secret_from_file(secretpath):
|
def test_read_secret_from_file(secretpath, defaultenv):
|
||||||
"Authorization should succeed when the secret is read from a file."
|
"Authorization should succeed when the secret is read from a file."
|
||||||
if secretpath.suffix == ".b64":
|
if secretpath.suffix == ".b64":
|
||||||
configfile = CONFIGSDIR / "base64-secret-from-file.config"
|
configfile = CONFIGSDIR / "base64-secret-from-file.config"
|
||||||
@@ -226,53 +246,59 @@ def test_read_secret_from_file(secretpath):
|
|||||||
secret = secretpath.read_bytes()
|
secret = secretpath.read_bytes()
|
||||||
headers = authheader(secretpath.with_suffix(".jwt").read_text())
|
headers = authheader(secretpath.with_suffix(".jwt").read_text())
|
||||||
|
|
||||||
with run(configfile, stdin=secret) as postgrest:
|
with run(configfile, stdin=secret, env=defaultenv) as postgrest:
|
||||||
response = postgrest.session.get("/authors_only", headers=headers)
|
response = postgrest.session.get("/authors_only", headers=headers)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
def test_read_dburi_from_file_without_eol(dburi):
|
def test_read_dburi_from_file_without_eol(dburi, defaultenv):
|
||||||
"Reading the dburi from a file with a single line should work."
|
"Reading the dburi from a file with a single line should work."
|
||||||
config = CONFIGSDIR / "dburi-from-file.config"
|
config = CONFIGSDIR / "dburi-from-file.config"
|
||||||
unset = {"PGRST_DB_URI": None}
|
env = {key: value for key, value in defaultenv.items() if key != "PGRST_DB_URI"}
|
||||||
with run(config, moreenv=unset, stdin=dburi):
|
with run(config, env=env, stdin=dburi):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_read_dburi_from_file_with_eol(dburi):
|
def test_read_dburi_from_file_with_eol(dburi, defaultenv):
|
||||||
"Reading the dburi from a file containing a newline should work."
|
"Reading the dburi from a file containing a newline should work."
|
||||||
config = CONFIGSDIR / "dburi-from-file.config"
|
config = CONFIGSDIR / "dburi-from-file.config"
|
||||||
unset = {"PGRST_DB_URI": None}
|
env = {key: value for key, value in defaultenv.items() if key != "PGRST_DB_URI"}
|
||||||
with run(config, moreenv=unset, stdin=dburi + b"\n"):
|
with run(config, env=env, stdin=dburi + b"\n"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"roleclaim", FIXTURES["roleclaims"], ids=lambda claim: claim["key"]
|
"roleclaim", FIXTURES["roleclaims"], ids=lambda claim: claim["key"]
|
||||||
)
|
)
|
||||||
def test_role_claim_key(roleclaim):
|
def test_role_claim_key(roleclaim, defaultenv):
|
||||||
"Authorization should depend on a correct role-claim-key and JWT claim."
|
"Authorization should depend on a correct role-claim-key and JWT claim."
|
||||||
env = {"ROLE_CLAIM_KEY": roleclaim["key"]}
|
env = {
|
||||||
|
**defaultenv,
|
||||||
|
"ROLE_CLAIM_KEY": roleclaim["key"],
|
||||||
|
}
|
||||||
headers = jwtauthheader(roleclaim["data"], SECRET)
|
headers = jwtauthheader(roleclaim["data"], SECRET)
|
||||||
|
|
||||||
with run(CONFIGSDIR / "role-claim-key.config", moreenv=env) as postgrest:
|
with run(CONFIGSDIR / "role-claim-key.config", env=env) as postgrest:
|
||||||
response = postgrest.session.get("/authors_only", headers=headers)
|
response = postgrest.session.get("/authors_only", headers=headers)
|
||||||
assert response.status_code == roleclaim["expected_status"]
|
assert response.status_code == roleclaim["expected_status"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("invalidroleclaimkey", FIXTURES["invalidroleclaimkeys"])
|
@pytest.mark.parametrize("invalidroleclaimkey", FIXTURES["invalidroleclaimkeys"])
|
||||||
def test_invalid_role_claim_key(invalidroleclaimkey):
|
def test_invalid_role_claim_key(invalidroleclaimkey, defaultenv):
|
||||||
"Given an invalid role-claim-key, Postgrest should exit with a non-zero exit code."
|
"Given an invalid role-claim-key, Postgrest should exit with a non-zero exit code."
|
||||||
env = {"ROLE_CLAIM_KEY": invalidroleclaimkey}
|
env = {
|
||||||
|
**defaultenv,
|
||||||
|
"ROLE_CLAIM_KEY": invalidroleclaimkey,
|
||||||
|
}
|
||||||
|
|
||||||
with pytest.raises(PostgrestError):
|
with pytest.raises(PostgrestError):
|
||||||
dump = dumpconfig(CONFIGSDIR / "role-claim-key.config", moreenv=env)
|
dump = dumpconfig(CONFIGSDIR / "role-claim-key.config", env=env)
|
||||||
for line in dump.split("\n"):
|
for line in dump.split("\n"):
|
||||||
if line.startswith("jwt-role-claim-key"):
|
if line.startswith("jwt-role-claim-key"):
|
||||||
print(line)
|
print(line)
|
||||||
|
|
||||||
|
|
||||||
def test_iat_claim():
|
def test_iat_claim(defaultenv):
|
||||||
"""
|
"""
|
||||||
A claim with an 'iat' (issued at) attribute should be successful.
|
A claim with an 'iat' (issued at) attribute should be successful.
|
||||||
|
|
||||||
@@ -283,7 +309,7 @@ def test_iat_claim():
|
|||||||
claim = {"role": "postgrest_test_author", "iat": datetime.utcnow()}
|
claim = {"role": "postgrest_test_author", "iat": datetime.utcnow()}
|
||||||
headers = jwtauthheader(claim, SECRET)
|
headers = jwtauthheader(claim, SECRET)
|
||||||
|
|
||||||
with run(CONFIGSDIR / "simple.config") as postgrest:
|
with run(CONFIGSDIR / "simple.config", env=defaultenv) as postgrest:
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
response = postgrest.session.get("/authors_only", headers=headers)
|
response = postgrest.session.get("/authors_only", headers=headers)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -291,14 +317,14 @@ def test_iat_claim():
|
|||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
|
||||||
def test_app_settings():
|
def test_app_settings(defaultenv):
|
||||||
"""
|
"""
|
||||||
App settings should not reset when the db pool times out.
|
App settings should not reset when the db pool times out.
|
||||||
|
|
||||||
See: https://github.com/PostgREST/postgrest/issues/1141
|
See: https://github.com/PostgREST/postgrest/issues/1141
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with run(CONFIGSDIR / "app-settings.config") as postgrest:
|
with run(CONFIGSDIR / "app-settings.config", env=defaultenv) as postgrest:
|
||||||
# Wait for the db pool to time out, set to 1s in config
|
# Wait for the db pool to time out, set to 1s in config
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
@@ -309,14 +335,14 @@ def test_app_settings():
|
|||||||
assert response.text == '"0123456789abcdef"'
|
assert response.text == '"0123456789abcdef"'
|
||||||
|
|
||||||
|
|
||||||
def test_app_settings_reload(tmp_path):
|
def test_app_settings_reload(tmp_path, defaultenv):
|
||||||
"App settings should be reloaded when PostgREST is sent SIGUSR2."
|
"App settings should be reloaded when PostgREST is sent SIGUSR2."
|
||||||
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
||||||
configfile = tmp_path / "test.config"
|
configfile = tmp_path / "test.config"
|
||||||
configfile.write_text(config)
|
configfile.write_text(config)
|
||||||
uri = "/rpc/get_guc_value?name=app.settings.name_var"
|
uri = "/rpc/get_guc_value?name=app.settings.name_var"
|
||||||
|
|
||||||
with run(configfile) as postgrest:
|
with run(configfile, env=defaultenv) as postgrest:
|
||||||
response = postgrest.session.get(uri)
|
response = postgrest.session.get(uri)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.text == '"John"'
|
assert response.text == '"John"'
|
||||||
@@ -333,7 +359,7 @@ def test_app_settings_reload(tmp_path):
|
|||||||
assert response.text == '"Jane"'
|
assert response.text == '"Jane"'
|
||||||
|
|
||||||
|
|
||||||
def test_jwt_secret_reload(tmp_path):
|
def test_jwt_secret_reload(tmp_path, defaultenv):
|
||||||
"JWT secret should be reloaded when PostgREST is sent SIGUSR2."
|
"JWT secret should be reloaded when PostgREST is sent SIGUSR2."
|
||||||
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
||||||
configfile = tmp_path / "test.config"
|
configfile = tmp_path / "test.config"
|
||||||
@@ -341,7 +367,7 @@ def test_jwt_secret_reload(tmp_path):
|
|||||||
|
|
||||||
headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET)
|
headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET)
|
||||||
|
|
||||||
with run(configfile) as postgrest:
|
with run(configfile, env=defaultenv) as postgrest:
|
||||||
response = postgrest.session.get("/authors_only", headers=headers)
|
response = postgrest.session.get("/authors_only", headers=headers)
|
||||||
assert response.status_code == 401
|
assert response.status_code == 401
|
||||||
|
|
||||||
@@ -357,16 +383,16 @@ def test_jwt_secret_reload(tmp_path):
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
def test_db_schema_reload(tmp_path):
|
def test_db_schema_reload(tmp_path, defaultenv):
|
||||||
"DB schema should be reloaded when PostgREST is sent SIGUSR2."
|
"DB schema should be reloaded when PostgREST is sent SIGUSR2."
|
||||||
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
config = (CONFIGSDIR / "sigusr2-settings.config").read_text()
|
||||||
configfile = tmp_path / "test.config"
|
configfile = tmp_path / "test.config"
|
||||||
configfile.write_text(config)
|
configfile.write_text(config)
|
||||||
|
|
||||||
headers = {"Accept-Profile": "v1"}
|
headers = {"Accept-Profile": "v1"}
|
||||||
unset = {"PGRST_DB_SCHEMAS": None}
|
env = {key: value for key, value in defaultenv.items() if key != "PGRST_DB_SCHEMAS"}
|
||||||
|
|
||||||
with run(configfile, moreenv=unset) as postgrest:
|
with run(configfile, env=env) as postgrest:
|
||||||
response = postgrest.session.get("/parents", headers=headers)
|
response = postgrest.session.get("/parents", headers=headers)
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
pgrPort=49421
|
||||||
|
|
||||||
# PGRST_DB_URI, PGRST_DB_ANON_ROLE and PGRST_DB_SCHEMAS are expected to be set by with_tmp_db
|
# PGRST_DB_URI, PGRST_DB_ANON_ROLE and PGRST_DB_SCHEMAS are expected to be set by with_tmp_db
|
||||||
export PGRST_DB_POOL="1"
|
export PGRST_DB_POOL="1"
|
||||||
export PGRST_SERVER_HOST="127.0.0.1"
|
export PGRST_SERVER_HOST="127.0.0.1"
|
||||||
export PGRST_SERVER_PORT="49421"
|
export PGRST_SERVER_PORT="$pgrPort"
|
||||||
export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe"
|
export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe"
|
||||||
|
|
||||||
trap "kill 0" int term exit
|
trap "kill 0" int term exit
|
||||||
@@ -19,8 +21,6 @@ result(){ echo "$1 $currentTest $2"; currentTest=$(( $currentTest + 1 )); }
|
|||||||
ok(){ result 'ok' "- $1"; }
|
ok(){ result 'ok' "- $1"; }
|
||||||
ko(){ result 'not ok' "- $1"; failedTests=$(( $failedTests + 1 )); }
|
ko(){ result 'not ok' "- $1"; failedTests=$(( $failedTests + 1 )); }
|
||||||
|
|
||||||
pgrPort=49421
|
|
||||||
|
|
||||||
pgrStart(){ postgrest +RTS -p -h > /dev/null & pgrPID="$!"; }
|
pgrStart(){ postgrest +RTS -p -h > /dev/null & pgrPID="$!"; }
|
||||||
pgrStop(){ kill "$pgrPID" 2>/dev/null; }
|
pgrStop(){ kill "$pgrPID" 2>/dev/null; }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ export PGDATA="$tmpdir/db"
|
|||||||
export PGHOST="$tmpdir/socket"
|
export PGHOST="$tmpdir/socket"
|
||||||
export PGUSER=postgrest_test_authenticator
|
export PGUSER=postgrest_test_authenticator
|
||||||
export PGDATABASE=postgres
|
export PGDATABASE=postgres
|
||||||
export DB_URI="postgresql://$PGDATABASE?host=$PGHOST&user=$PGUSER"
|
export DB_URI="postgresql:///$PGDATABASE?host=$PGHOST&user=$PGUSER"
|
||||||
export PGRST_DB_URI="$DB_URI"
|
export PGRST_DB_URI="$DB_URI"
|
||||||
export PGRST_DB_SCHEMAS="test"
|
export PGRST_DB_SCHEMAS="test"
|
||||||
export PGRST_DB_ANON_ROLE="postgrest_test_anonymous"
|
export PGRST_DB_ANON_ROLE="postgrest_test_anonymous"
|
||||||
|
|||||||
Reference in New Issue
Block a user