Skip to content

Commit 2f6b2a6

Browse files
authored
fix: mocks for supervised tasks (#750)
Fix mocks for supervised tasks
1 parent 15f69d7 commit 2f6b2a6

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

lib/tesla/mock.ex

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -229,23 +229,12 @@ defmodule Tesla.Mock do
229229

230230
# Gets the mock fun for the current process or its ancestors
231231
defp pdict_get do
232-
pid_holder =
233-
Enum.find(Process.get(:"$ancestors", []), self(), fn ancestor ->
234-
is_holder? =
235-
ancestor
236-
|> Process.info()
237-
|> Keyword.get(:dictionary)
238-
|> Keyword.get(__MODULE__)
239-
240-
!is_nil(is_holder?)
241-
end)
242-
|> case do
243-
nil -> raise "Unknown pid_holder in mock"
244-
pid when is_pid(pid) -> pid
245-
name when is_atom(name) -> Process.whereis(name)
246-
end
232+
potential_mock_holder_pids = [self() | Enum.reverse(Process.get(:"$callers", []))]
247233

248-
pid_holder |> Process.info() |> Keyword.get(:dictionary) |> Keyword.get(__MODULE__)
234+
Enum.find_value(potential_mock_holder_pids, nil, fn pid ->
235+
{:dictionary, process_dictionary} = Process.info(pid, :dictionary)
236+
Keyword.get(process_dictionary, __MODULE__)
237+
end)
249238
end
250239

251240
defp agent_set(fun) do

test/tesla/mock_test.exs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,41 @@ defmodule Tesla.MockTest do
113113
end
114114
end
115115

116+
describe "supervised task" do
117+
test "allows mocking in the caller process" do
118+
# in real apps, task supervisor will be part of the supervision tree
119+
# and it won't be an ancestor of the test process
120+
# to simulate that, we will set the mock in a task
121+
#
122+
# test_process
123+
# |-mocking_task will set the mock and create the supervised task
124+
# `-task supervisor
125+
# `- supervised_task
126+
# this way, mocking_task is not an $ancestor of the supervised_task
127+
# but it is $caller
128+
{:ok, supervisor_pid} = start_supervised(Task.Supervisor, restart: :temporary)
129+
130+
mocking_task =
131+
Task.async(fn ->
132+
mock(fn
133+
%{url: "/callers-test"} ->
134+
{:ok, %Tesla.Env{status: 200, body: "callers work"}}
135+
end)
136+
137+
supervised_task =
138+
Task.Supervisor.async(supervisor_pid, fn ->
139+
assert {:ok, %Tesla.Env{} = env} = Client.get("/callers-test")
140+
assert env.status == 200
141+
assert env.body == "callers work"
142+
end)
143+
144+
Task.await(supervised_task)
145+
end)
146+
147+
Task.await(mocking_task)
148+
end
149+
end
150+
116151
describe "without mock" do
117152
test "raise on unmocked request" do
118153
assert_raise Tesla.Mock.Error, fn ->

0 commit comments

Comments
 (0)