Skip to content

Commit 3af2473

Browse files
author
Garth Kidd
committed
Fix SpanCaptureReporter test spillage (#22)
* Discard spans started before `attach/0` was called * Trigger `report/2` and wait 1ms before `collect/0` * Set and advise `send_interval_ms: 100` to reduce unpredictability of `report/2` time, which with `send_interval_ms: 1` would sometimes wait until after `detach/0`
1 parent 221c58f commit 3af2473

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

config/config.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ if Mix.env() == :test do
99

1010
config :opencensus,
1111
reporters: [{Opencensus.TestSupport.SpanCaptureReporter, []}],
12-
send_interval_ms: 0
12+
send_interval_ms: 100
1313
end

lib/opencensus/span.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,10 @@ defmodule Opencensus.Span do
3434
def load(span_ctx) when is_tuple(span_ctx) do
3535
span_ctx |> SpanContext.from() |> Map.get(:span_id) |> load()
3636
end
37+
38+
@doc false
39+
def began_monotonic(record) when Record.is_record(record, :span) do
40+
{native_time, _native_offset} = span(record, :start_time)
41+
native_time
42+
end
3743
end

lib/opencensus/test_support/span_capture_reporter.ex

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule Opencensus.TestSupport.SpanCaptureReporter do
88
```elixir
99
if Mix.env() == :test do
1010
config :opencensus,
11-
send_interval_ms: 1,
11+
send_interval_ms: 100,
1212
reporters: [{Opencensus.TestSupport.SpanCaptureReporter, []}]
1313
end
1414
```
@@ -52,25 +52,52 @@ defmodule Opencensus.TestSupport.SpanCaptureReporter do
5252
end
5353

5454
@doc false
55-
def handler([__MODULE__], %{}, %{spans: spans}, pid), do: send(pid, {:spans, spans})
55+
def handler([__MODULE__], %{}, %{spans: spans}, {pid, attached_monotonic}) do
56+
started_after_attach? = fn span -> span |> Span.began_monotonic() >= attached_monotonic end
57+
filtered = spans |> Enum.filter(started_after_attach?)
58+
send(pid, {:spans, filtered})
59+
end
5660

5761
@doc "Attach the reporter to deliver spans to your process inbox."
58-
def attach, do: :telemetry.attach(__MODULE__, [__MODULE__], &handler/4, self())
62+
def attach do
63+
:telemetry.attach(__MODULE__, [__MODULE__], &handler/4, {self(), :erlang.monotonic_time()})
64+
end
65+
66+
@doc """
67+
Detach the reporter to stop delivering spans to your process inbox.
68+
69+
If still attached, triggers span delivery before detaching.
70+
"""
71+
def detach do
72+
if handler_attached?(), do: trigger_and_wait_for_span_delivery()
73+
:telemetry.detach(__MODULE__)
74+
end
5975

60-
@doc "Detach the reporter to stop delivering spans to your process inbox."
61-
def detach, do: :telemetry.detach(__MODULE__)
76+
@doc """
77+
Collect spans from your process inbox.
6278
63-
@doc "Collect spans from your process inbox."
79+
If still attached, triggers span delivery before collection.
80+
"""
6481
@spec collect() :: list(%Span{})
6582
def collect do
83+
if handler_attached?(), do: trigger_and_wait_for_span_delivery()
6684
collect_span_records([]) |> Enum.map(&Span.from/1)
6785
end
6886

87+
defp trigger_and_wait_for_span_delivery do
88+
send(:oc_reporter, :report_spans)
89+
:timer.sleep(1)
90+
end
91+
92+
defp handler_attached? do
93+
:telemetry.list_handlers([__MODULE__]) != []
94+
end
95+
6996
defp collect_span_records(acc) when is_list(acc) do
7097
receive do
7198
{:spans, spans} -> collect_span_records(acc ++ spans)
7299
after
73-
10 -> acc
100+
1 -> acc
74101
end
75102
end
76103
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule Opencensus.TestSupport.SpanCaptureReporterTest do
2+
use ExUnit.Case, async: false
3+
import Opencensus.Trace
4+
5+
alias Opencensus.TestSupport.SpanCaptureReporter
6+
7+
describe "Opencensus.TestSupport.SpanCaptureReporter.collect/3" do
8+
defp loop_count do
9+
case System.get_env("CI") do
10+
nil -> 10
11+
_ -> 1000
12+
end
13+
end
14+
15+
test "before detach, gets the just-finished span" do
16+
for _ <- 1..loop_count() do
17+
SpanCaptureReporter.attach()
18+
19+
with_child_span "inner" do
20+
[0, 1, 1, 2, 2, 2, 2, 3, 3, 4] |> Enum.random() |> :timer.sleep()
21+
:...
22+
end
23+
24+
assert SpanCaptureReporter.collect() |> length() == 1
25+
SpanCaptureReporter.detach()
26+
end
27+
end
28+
29+
test "after detach, gets the just-finished span" do
30+
for _ <- 1..loop_count() do
31+
SpanCaptureReporter.attach()
32+
33+
with_child_span "inner" do
34+
[0, 1, 1, 2, 2, 2, 2, 3, 3, 4] |> Enum.random() |> :timer.sleep()
35+
:...
36+
end
37+
38+
SpanCaptureReporter.detach()
39+
assert SpanCaptureReporter.collect() |> length() == 1
40+
end
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)