Current section
Files
Jump to
Current section
Files
test/tracer_test.exs
defmodule Tracer.Test do
use ExUnit.Case
import Tracer
import Tracer.Matcher
alias Tracer.{Tool.Count, Tool.Duration, Tool.CallSeq, Tool.Display}
setup do
# kill server if alive? for a fresh test
case Process.whereis(Tracer.Server) do
nil -> :ok
pid ->
Process.exit(pid, :kill)
:timer.sleep(10)
end
:ok
end
@tag :timing
test "can add multiple probes" do
{:ok, pid} = Tracer.start_server()
assert Process.alive?(pid)
test_pid = self()
tool = Tracer.tool(Display, forward_to: test_pid)
|> Tracer.Tool.add_probe(Tracer.probe(type: :call, process: :all,
match: local do Map.new() -> :ok end))
|> Tracer.Tool.add_probe(Tracer.probe(type: :gc, process: self()))
|> Tracer.Tool.add_probe(Tracer.probe(type: :set_on_link, process: [self()]))
|> Tracer.Tool.add_probe(Tracer.probe(type: :procs, process: [self()]))
|> Tracer.Tool.add_probe(Tracer.probe(type: :receive, process: [self()]))
|> Tracer.Tool.add_probe(Tracer.probe(type: :send, process: [self()]))
|> Tracer.Tool.add_probe(Tracer.probe(type: :sched, process: [self()]))
probes = Tracer.Tool.get_probes(tool)
assert probes ==
[
%Tracer.Probe{enabled?: true, flags: [:arity, :timestamp],
process_list: [:all], type: :call,
clauses: [%Tracer.Clause{matches: 0, type: :call,
desc: "local do Map.new() -> :ok end",
flags: [:local],
match_specs: [{[], [], [:ok]}],
mfa: {Map, :new, 0}}]},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp], process_list: [test_pid],
type: :gc},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp],
process_list: [test_pid], type: :set_on_link},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp],
process_list: [test_pid], type: :procs},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp],
process_list: [test_pid], type: :receive},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp],
process_list: [test_pid], type: :send},
%Tracer.Probe{clauses: [], enabled?: true,
flags: [:timestamp],
process_list: [test_pid], type: :sched}
]
Tracer.run(tool)
%{tracing: true} = :sys.get_state(Tracer.Server, 100)
assert_receive :started_tracing
res = :erlang.trace_info(test_pid, :flags)
assert res == {:flags, [:arity, :garbage_collection, :running,
:set_on_link, :procs,
:call, :receive, :send, :timestamp]}
res = :erlang.trace_info({Map, :new, 0}, :all)
assert res == {:all,
[traced: :local,
match_spec: [{[], [], [:ok]}],
meta: false,
meta_match_spec: false,
call_time: false,
call_count: false]}
end
test "display tool" do
test_pid = self()
res = run(Display,
forward_to: test_pid,
process: test_pid,
match: local do Map.new() -> :ok end)
assert res == :ok
:timer.sleep(50)
%{tracing: true} = :sys.get_state(Tracer.Server, 100)
Map.new()
assert_receive :started_tracing
res = stop()
assert res == :ok
assert_receive %Tracer.EventCall{arity: 0, fun: :new, message: nil,
mod: Map, pid: ^test_pid, ts: _}
assert_receive {:done_tracing, :stop_command}
# not expeting more events
refute_receive(_)
end
test "count tool" do
test_pid = self()
res = run(Count,
process: test_pid,
forward_to: test_pid,
match: global do Map.new(%{a: a}); Map.new(%{b: b}) end)
assert res == :ok
:timer.sleep(50)
%{tracing: true} = :sys.get_state(Tracer.Server, 100)
Map.new(%{})
Map.new(%{})
Map.new(%{})
Map.new(%{})
Map.new(%{a: :foo})
Map.new(%{a: :foo})
Map.new(%{b: :bar})
Map.new(%{b: :bar})
Map.new(%{b: :bar})
Map.new(%{b: :bar})
Map.new(%{b: :bar})
Map.new(%{b: :bar})
assert_receive :started_tracing
res = stop()
assert res == :ok
assert_receive %Count.Event{counts:
[{[a: :foo], 2},
{[b: :bar], 6}]}
assert_receive {:done_tracing, :stop_command}
# not expeting more events
refute_receive(_)
end
def recur_len([], acc), do: acc
def recur_len([_h | t], acc), do: recur_len(t, acc + 1)
test "duration tool" do
test_pid = self()
res = run(Duration,
process: test_pid,
forward_to: test_pid,
match: local Tracer.Test.recur_len(list, val))
assert res == :ok
:timer.sleep(50)
%{tracing: true} = :sys.get_state(Tracer.Server, 100)
recur_len([1, 2, 3, 4, 5], 0)
recur_len([1, 2, 3, 5], 2)
assert_receive :started_tracing
assert_receive(%{pid: ^test_pid, mod: Tracer.Test, fun: :recur_len,
arity: 2, duration: _, message: [[:list, [1, 2, 3, 4, 5]], [:val, 0]]})
assert_receive(%{pid: ^test_pid, mod: Tracer.Test, fun: :recur_len,
arity: 2, duration: _, message: [[:list, [1, 2, 3, 5]], [:val, 2]]})
res = stop()
assert res == :ok
assert_receive {:done_tracing, :stop_command}
# not expeting more events
refute_receive(_)
end
@tag :timing
test "call_seq tool" do
test_pid = self()
res = run(CallSeq,
process: test_pid,
forward_to: test_pid,
show_args: true,
show_return: true,
ignore_recursion: false,
start_match: Tracer.Test)
assert res == :ok
:timer.sleep(10)
assert_receive :started_tracing
recur_len([1, 2, 3, 4, 5], 0)
:timer.sleep(10)
res = stop()
assert res == :ok
assert_receive %CallSeq.Event{arity: 2, depth: 0, fun: :recur_len, message: [[[1, 2, 3, 4, 5], 0]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 1, fun: :recur_len, message: [[[2, 3, 4, 5], 1]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 2, fun: :recur_len, message: [[[3, 4, 5], 2]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 3, fun: :recur_len, message: [[[4, 5], 3]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 4, fun: :recur_len, message: [[[5], 4]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 5, fun: :recur_len, message: [[[], 5]], mod: Tracer.Test, pid: _, return_value: nil, type: :enter}
assert_receive %CallSeq.Event{arity: 2, depth: 5, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive %CallSeq.Event{arity: 2, depth: 4, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive %CallSeq.Event{arity: 2, depth: 3, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive %CallSeq.Event{arity: 2, depth: 2, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive %CallSeq.Event{arity: 2, depth: 1, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive %CallSeq.Event{arity: 2, depth: 0, fun: :recur_len, message: nil, mod: Tracer.Test, pid: _, return_value: 5, type: :exit}
assert_receive {:done_tracing, :stop_command}
# not expeting more events
refute_receive(_)
end
end