Skip to content

Commit faa5dc7

Browse files
authored
Bump nimble_ownership dep to make testing better (#700)
1 parent 26c166d commit faa5dc7

File tree

4 files changed

+106
-16
lines changed

4 files changed

+106
-16
lines changed

lib/sentry/test.ex

Lines changed: 89 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ defmodule Sentry.Test do
6464
@spec maybe_collect(Sentry.Event.t()) :: :collected | :not_collecting
6565
def maybe_collect(%Sentry.Event{} = event) do
6666
if Sentry.Config.test_mode?() do
67+
ensure_ownership_server_started()
68+
6769
case NimbleOwnership.fetch_owner(@server, callers(), @key) do
6870
{:ok, owner_pid} ->
6971
result =
@@ -102,24 +104,77 @@ defmodule Sentry.Test do
102104
103105
setup :start_collecting_sentry_reports
104106
107+
For a more flexible way to start collecting events, see `start_collecting/1`.
105108
"""
106109
@doc since: "10.2.0"
107110
@spec start_collecting_sentry_reports(map()) :: :ok
108111
def start_collecting_sentry_reports(_context \\ %{}) do
112+
start_collecting()
113+
end
114+
115+
@doc """
116+
Starts collecting events.
117+
118+
This function starts collecting events reported from the given (*owner*) process. If you want to
119+
allow other processes to report events, you need to *allow* them to report events back
120+
to the owner process. See `allow/2` for more information on allowances. If the owner
121+
process is already *allowed by another process*, this function raises an error.
122+
123+
## Options
124+
125+
* `:owner` - the PID of the owner process that will collect the events. Defaults to `self/0`.
126+
127+
* `:cleanup` - a boolean that controls whether collected resources around the owner process
128+
should be cleaned up when the owner process exits. Defaults to `true`. If `false`, you'll
129+
need to manually call `cleanup/1` to clean up the resources.
130+
131+
## Examples
132+
133+
The `:cleanup` option can be used to implement expectation-based tests, akin to something
134+
like [`Mox.expect/4`](https://hexdocs.pm/mox/1.1.0/Mox.html#expect/4).
135+
136+
test "implementing an expectation-based test workflow" do
137+
test_pid = self()
138+
139+
Test.start_collecting(owner: test_pid, cleanup: false)
140+
141+
on_exit(fn ->
142+
assert [%Event{} = event] = Test.pop_sentry_reports(test_pid)
143+
assert event.message.formatted == "Oops"
144+
assert :ok = Test.cleanup(test_pid)
145+
end)
146+
147+
assert {:ok, ""} = Sentry.capture_message("Oops")
148+
end
149+
150+
"""
151+
@doc since: "10.2.0"
152+
@spec start_collecting(keyword()) :: :ok
153+
def start_collecting(options \\ []) when is_list(options) do
154+
owner_pid = Keyword.get(options, :owner, self())
155+
cleanup? = Keyword.get(options, :cleanup, true)
156+
157+
callers =
158+
if owner_pid == self() do
159+
callers()
160+
else
161+
[owner_pid]
162+
end
163+
109164
# Make sure the ownership server is started (this is idempotent).
110165
ensure_ownership_server_started()
111166

112-
case NimbleOwnership.fetch_owner(@server, callers(), @key) do
167+
case NimbleOwnership.fetch_owner(@server, callers, @key) do
113168
# No-op
114-
{tag, owner_pid} when tag in [:ok, :shared_owner] and owner_pid == self() ->
169+
{tag, ^owner_pid} when tag in [:ok, :shared_owner] ->
115170
:ok
116171

117-
{:shared_owner, _pid} ->
172+
{:shared_owner, _other_pid} ->
118173
raise ArgumentError,
119174
"Sentry.Test is in global mode and is already collecting reported events"
120175

121-
{:ok, another_pid} ->
122-
raise ArgumentError, "already collecting reported events from #{inspect(another_pid)}"
176+
{:ok, other_pid} ->
177+
raise ArgumentError, "already collecting reported events from #{inspect(other_pid)}"
123178

124179
:error ->
125180
:ok
@@ -130,9 +185,25 @@ defmodule Sentry.Test do
130185
{:ignored, events || []}
131186
end)
132187

188+
if not cleanup? do
189+
:ok = NimbleOwnership.set_owner_to_manual_cleanup(@server, owner_pid)
190+
end
191+
133192
:ok
134193
end
135194

195+
@doc """
196+
Cleans up test resources associated with `owner_pid`.
197+
198+
See the `:cleanup` option in `start_collecting/1` and the corresponding
199+
example for more information.
200+
"""
201+
@doc since: "10.2.0"
202+
@spec cleanup(pid()) :: :ok
203+
def cleanup(owner_pid) when is_pid(owner_pid) do
204+
:ok = NimbleOwnership.cleanup_owner(@server, owner_pid)
205+
end
206+
136207
@doc """
137208
Allows `pid_to_allow` to collect events back to the root process via `owner_pid`.
138209
@@ -180,17 +251,22 @@ defmodule Sentry.Test do
180251
181252
"""
182253
@doc since: "10.2.0"
183-
@spec pop_sentry_reports() :: [Sentry.Event.t()]
184-
def pop_sentry_reports do
254+
@spec pop_sentry_reports(pid()) :: [Sentry.Event.t()]
255+
def pop_sentry_reports(owner_pid \\ self()) when is_pid(owner_pid) do
185256
result =
186-
NimbleOwnership.get_and_update(@server, self(), @key, fn
187-
nil -> {:not_collecting, []}
188-
events when is_list(events) -> {events, []}
189-
end)
257+
try do
258+
NimbleOwnership.get_and_update(@server, owner_pid, @key, fn
259+
nil -> {:not_collecting, []}
260+
events when is_list(events) -> {events, []}
261+
end)
262+
catch
263+
:exit, {:noproc, _} ->
264+
raise ArgumentError, "not collecting reported events from #{inspect(owner_pid)}"
265+
end
190266

191267
case result do
192268
{:ok, :not_collecting} ->
193-
raise ArgumentError, "not collecting reported events from #{inspect(self())}"
269+
raise ArgumentError, "not collecting reported events from #{inspect(owner_pid)}"
194270

195271
{:ok, events} ->
196272
events
@@ -203,7 +279,7 @@ defmodule Sentry.Test do
203279
## Helpers
204280

205281
defp ensure_ownership_server_started do
206-
case NimbleOwnership.start_link(name: @server) do
282+
case Supervisor.start_child(Sentry.Supervisor, NimbleOwnership.child_spec(name: @server)) do
207283
{:ok, pid} ->
208284
pid
209285

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ defmodule Sentry.Mixfile do
8282
defp deps do
8383
[
8484
{:nimble_options, "~> 1.0"},
85-
{:nimble_ownership, "~> 0.2.0"},
85+
{:nimble_ownership, "~> 0.3.0"},
8686

8787
# Optional dependencies
8888
{:hackney, "~> 1.8", optional: true},

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"},
2626
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
2727
"nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"},
28-
"nimble_ownership": {:hex, :nimble_ownership, "0.2.1", "3e44c72ebe8dd213db4e13aff4090aaa331d158e72ce1891d02e0ffb05a1eb2d", [:mix], [], "hexpm", "bf38d2ef4fb990521a4ecf112843063c1f58a5c602484af4c7977324042badee"},
28+
"nimble_ownership": {:hex, :nimble_ownership, "0.3.0", "29514f8779b26f50f9c07109677c98c0cc0b8025e89f82964dafa9cf7d657ec0", [:mix], [], "hexpm", "76c605106bc1e60f5b028b20203a1e0c90b4350b08e4b8a33f68bb50dcb6e837"},
2929
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
3030
"oban": {:hex, :oban, "2.17.6", "bac1dacd836edbf6a200ddd880db10faa2d39bb2e550ec6d19b3eb9c43852c2a", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "623f3554212e9a776e015156c47f076d66c7b74115ac47a7d3acba0294e65acb"},
3131
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},

test/sentry/test_test.exs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule Sentry.TestTest do
2-
use ExUnit.Case, async: true
2+
use ExUnit.Case, async: false
33

44
import Sentry.TestHelpers
55

@@ -174,4 +174,18 @@ defmodule Sentry.TestTest do
174174
assert [%Event{} = event] = Test.pop_sentry_reports()
175175
assert event.message.formatted == "Oops from parent process"
176176
end
177+
178+
test "implementing an expectation-based test workflow" do
179+
test_pid = self()
180+
181+
Test.start_collecting(owner: test_pid, cleanup: false)
182+
183+
on_exit(fn ->
184+
assert [%Event{} = event] = Test.pop_sentry_reports(test_pid)
185+
assert event.message.formatted == "Oops"
186+
assert :ok = Test.cleanup(test_pid)
187+
end)
188+
189+
assert {:ok, ""} = Sentry.capture_message("Oops")
190+
end
177191
end

0 commit comments

Comments
 (0)