Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ jobs:
fail-fast: false
matrix:
# Latest version is tested via `coverage` above.
pgVersion: [14, 15, 16, 17, 18]
name: PG ${{ matrix.pgVersion }}
pgVersion: [pg-14, pg-15, pg-16, pg-17, oriole-18, pg-18]
name: ${{ matrix.pgVersion }}
runs-on: ubuntu-24.04
defaults:
run:
Expand All @@ -89,25 +89,25 @@ jobs:
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: tests.testSpec.bin tests.testObservability.bin tests.testIO.bin tests.testBigSchema.bin withTools.pg-${{ matrix.pgVersion }}.bin cabalTools.update.bin
tools: tests.testSpec.bin tests.testObservability.bin tests.testIO.bin tests.testBigSchema.bin withTools.${{ matrix.pgVersion }}.bin cabalTools.update.bin

- run: postgrest-cabal-update

- name: Run spec tests
if: always()
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-spec
run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-spec

- name: Run observability tests
if: always()
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-observability
run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-observability

- name: Run IO tests
if: always()
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-io -vv
run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-io -vv

- name: Run IO tests on a big schema
if: always()
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-big-schema -vv


memory:
Expand Down Expand Up @@ -191,7 +191,6 @@ jobs:
fail-fast: false
matrix:
runs-on:
- macos-15-intel # x86_64-darwin
- macos-14 # aarch64-darwin
- ubuntu-24.04 # x86_64-linux
- ubuntu-24.04-arm # aarch64-linux
Expand Down
8 changes: 8 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ let
{ name = "pg-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{
name = "oriole-18";
postgresql = pkgs.orioledb.withPackages (p: [ p.postgis p.pg_safeupdate ]);
config = "
default_table_access_method = 'orioledb'
shared_preload_libraries = 'orioledb, pg_stat_statements'
";
}
];

haskellPackages = pkgs.haskell.packages."${compiler}";
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions nix/tools/style.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ let
name = "postgrest-style";
docs = "Automatically format Haskell, Nix and Python files.";
workingDir = "/";
withTmpDir = true;
}
''
# Format Nix files
${statix}/bin/statix fix
${nixpkgs-fmt}/bin/nixpkgs-fmt . > /dev/null 2> /dev/null
${nixpkgs-fmt}/bin/nixpkgs-fmt .

# Format Haskell files
${fd}/bin/fd '\.l?hs$' \
| xargs ${stylish-haskell}/bin/stylish-haskell -i

# Format Python files
${black}/bin/black . 2> /dev/null
TMPDIR="$tmpdir" ${black}/bin/black .
'';

