Skip to content

Commit 3ff1818

Browse files
authored
Support multiple repos on sandbox plug API (#155)
1 parent 613614b commit 3ff1818

File tree

3 files changed

+69
-17
lines changed

3 files changed

+69
-17
lines changed

lib/phoenix_ecto/sql/sandbox.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ defmodule Phoenix.Ecto.SQL.Sandbox do
162162
163163
iex> {:ok, _owner_pid, metadata} = start_child(MyApp.Repo)
164164
"""
165-
def start_child(repo, opts \\ []) do
166-
child_spec = {SandboxSession, {repo, self(), opts}}
165+
def start_child(repos, opts \\ []) do
166+
child_spec = {SandboxSession, {repos, self(), opts}}
167167

168168
case DynamicSupervisor.start_child(SandboxSupervisor, child_spec) do
169169
{:ok, owner} ->
170-
metadata = metadata_for(repo, owner)
170+
metadata = metadata_for(repos, owner)
171171
{:ok, owner, metadata}
172172

173173
{:error, reason} ->
@@ -194,7 +194,7 @@ defmodule Phoenix.Ecto.SQL.Sandbox do
194194
%{
195195
header: Keyword.get(opts, :header, "user-agent"),
196196
path: get_path_info(opts[:at]),
197-
repo: opts[:repo],
197+
repos: List.wrap(opts[:repo]),
198198
sandbox: session_opts[:sandbox] || Ecto.Adapters.SQL.Sandbox,
199199
session_opts: session_opts
200200
}
@@ -205,8 +205,8 @@ defmodule Phoenix.Ecto.SQL.Sandbox do
205205

206206
@doc false
207207
def call(%Conn{method: "POST", path_info: path} = conn, %{path: path} = opts) do
208-
%{repo: repo, session_opts: session_opts} = opts
209-
{:ok, _owner, metadata} = start_child(repo, session_opts)
208+
%{repos: repos, session_opts: session_opts} = opts
209+
{:ok, _owner, metadata} = start_child(repos, session_opts)
210210

211211
conn
212212
|> put_resp_content_type("text/plain")

lib/phoenix_ecto/sql/sandbox_session.ex

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@ defmodule Phoenix.Ecto.SQL.SandboxSession do
44

55
@timeout 15_000
66

7-
def start_link({repo, client, opts}) do
8-
GenServer.start_link(__MODULE__, [repo, client, opts])
7+
def start_link({repos, client, opts}) do
8+
GenServer.start_link(__MODULE__, [repos, client, opts])
99
end
1010

11-
def init([repo, client, opts]) do
11+
def init([repos, client, opts]) do
1212
timeout = opts[:timeout] || @timeout
1313
sandbox = opts[:sandbox] || Ecto.Adapters.SQL.Sandbox
1414

15-
:ok = checkout_connection(sandbox, repo, client)
15+
:ok = checkout_connection(sandbox, repos, client)
1616
Process.send_after(self(), :timeout, timeout)
1717

18-
{:ok, %{repo: repo, client: client, sandbox: sandbox}}
18+
{:ok, %{repos: repos, client: client, sandbox: sandbox}}
1919
end
2020

2121
def handle_call(:checkin, _from, state) do
22-
:ok = checkin_connection(state.sandbox, state.repo, state.client)
22+
:ok = checkin_connection(state.sandbox, state.repos, state.client)
2323
{:stop, :shutdown, :ok, state}
2424
end
2525

2626
def handle_info(:timeout, state) do
27-
:ok = checkin_connection(state.sandbox, state.repo, state.client)
27+
:ok = checkin_connection(state.sandbox, state.repos, state.client)
2828
{:stop, :shutdown, state}
2929
end
3030

@@ -33,11 +33,19 @@ defmodule Phoenix.Ecto.SQL.SandboxSession do
3333
{:noreply, state}
3434
end
3535

36-
defp checkin_connection(sandbox, repo, client) do
37-
sandbox.checkin(repo, client: client)
36+
defp checkin_connection(sandbox, repos, client) do
37+
for repo <- repos do
38+
:ok = sandbox.checkin(repo, client: client)
39+
end
40+
41+
:ok
3842
end
3943

40-
defp checkout_connection(sandbox, repo, client) do
41-
sandbox.checkout(repo, client: client)
44+
defp checkout_connection(sandbox, repos, client) do
45+
for repo <- repos do
46+
:ok = sandbox.checkout(repo, client: client)
47+
end
48+
49+
:ok
4250
end
4351
end

test/phoenix_ecto/sql/sandbox_test.exs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,48 @@ defmodule PhoenixEcto.SQL.SandboxTest do
152152

153153
refute_receive {:allowed, MyRepo}
154154
end
155+
156+
test "checks out/in connection through sandbox owner at path with multiple repos" do
157+
# start new sandbox owner
158+
conn = call_plug_with_checkout(conn(:post, "/sandbox"), repo: [MyRepoOne, MyRepoTwo])
159+
assert "BeamMetadata" <> _ = user_agent = conn.resp_body
160+
assert conn.halted
161+
assert conn.status == 200
162+
assert_receive {:checkout, MyRepoOne}
163+
assert_receive {:checkout, MyRepoTwo}
164+
165+
# no allow with missing header
166+
conn = call_plug_with_checkout(conn(:get, "/"), repo: [MyRepoOne, MyRepoTwo])
167+
refute conn.halted
168+
refute_receive {:allowed, MyRepoOne}
169+
refute_receive {:allowed, MyRepoTwo}
170+
171+
# allows new request with metadata in header
172+
conn =
173+
conn(:get, "/")
174+
|> put_req_header("user-agent", user_agent)
175+
|> call_plug_with_checkout(repo: [MyRepoOne, MyRepoTwo])
176+
177+
refute conn.halted
178+
assert_receive {:allowed, MyRepoOne}
179+
assert_receive {:allowed, MyRepoTwo}
180+
181+
# checks in request with metadata
182+
conn =
183+
conn(:delete, "/sandbox")
184+
|> put_req_header("user-agent", user_agent)
185+
|> call_plug_with_checkout(repo: [MyRepoOne, MyRepoTwo])
186+
187+
assert conn.status == 200
188+
assert conn.halted
189+
190+
# old user agent refuses owner who has been checked in
191+
_conn =
192+
conn(:get, "/")
193+
|> put_req_header("user-agent", user_agent)
194+
|> call_plug_with_checkout(repo: [MyRepoOne, MyRepoTwo])
195+
196+
refute_receive {:allowed, MyRepoOne}
197+
refute_receive {:allowed, MyRepoTwo}
198+
end
155199
end

0 commit comments

Comments
 (0)