Skip to content

Commit

Permalink
test: add integration tests against Postgres.js (#479)
Browse files Browse the repository at this point in the history
  • Loading branch information
hauleth authored Nov 15, 2024
1 parent 43dd1fc commit 32c0086
Show file tree
Hide file tree
Showing 15 changed files with 2,916 additions and 4 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,54 @@ jobs:
- name: Run tests
run: mix test

integration:
name: Run integration tests
runs-on: u22-arm-runner
needs: [deps]

steps:
- uses: actions/checkout@v4
- name: Setup Elixir
id: beam
uses: erlef/setup-beam@v1
with:
otp-version: '25.3.2.7'
elixir-version: '1.14.5'
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Set up Rust
uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Cache Mix
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Cache native
uses: actions/cache@v4
with:
path: |
_build/${{ env.MIX_ENV }}/lib/supavisor/native
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-build-native-${{ hashFiles(format('{0}{1}', github.workspace, '/native/**/Cargo.lock')) }}
restore-keys: |
${{ runner.os }}-build-native-
- name: Compile deps
run: mix deps.compile
- name: Compile
run: mix compile
- name: Set up Postgres
run: docker-compose -f ./docker-compose.db.yml up -d
- name: Start epmd
run: epmd -daemon
- name: Run tests
run: mix test --only integration --trace

dialyzer:
name: Dialyze
runs-on: u22-arm-runner
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:
- ./dev/postgres:/docker-entrypoint-initdb.d/
# Uncomment to set MD5 authentication method on uninitialized databases
# - ./dev/postgres/md5/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf -c max_prepared_transactions=2000
environment:
POSTGRES_HOST: /var/run/postgresql
POSTGRES_PASSWORD: postgres
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:
- ./dev/postgres:/docker-entrypoint-initdb.d/
# Uncomment to set MD5 authentication method on uninitialized databases
# - ./dev/postgres/md5/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf -c max_prepared_transactions=2000
environment:
POSTGRES_HOST: /var/run/postgresql
POSTGRES_PASSWORD: postgres
Expand Down
18 changes: 17 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@
{
pre-commit.hooks = {
alejandra.enable = true;
typos.enable = true;
typos = {
enable = true;
excludes = [
"test/integration/"
];
};
};
}
{
Expand All @@ -78,20 +83,31 @@

services.postgres = {
enable = true;
package = pkgs.postgresql_15;
initialScript = ''
${builtins.readFile ./dev/postgres/00-setup.sql}
CREATE USER postgres SUPERUSER PASSWORD 'postgres';
'';
listen_addresses = "127.0.0.1";
port = 6432;
settings = {
max_prepared_transactions = 262143;
};
};

process.implementation = "honcho";

# Force connection through TCP instead of Unix socket
env.PGHOST = lib.mkForce "";
}
{
languages.javascript = {
enable = true;
bun.enable = true;
yarn.enable = true;
};
}
({
pkgs,
lib,
Expand Down
125 changes: 125 additions & 0 deletions test/integration/external_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
defmodule Supavisor.Integration.ExternalTest do
use ExUnit.Case, async: false

@moduletag integration: true

setup_all do
npm =
get_tool("yarn") || get_tool("npm") || get_tool("bun") ||
raise "Cannot find neither Yarn nor NPM"

assert {_, 0} = System.cmd(npm, ~w[install], cd: suite("js"))

{:ok, npm: npm}
end

setup :external_id

setup ctx do
if get_tool(ctx.runtime) do
:ok
else
raise "Runtime not available"
end
end

describe "Postgres.js" do
@describetag library: "postgres.js", suite: "js"

@tag runtime: "node", mode: "session"
test "Node session", ctx do
assert_run(ctx, ~w[postgres/index.js])
end

@tag runtime: "node", mode: "transaction"
test "Node transaction", ctx do
assert_run(ctx, ~w[postgres/index.js])
end

# These currently do not pass
# @tag runtime: "bun", mode: "session"
# test "Bun session", ctx do
# assert_run ctx, ~w[postgres/index.js], suite: "js"
# end
#
# @tag runtime: "bun", mode: "transaction"
# test "Bun transaction", ctx do
# assert_run ctx, ~w[postgres/index.js], suite: "js"
# end
#
# @tag runtime: "deno", mode: "session"
# test "Deno session", ctx do
# assert_run ctx, ~w[run --allow-all postgres/index.js], suite: "js"
# end
#
# @tag runtime: "deno", mode: "transaction"
# test "Deno transaction", ctx do
# assert_run ctx, ~w[run --allow-all postgres/index.js], suite: "js"
# end
end

defp assert_run(ctx, args, opts \\ []) do
suite = suite(ctx.suite)

env =
[
{"PGMODE", ctx.mode},
{"PGDATABASE", ctx.db},
{"PGHOST", "localhost"},
{"PGPORT", to_string(port(ctx.mode))},
{"PGUSER", ctx.user},
{"PGPASS", "postgres"}
] ++ (opts[:env] || [])

assert {output, code} =
System.cmd(ctx.runtime, args,
env: env,
cd: suite,
stderr_to_stdout: true
)

assert code == 0, output
end

## UTILS

defp suite(name), do: Path.join(__DIR__, name)

defp get_tool(name), do: System.find_executable(name)

defp port("session"), do: Application.fetch_env!(:supavisor, :proxy_port_session)
defp port("transaction"), do: Application.fetch_env!(:supavisor, :proxy_port_transaction)

defp external_id(ctx) do
external_id =
[ctx.runtime, ctx.library, ctx.mode]
|> Enum.map_join("_", &String.replace(&1, ~r/\W/, ""))

# Ensure that there are no leftovers
_ = Supavisor.Tenants.delete_tenant_by_external_id(external_id)

_ = Supavisor.Repo.query("DROP DATABASE IF EXISTS #{external_id}")
assert {:ok, _} = Supavisor.Repo.query("CREATE DATABASE #{external_id}")

assert {:ok, tenant} =
Supavisor.Tenants.create_tenant(%{
default_parameter_status: %{},
db_host: "localhost",
db_port: 6432,
db_database: external_id,
auth_query: "SELECT rolname, rolpassword FROM pg_authid WHERE rolname=$1;",
external_id: external_id,
users: [
%{
"pool_size" => 3,
"db_user" => "postgres",
"db_password" => "postgres",
"is_manager" => true,
"mode_type" => "session"
}
]
})

{:ok, user: "postgres.#{external_id}", db: tenant.db_database, external_id: external_id}
end
end
1 change: 1 addition & 0 deletions test/integration/js/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
13 changes: 13 additions & 0 deletions test/integration/js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "supavisor-integration",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"license": "MIT",
"scripts": {
"test:postgres": "node ./postgres/index.js"
},
"dependencies": {
"postgres": "^3.4.5"
}
}
2 changes: 2 additions & 0 deletions test/integration/js/postgres/copy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 2 3
4 5 6
Loading

0 comments on commit 32c0086

Please sign in to comment.