Skip to content

Commit 24cc228

Browse files
authored
Task: Add tests for TraceService and CallbackTracingServer (#290)
* Add ModuleDiscoveryService.all_modules test * wip * Add tests for TraceService * Refactor * Add tests for CallbackTracingServer * Change receive/send to sleep/exit * Ignore LiveDebuggerDev in test coverage * Add tracing mechanism tests * Remove duplicate test * Update TraceService test * Update CallbackTracingServer tests * Change test to async * Refactor * Add verify_on_exit
1 parent 088c95b commit 24cc228

5 files changed

Lines changed: 364 additions & 4 deletions

File tree

mix.exs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ defmodule LiveDebugger.MixProject do
1616
name: "LiveDebugger",
1717
source_url: "https://github.com/software-mansion/live-debugger",
1818
description: "Tool for debugging LiveView applications",
19-
docs: docs()
19+
docs: docs(),
20+
test_coverage: [
21+
ignore_modules: [~r/^LiveDebuggerDev\./, DevWeb]
22+
]
2023
]
2124
end
2225

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
defmodule LiveDebugger.GenServers.CallbackTracingServerTest do
2+
@moduledoc false
3+
use ExUnit.Case, async: true
4+
5+
import Mox
6+
7+
alias LiveDebugger.Structs.Trace
8+
alias LiveDebugger.GenServers.CallbackTracingServer
9+
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
10+
alias LiveDebugger.MockModuleService
11+
alias LiveDebugger.MockDbg
12+
alias LiveDebugger.MockEtsTableServer
13+
alias LiveDebugger.MockPubSubUtils
14+
alias LiveDebugger.MockProcessService
15+
16+
@modules [
17+
CoolApp.LiveViews.UserDashboard,
18+
CoolApp.Service.UserService,
19+
CoolApp.LiveComponent.UserElement
20+
]
21+
22+
setup :verify_on_exit!
23+
24+
test "init/1" do
25+
assert {:ok, %{}} = CallbackTracingServer.init([])
26+
assert_receive :setup_tracing
27+
end
28+
29+
test "handle_call/3" do
30+
assert {:reply, :ok, %{}} == CallbackTracingServer.handle_call(:ping, self(), %{})
31+
end
32+
33+
test "proper tracing setup" do
34+
MockModuleService
35+
|> expect(:all, fn ->
36+
Enum.map(@modules, fn module -> {to_charlist(module), ~c"", false} end)
37+
end)
38+
|> expect(:loaded?, 6, fn _module -> true end)
39+
|> expect(:behaviours, 6, fn module -> get_behaviours(module) end)
40+
41+
MockDbg
42+
|> expect(:tracer, fn :process, {_handler, 0} -> :ok end)
43+
|> expect(:p, fn :all, :c -> :ok end)
44+
45+
get_live_view_callbacks(CoolApp.LiveViews.UserDashboard)
46+
|> Enum.each(&expect(MockDbg, :tp, fn &1, [] -> :ok end))
47+
48+
get_live_component_callbacks(CoolApp.LiveComponent.UserElement)
49+
|> Enum.each(&expect(MockDbg, :tp, fn &1, [] -> :ok end))
50+
51+
MockDbg
52+
|> expect(:tp, fn {Phoenix.LiveView.Diff, :delete_component, 2}, [] -> :ok end)
53+
54+
assert {:noreply, %{}} = CallbackTracingServer.handle_info(:setup_tracing, %{})
55+
end
56+
57+
describe "tracing mechanism" do
58+
setup do
59+
parent = self()
60+
61+
MockModuleService
62+
|> expect(:all, fn -> [] end)
63+
64+
MockDbg
65+
|> expect(:p, fn :all, :c -> :ok end)
66+
|> expect(:tp, fn {Phoenix.LiveView.Diff, :delete_component, 2}, [] -> :ok end)
67+
|> expect(:tracer, fn :process, {handle_trace, 0} -> send(parent, handle_trace) end)
68+
69+
:ok
70+
end
71+
72+
test "handle delete component trace" do
73+
parent = self()
74+
transport_pid = :c.pid(0, 0, 1)
75+
pid = :c.pid(0, 0, 2)
76+
cid = 3
77+
socket_id = "phx-GDrDzLLr4USWzwBC"
78+
module = Phoenix.LiveView.Diff
79+
function = :delete_component
80+
args = [cid, %{}]
81+
82+
expected_topic =
83+
PubSubUtils.component_deleted_topic(%{socket_id: socket_id, transport_pid: transport_pid})
84+
85+
MockProcessService
86+
|> expect(:state, fn ^pid ->
87+
{:ok, LiveDebugger.Fakes.state(transport_pid: transport_pid, socket_id: socket_id)}
88+
end)
89+
90+
MockPubSubUtils
91+
|> expect(:broadcast, fn ^expected_topic, {:new_trace, trace} ->
92+
send(parent, {:trace, trace})
93+
end)
94+
95+
assert {:noreply, %{}} = CallbackTracingServer.handle_info(:setup_tracing, %{})
96+
97+
assert_receive handle_trace
98+
assert 0 == handle_trace.({:trace, pid, :call, {module, function, args}}, 0)
99+
assert_receive {:trace, trace}
100+
101+
assert %Trace{
102+
id: 0,
103+
module: ^module,
104+
function: ^function,
105+
arity: 2,
106+
args: ^args,
107+
socket_id: ^socket_id,
108+
transport_pid: ^transport_pid,
109+
pid: ^pid,
110+
cid: %Phoenix.LiveComponent.CID{cid: ^cid}
111+
} = trace
112+
end
113+
114+
test "handle standard live view trace" do
115+
transport_pid = :c.pid(0, 0, 1)
116+
pid = :c.pid(0, 0, 2)
117+
socket_id = "phx-GDrDzLLr4USWzwBC"
118+
module = CoolApp.LiveViews.UserDashboard
119+
function = :handle_info
120+
121+
args = [
122+
:msg,
123+
%{transport_pid: transport_pid, socket: %Phoenix.LiveView.Socket{id: socket_id}}
124+
]
125+
126+
table = :ets.new(:test_table, [:ordered_set, :public])
127+
128+
expected_tsnf_topic = PubSubUtils.tsnf_topic(socket_id, transport_pid, pid, function)
129+
expected_ts_f_topic = PubSubUtils.ts_f_topic(socket_id, transport_pid, function)
130+
131+
MockEtsTableServer
132+
|> expect(:table!, fn ^pid -> table end)
133+
134+
MockPubSubUtils
135+
|> expect(:broadcast, fn ^expected_tsnf_topic, {:new_trace, _trace} -> :ok end)
136+
|> expect(:broadcast, fn ^expected_ts_f_topic, {:new_trace, _trace} -> :ok end)
137+
138+
assert {:noreply, %{}} = CallbackTracingServer.handle_info(:setup_tracing, %{})
139+
assert_receive handle_trace
140+
assert -1 == handle_trace.({:trace, pid, :call, {module, function, args}}, 0)
141+
assert [{0, trace}] = :ets.tab2list(table)
142+
143+
assert %Trace{
144+
id: 0,
145+
module: ^module,
146+
function: ^function,
147+
arity: 2,
148+
args: ^args,
149+
socket_id: ^socket_id,
150+
transport_pid: ^transport_pid,
151+
pid: ^pid,
152+
cid: nil
153+
} = trace
154+
end
155+
156+
test "handle unexpected trace" do
157+
assert {:noreply, %{}} = CallbackTracingServer.handle_info(:setup_tracing, %{})
158+
assert_receive handle_trace
159+
assert 0 == handle_trace.({:_, :c.pid(0, 0, 1), :_, {SomeModule, :some_func, []}}, 0)
160+
end
161+
end
162+
163+
defp get_behaviours(module) do
164+
case module do
165+
CoolApp.LiveViews.UserDashboard -> [Phoenix.LiveView]
166+
CoolApp.Service.UserService -> []
167+
CoolApp.LiveComponent.UserElement -> [Phoenix.LiveComponent]
168+
end
169+
end
170+
171+
defp get_live_view_callbacks(module) do
172+
[
173+
{module, :mount, 3},
174+
{module, :handle_params, 3},
175+
{module, :handle_info, 2},
176+
{module, :handle_call, 3},
177+
{module, :handle_cast, 2},
178+
{module, :terminate, 2},
179+
{module, :render, 1},
180+
{module, :handle_event, 3},
181+
{module, :handle_async, 3}
182+
]
183+
end
184+
185+
defp get_live_component_callbacks(module) do
186+
[
187+
{module, :mount, 1},
188+
{module, :update, 2},
189+
{module, :update_many, 1},
190+
{module, :render, 1},
191+
{module, :handle_event, 3},
192+
{module, :handle_async, 3}
193+
]
194+
end
195+
end

