Skip to content

Commit bc6284d

Browse files
committed
test: add tests for different auth methods (scram-sha-256, password, md5)
1 parent e1a6779 commit bc6284d

File tree

6 files changed

+301
-126
lines changed

6 files changed

+301
-126
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ priv/native/*
4141
/.pre-commit-config.yaml
4242
*.coverdata
4343
/tmp
44+
45+
.devenv/
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
defmodule Supavisor.Integration.AuthenticationMethodsTest do
2+
use SupavisorWeb.ConnCase, async: false
3+
use Supavisor.PostgresCase, async: false
4+
5+
import Supavisor.Support.Tenants
6+
7+
@moduletag integration_docker: true
8+
9+
@auth_configs %{
10+
"scram-sha-256": [
11+
hostname: "localhost",
12+
port: 6433,
13+
database: "postgres",
14+
username: "postgres",
15+
password: "postgres"
16+
],
17+
password: [
18+
hostname: "localhost",
19+
port: 6434,
20+
database: "postgres",
21+
username: "postgres",
22+
password: "postgres",
23+
volume: "./dev/postgres/password/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf",
24+
environment: "--auth-host=password"
25+
]
26+
# md5: [
27+
# hostname: "localhost",
28+
# port: 6434,
29+
# database: "postgres",
30+
# username: "postgres",
31+
# password: "postgres",
32+
# volume: "./dev/postgres/md5/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf",
33+
# environment: "--auth-host=md5"
34+
# ]
35+
}
36+
37+
for {key, auth_config} <- @auth_configs do
38+
describe "#{key}" do
39+
setup %{conn: conn} do
40+
external_id = unquote(key)
41+
container_name = container_name(external_id)
42+
43+
cleanup_containers(container_name)
44+
45+
jwt = gen_token()
46+
47+
conn =
48+
conn
49+
|> put_req_header("accept", "application/json")
50+
|> put_req_header("authorization", "Bearer " <> jwt)
51+
52+
on_exit(fn -> cleanup_containers(container_name) end)
53+
54+
{:ok, conn: conn, container_name: container_name, external_id: external_id}
55+
end
56+
57+
test "starts postgres and connects through proxy", %{
58+
conn: conn,
59+
container_name: container_name,
60+
external_id: external_id
61+
} do
62+
opts =
63+
Keyword.merge(unquote(auth_config),
64+
container_name: container_name,
65+
external_id: external_id
66+
)
67+
68+
start_postgres_container(opts)
69+
create_tenant(conn, opts)
70+
71+
assert :ok = test_connection(opts)
72+
73+
stop_postgres_container(container_name)
74+
terminate_tenant(conn, external_id)
75+
end
76+
end
77+
end
78+
79+
defp test_connection(opts) do
80+
connection_opts = connection_opts(opts)
81+
82+
assert {:ok, conn} = Postgrex.start_link(connection_opts)
83+
assert {:ok, %{rows: [[_version_string]]}} = Postgrex.query(conn, "SELECT version();", [])
84+
85+
:ok
86+
end
87+
88+
defp container_name(internal_id), do: "supavisor-db-#{internal_id}"
89+
end
Lines changed: 32 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
defmodule Supavisor.Integration.PostgresSwitchingTest do
22
use SupavisorWeb.ConnCase, async: false
3+
use Supavisor.PostgresCase, async: false
34

4-
alias Supavisor.Jwt.Token
5+
import Supavisor.Support.Tenants
56

67
@moduletag integration_docker: true
78

@@ -13,7 +14,8 @@ defmodule Supavisor.Integration.PostgresSwitchingTest do
1314
@db_host "localhost"
1415

1516
setup %{conn: conn} do
16-
cleanup_containers()
17+
containers = [container_name(15), container_name(16)]
18+
cleanup_containers(containers)
1719

1820
jwt = gen_token()
1921

@@ -22,17 +24,19 @@ defmodule Supavisor.Integration.PostgresSwitchingTest do
2224
|> put_req_header("accept", "application/json")
2325
|> put_req_header("authorization", "Bearer " <> jwt)
2426

25-
on_exit(fn -> cleanup_containers() end)
27+
on_exit(fn -> cleanup_containers(containers) end)
2628

2729
{:ok, conn: conn}
2830
end
2931

3032
test "PostgreSQL upgrade scenario: 15 -> 16", %{conn: conn} do
31-
start_postgres_container(15)
32-
create_tenant(conn)
33-
assert :ok = test_connection()
33+
opts = build_opts(15, @tenant_name)
3434

35-
stop_postgres_container(15)
35+
start_postgres_container(opts)
36+
create_tenant(conn, opts)
37+
assert :ok = test_connection(opts)
38+
39+
stop_postgres_container(opts[:container_name])
3640

3741
# Ideally, we shouldn't need to terminate the tenant manually here.
3842
#
@@ -43,139 +47,41 @@ defmodule Supavisor.Integration.PostgresSwitchingTest do
4347
#
4448
# Currently, if we don't terminate the tenant (or restart supavisor),
4549
# we get authentication errors.
46-
terminate_tenant(conn)
50+
terminate_tenant(conn, @tenant_name)
4751
Process.sleep(2000)
48-
start_postgres_container(16)
49-
50-
assert :ok = test_connection()
51-
end
52-
53-
defp start_postgres_container(version) do
54-
container_name = container_name(version)
55-
56-
{_output, 0} =
57-
System.cmd("docker", [
58-
"run",
59-
"-d",
60-
"--name",
61-
container_name,
62-
"-e",
63-
"POSTGRES_USER=#{@postgres_user}",
64-
"-e",
65-
"POSTGRES_PASSWORD=#{@postgres_password}",
66-
"-e",
67-
"POSTGRES_DB=#{@postgres_db}",
68-
"-p",
69-
"#{@postgres_port}:5432",
70-
"postgres:#{version}"
71-
])
72-
73-
wait_for_postgres()
74-
end
75-
76-
defp wait_for_postgres(max_attempts \\ 30) do
77-
wait_for_postgres(1, max_attempts)
78-
end
79-
80-
defp wait_for_postgres(attempt, max_attempts) when attempt != max_attempts do
81-
case System.cmd("pg_isready", [
82-
"-h",
83-
"localhost",
84-
"-p",
85-
to_string(@postgres_port),
86-
"-U",
87-
@postgres_user,
88-
"-d",
89-
@postgres_db
90-
]) do
91-
{_, 0} ->
92-
:ok
93-
94-
_ ->
95-
Process.sleep(1000)
96-
wait_for_postgres(attempt + 1, max_attempts)
97-
end
98-
end
9952

100-
defp wait_for_postgres(_attempt, max_attempts) do
101-
raise "PostgreSQL failed to start within #{max_attempts} seconds"
102-
end
53+
opts = build_opts(16, @tenant_name)
54+
start_postgres_container(opts)
10355

104-
defp stop_postgres_container(version) do
105-
System.cmd("docker", ["stop", container_name(version)])
106-
System.cmd("docker", ["rm", container_name(version)])
56+
assert :ok = test_connection(opts)
10757
end
10858

109-
defp create_tenant(conn) do
110-
tenant_attrs = %{
111-
db_host: @db_host,
112-
db_port: @postgres_port,
113-
db_database: @postgres_db,
114-
external_id: @tenant_name,
115-
ip_version: "auto",
116-
enforce_ssl: false,
117-
require_user: false,
118-
auth_query: "SELECT rolname, rolpassword FROM pg_authid WHERE rolname=$1;",
119-
users: [
120-
%{
121-
db_user: @postgres_user,
122-
db_password: @postgres_password,
123-
pool_size: 20,
124-
mode_type: "transaction",
125-
is_manager: true
126-
}
127-
]
128-
}
129-
130-
conn = put(conn, Routes.tenant_path(conn, :update, @tenant_name), tenant: tenant_attrs)
131-
132-
case conn.status do
133-
status when status in 200..201 ->
134-
:ok
135-
136-
_status ->
137-
:ok
138-
end
59+
defp build_opts(version, external_id) do
60+
Keyword.merge(postgres_container_opts(version),
61+
container_name: container_name(version),
62+
external_id: external_id
63+
)
13964
end
14065

141-
defp terminate_tenant(conn) do
142-
_conn = get(conn, Routes.tenant_path(conn, :terminate, @tenant_name))
143-
:ok
144-
end
145-
146-
defp test_connection do
147-
proxy_port = Application.fetch_env!(:supavisor, :proxy_port_transaction)
148-
149-
connection_opts = [
150-
hostname: @db_host,
151-
port: proxy_port,
152-
database: @postgres_db,
153-
username: "#{@postgres_user}.#{@tenant_name}",
66+
defp postgres_container_opts(version) do
67+
[
68+
image: "postgres:#{version}",
69+
port: @postgres_port,
70+
user: @postgres_user,
15471
password: @postgres_password,
155-
# This is important as otherwise Postgrex may try to reconnect in case of errors.
156-
# We want to avoid that, as it hides connection errors.
157-
backoff: nil
72+
database: @postgres_db,
73+
hostname: @db_host
15874
]
75+
end
76+
77+
defp test_connection(opts) do
78+
connection_opts = connection_opts(opts)
15979

16080
assert {:ok, conn} = Postgrex.start_link(connection_opts)
16181
assert {:ok, %{rows: [[_version_string]]}} = Postgrex.query(conn, "SELECT version();", [])
16282

16383
:ok
16484
end
16585

166-
defp container_name(version) do
167-
"test_postgres_#{version}_switching"
168-
end
169-
170-
defp cleanup_containers do
171-
[15, 16]
172-
|> Enum.each(fn version ->
173-
System.cmd("docker", ["rm", "-f", container_name(version)], stderr_to_stdout: true)
174-
end)
175-
end
176-
177-
defp gen_token do
178-
secret = Application.fetch_env!(:supavisor, :api_jwt_secret)
179-
Token.gen!(secret)
180-
end
86+
defp container_name(version), do: "test_postgres_#{version}_switching"
18187
end

test/support/conn_case.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ defmodule SupavisorWeb.ConnCase do
1717

1818
use ExUnit.CaseTemplate
1919

20+
alias Supavisor.Jwt.Token
21+
2022
using do
2123
quote do
2224
# Import conveniences for testing with connections
@@ -35,4 +37,9 @@ defmodule SupavisorWeb.ConnCase do
3537
Supavisor.DataCase.setup_sandbox(tags)
3638
{:ok, conn: Phoenix.ConnTest.build_conn()}
3739
end
40+
41+
def gen_token do
42+
secret = Application.fetch_env!(:supavisor, :api_jwt_secret)
43+
Token.gen!(secret)
44+
end
3845
end

0 commit comments

Comments
 (0)