# Script to check whether any uncommitted changes result from postgrest-style
Expand Down
6 changes: 3 additions & 3 deletions nix/tools/withTools.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
}:
let
withTmpDb =
{ name, postgresql }:
{ name, postgresql, config ? "" }:
let
commandName = "postgrest-with-${name}";
postgresqlConf = writeText "postgresql.conf" "
postgresqlConf = writeText "postgresql.conf" ("
autovacuum = false
listen_addresses = ''
log_statement = all
shared_preload_libraries=pg_stat_statements
";
" + config);
in
checkedShellScript
{
Expand Down
1 change: 0 additions & 1 deletion test/io/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import uuid
import yaml


BASEDIR = pathlib.Path(os.path.realpath(__file__)).parent
CONFIGSDIR = BASEDIR / "configs"
FIXTURES = yaml.load(
Expand Down
2 changes: 2 additions & 0 deletions test/io/fixtures/big_schema.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
\ir ../../orioledb.sql

/*
This is a 2018 version of the apflora schema https://github.com/barbalex/apf2/tree/master/sql/apflora - latest version likely has differing contents

Expand Down
1 change: 1 addition & 0 deletions test/io/fixtures/load.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

\set ON_ERROR_STOP on

\ir ../../orioledb.sql
\ir database.sql
\ir db_config.sql
\ir roles.sql
Expand Down
2 changes: 1 addition & 1 deletion test/io/postgrest.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def run_pgproxy(env=None, proxy_timeout="1s"):
)

if process.poll() is not None:
(_, stderr_output) = process.communicate(timeout=1)
_, stderr_output = process.communicate(timeout=1)
raise RuntimeError(
f"{NGINX_BIN} exited with {process.returncode}: {stderr_output}"
)
Expand Down
10 changes: 5 additions & 5 deletions test/io/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def cli(args, env=None, stdin=None, expect_error=False):

process.stdin.write(stdin or b"")
try:
(stdout_output, stderr_output) = process.communicate(timeout=5)
stdout_output, stderr_output = process.communicate(timeout=5)
if expect_error: # When expected to fail, return stderr, else stdout
if process.returncode == 0:
raise PostgrestError(
Expand Down Expand Up @@ -310,7 +310,7 @@ def test_cli_ready_flag_success(host, defaultenv):
with run(env=defaultenv, host=host, port=port, admin_port=admin_port) as postgrest:
output = cli(["--ready"], env=postgrest.config)

(admin_host, admin_port) = get_admin_host_and_port_from_config(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
Expand Down Expand Up @@ -344,7 +344,7 @@ def test_cli_ready_flag_fail_when_schema_cache_not_loaded(defaultenv, metapostgr
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)
admin_host, admin_port = get_admin_host_and_port_from_config(postgrest.config)

assert f"ERROR: http://{admin_host}:{admin_port}/ready" in output

Expand All @@ -362,7 +362,7 @@ def test_cli_ready_flag_fail_with_http_exception(defaultenv):

postgrest.config["PGRST_ADMIN_SERVER_PORT"] = str(freeport(used_ports))
output = cli(["--ready"], env=postgrest.config, expect_error=True)
(admin_host, admin_port) = get_admin_host_and_port_from_config(postgrest.config)
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"
Expand All @@ -373,7 +373,7 @@ def test_cli_ready_flag_fail_with_http_exception(defaultenv):
with run(env=defaultenv, port=port, admin_port=admin_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)
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

Expand Down
12 changes: 4 additions & 8 deletions test/io/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,25 +1083,21 @@ def test_stale_schema_cache_dropped_table_returns_database_error(defaultenv):
}

try:
psql_as_superuser(
"""
psql_as_superuser("""
drop table if exists stale_schema_cache_items;
create table stale_schema_cache_items(id int primary key);
insert into stale_schema_cache_items values (1);
grant select on stale_schema_cache_items to postgrest_test_anonymous;
"""
)
""")

with run(env=env, wait_max_seconds=10) as postgrest:
response = postgrest.session.get("/stale_schema_cache_items")
assert response.status_code == 200

psql_as_superuser(
"""
psql_as_superuser("""
drop table stale_schema_cache_items;
notify pgrst, 'reload schema';
"""
)
""")

response = postgrest.session.get("/stale_schema_cache_items")
payload = response.json()
Expand Down
2 changes: 2 additions & 0 deletions test/load/fixtures.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
\ir ../orioledb.sql

CREATE ROLE postgrest_test_anonymous;
CREATE ROLE postgrest_test_author;
GRANT postgrest_test_anonymous TO :"PGUSER";
Expand Down
1 change: 1 addition & 0 deletions test/observability/fixtures/load.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

\set ON_ERROR_STOP on

\ir ../../orioledb.sql
\ir database.sql
\ir roles.sql
\ir schema.sql
Expand Down
6 changes: 6 additions & 0 deletions test/orioledb.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT EXISTS (SELECT * FROM pg_available_extensions WHERE name = 'orioledb') AS is_orioledb_available \gset

\if :is_orioledb_available
CREATE SCHEMA orioledb;
CREATE EXTENSION orioledb WITH SCHEMA orioledb;
\endif
2 changes: 1 addition & 1 deletion test/spec/Feature/Query/EmbedInnerJoinSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ spec withConfig = withConfig baseCfg $
}

it "only affects the source table rows if his direct embedding is an inner join" $ do
get "/tasks?select=id,projects(id,clients!inner(id))&projects.clients.id=eq.2" `shouldRespondWith`
get "/tasks?select=id,projects(id,clients!inner(id))&projects.clients.id=eq.2&order=id" `shouldRespondWith`
[json|[
{"id":1,"projects":null},
{"id":2,"projects":null},
Expand Down
22 changes: 11 additions & 11 deletions test/spec/Feature/Query/PlanSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 1.11
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for a single filter on a view" $ do
r <- request methodGet "/projects_view?id=gt.2"
Expand All @@ -47,7 +47,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
liftIO $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 1.1
totalCost `shouldSatisfy` (> 0)

it "outputs blocks info when using the buffers option" $ do
r <- request methodGet "/projects" (acceptHdrs "application/vnd.pgrst.plan+json; options=buffers") ""
Expand Down Expand Up @@ -139,7 +139,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 0.06
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for an update" $ do
r <- request methodPatch "/projects?id=eq.3"
Expand All @@ -153,7 +153,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 1.13
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for a delete" $ do
r <- request methodDelete "/projects?id=in.(1,2,3)"
Expand All @@ -167,7 +167,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 1.16
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for a single upsert" $ do
r <- request methodPut "/tiobe_pls?name=eq.Go"
Expand All @@ -182,7 +182,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 3.55
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for 2 upserts" $ do
r <- request methodPost "/tiobe_pls"
Expand All @@ -197,7 +197,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 5.53
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for an upsert with 10 rows" $ do
r <- request methodPost "/tiobe_pls"
Expand All @@ -211,7 +211,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
liftIO $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 5.53
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for an upsert with 100 rows" $ do
r <- request methodPost "/tiobe_pls"
Expand All @@ -225,7 +225,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
liftIO $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 5.53
totalCost `shouldSatisfy` (> 0)

it "outputs the total cost for an upsert with 1000 rows" $ do
r <- request methodPost "/tiobe_pls"
Expand All @@ -239,7 +239,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
liftIO $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 5.53
totalCost `shouldSatisfy` (> 0)

it "outputs the plan for application/vnd.pgrst.object" $ do
r <- request methodDelete "/projects?id=eq.6"
Expand All @@ -266,7 +266,7 @@ spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8")
resHeaders `shouldSatisfy` notZeroContentLength
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
totalCost `shouldBe` 68.56
totalCost `shouldSatisfy` (> 0)

describe "text format" $ do
it "outputs the total cost for a function call" $ do
Expand Down
1 change: 1 addition & 0 deletions test/spec/fixtures/load.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

\set ON_ERROR_STOP on

\ir ../../orioledb.sql
\ir database.sql
\ir roles.sql
\ir schema.sql
Expand Down