Skip to content
Open
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
7 changes: 7 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ jobs:
run: epmd -daemon
- name: Install Node dependencies
run: 'cd test/integration/js/; npm install'
- name: Ensure psql client
run: |
if ! command -v psql >/dev/null; then
echo "Installing psql client"
sudo apt-get update -qq
sudo apt-get install -qq -y postgresql-client
fi
- name: Run tests
run: mix coveralls.lcov --only integration --trace
- name: Upload Parallel Coverage Report
Expand Down
2 changes: 1 addition & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ config :supavisor,
System.get_env("SESSION_PROXY_PORTS", "12100,12101,12102,12103") |> parse_integer_list.(),
transaction_proxy_ports:
System.get_env("TRANSACTION_PROXY_PORTS", "12104,12105,12106,12107") |> parse_integer_list.(),
max_pools: 5,
max_pools: 10,
reconnect_retries: System.get_env("RECONNECT_RETRIES", "5") |> String.to_integer(),
subscribe_retries: System.get_env("SUBSCRIBE_RETRIES", "5") |> String.to_integer()

Expand Down
3 changes: 2 additions & 1 deletion priv/repo/seeds_after_migration.exs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ end)
# Create tenants with specific prepared statements feature flag settings for transaction mode
[
{"proxy_tenant_ps_enabled", %{"named_prepared_statements" => true}},
{"proxy_tenant_ps_disabled", %{"named_prepared_statements" => false}}
{"proxy_tenant_ps_disabled", %{"named_prepared_statements" => false}},
{"proxy_tenant_pgoptions", %{}}
]
|> Enum.each(fn {tenant, feature_flags} ->
if !Tenants.get_tenant_by_external_id(tenant) do
Expand Down
151 changes: 151 additions & 0 deletions test/integration/pgoptions_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
defmodule Supavisor.Integration.PgoptionsTest do
use Supavisor.DataCase, async: false

import ExUnit.CaptureLog

@tenant "proxy_tenant_pgoptions"

@moduletag integration: true

@psql System.find_executable("psql")
if is_nil(@psql) do
@moduletag skip: "psql executable is required for PGOPTIONS integration checks"
end

setup do
repo_conf = Application.fetch_env!(:supavisor, Repo)
port = Application.fetch_env!(:supavisor, :proxy_port_transaction)

{:ok,
%{
psql: @psql,
port: port,
db: repo_conf[:database],
user: "#{repo_conf[:username]}.#{@tenant}"
}}
end

test "PGOPTIONS --search_path=schemaA,schemaB", ctx do
result =
run_psql!(ctx, "SHOW search_path;", pgoptions: "--search_path=schemaA,schemaB")

assert result == "schemaA,schemaB"
end

test "PGOPTIONS -c search_path=custom-schema", ctx do
result =
run_psql!(ctx, "SHOW search_path;", pgoptions: "-c search_path=custom-schema")

assert result == "custom-schema"
end

test "PGOPTIONS --search_path schema with whitespaces", ctx do
result =
run_psql!(ctx, "SHOW search_path;", pgoptions: "--search_path=schemaA,\\ schemaB")

assert result == "schemaA, schemaB"
end

test "PGOPTIONS does not allow injecting additional -c flags after the --search_path", ctx do
default_timeout = run_psql!(ctx, "SHOW work_mem;")

injected_timeout =
run_psql!(ctx, "SHOW work_mem;", pgoptions: "--search_path=public -c work_mem=2047GB")

assert injected_timeout == default_timeout
assert injected_timeout != "2047GB"
end

test "Malformed option is ignored", ctx do
log =
capture_log([level: :debug], fn ->
assert run_psql!(ctx, "SHOW search_path;",
pgoptions: "--search_path=OK -malformed-option"
) == "OK"
end)

assert log =~ ~s(StartupOptions: ignored token "-malformed-option")
end

test "PGOPTIONS log_level switches Supavisor process log level", ctx do
log =
capture_log([level: :debug], fn ->
run_psql!(ctx, "SELECT 1;", pgoptions: "--log_level=notice")
end)

assert log =~ "Setting log level to :notice"
end

# TODO: https://github.com/supabase/supavisor/issues/343
@tag skip: "known issue #343"
test "PGOPTIONS -c application_name applies to upstream application_name", ctx do
result =
run_psql!(ctx, "SHOW application_name;", pgoptions: "-c application_name=from_options")

assert result == "from_options"
end

# TODO: handle Supavisor startup failures instead of restarts
@tag skip: "known issue: keeps reconnecting on invalid PGOPTIONS search_path"
test "PGOPTIONS --search_path invalid syntax", ctx do
log =
capture_log([level: :debug], fn ->
assert_raise ExUnit.AssertionError,
~r/(invalid value for parameter \"search_path\"|server closed the connection unexpectedly)/,
fn ->
run_psql!(ctx, "SHOW search_path;",
pgoptions: "--search_path=,--invalid-syntax--;("
)
end
end)

occurrences =
Regex.scan(~r/"SFATAL", "VFATAL", "C22023", "Minvalid value for parameter/, log)
|> length()

assert occurrences == 1
end

defp run_psql!(ctx, sql, opts \\ []) do
db_conf = Application.fetch_env!(:supavisor, Repo)

env =
[
{"PGHOST", "127.0.0.1"},
{"PGPORT", Integer.to_string(ctx.port)},
{"PGDATABASE", ctx.db},
{"PGUSER", ctx.user},
{"PGPASSWORD", db_conf[:password]},
{"PGSSLMODE", "disable"}
]
|> maybe_put_pgoptions(opts[:pgoptions])

args = [
"--no-psqlrc",
"--set",
"ON_ERROR_STOP=on",
"--tuples-only",
"-A",
"-c",
sql
]

{output, status} =
System.cmd(ctx.psql, args,
env: env,
stderr_to_stdout: true
)

assert status == 0, output

output
|> String.trim()
|> String.split("\n")
|> List.last()
|> String.trim()
end

defp maybe_put_pgoptions(env, nil), do: env
defp maybe_put_pgoptions(env, ""), do: env
defp maybe_put_pgoptions(env, value), do: [{"PGOPTIONS", value} | env]
end
Loading