test/gen_servers/ets_table_server_test.exs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ defmodule LiveDebugger.GenServers.EtsTableServerTest do
22
@moduledoc false
33
use ExUnit.Case, async: true
44

5+
import Mox
6+
57
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
68
alias LiveDebugger.GenServers.EtsTableServer
79

10+
setup :verify_on_exit!
11+
812
test "start_link/1" do
913
assert {:ok, _pid} = EtsTableServer.start_link()
1014
GenServer.stop(EtsTableServer)
@@ -19,7 +23,7 @@ defmodule LiveDebugger.GenServers.EtsTableServerTest do
1923
pid = :c.pid(0, 0, 1)
2024

2125
LiveDebugger.MockEtsTableServer
22-
|> Mox.expect(:table!, fn ^pid -> :some_ref end)
26+
|> expect(:table!, fn ^pid -> :some_ref end)
2327

2428
assert :some_ref = EtsTableServer.table!(pid)
2529
end
@@ -28,7 +32,7 @@ defmodule LiveDebugger.GenServers.EtsTableServerTest do
2832
pid = :c.pid(0, 0, 1)
2933

3034
LiveDebugger.MockEtsTableServer
31-
|> Mox.expect(:delete_table!, fn ^pid -> :ok end)
35+
|> expect(:delete_table!, fn ^pid -> :ok end)
3236

3337
assert :ok = EtsTableServer.delete_table!(pid)
3438
end
@@ -47,7 +51,7 @@ defmodule LiveDebugger.GenServers.EtsTableServerTest do
4751
topic = PubSubUtils.process_status_topic(pid)
4852

4953
LiveDebugger.MockPubSubUtils
50-
|> Mox.expect(:broadcast, fn ^topic, {:process_status, :dead} -> :ok end)
54+
|> expect(:broadcast, fn ^topic, {:process_status, :dead} -> :ok end)
5155

5256
assert {:noreply, new_table_refs} =
5357
EtsTableServer.handle_info({:DOWN, :_, :process, pid, :_}, table_refs)

0 commit comments

Comments
 (0)