Skip to content

Commit

Permalink
Fix SpanCaptureReporter test spillage (#22)
Browse files Browse the repository at this point in the history
* 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`
  • Loading branch information
Garth Kidd committed Aug 3, 2019
1 parent 221c58f commit 3af2473
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 8 deletions.
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ if Mix.env() == :test do

config :opencensus,
reporters: [{Opencensus.TestSupport.SpanCaptureReporter, []}],
send_interval_ms: 0
send_interval_ms: 100
end
6 changes: 6 additions & 0 deletions lib/opencensus/span.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,10 @@ defmodule Opencensus.Span do
def load(span_ctx) when is_tuple(span_ctx) do
span_ctx |> SpanContext.from() |> Map.get(:span_id) |> load()
end

@doc false
def began_monotonic(record) when Record.is_record(record, :span) do
{native_time, _native_offset} = span(record, :start_time)
native_time
end
end
41 changes: 34 additions & 7 deletions lib/opencensus/test_support/span_capture_reporter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule Opencensus.TestSupport.SpanCaptureReporter do
```elixir
if Mix.env() == :test do
config :opencensus,
send_interval_ms: 1,
send_interval_ms: 100,
reporters: [{Opencensus.TestSupport.SpanCaptureReporter, []}]
end
```
Expand Down Expand Up @@ -52,25 +52,52 @@ defmodule Opencensus.TestSupport.SpanCaptureReporter do
end

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

@doc "Attach the reporter to deliver spans to your process inbox."
def attach, do: :telemetry.attach(__MODULE__, [__MODULE__], &handler/4, self())
def attach do
:telemetry.attach(__MODULE__, [__MODULE__], &handler/4, {self(), :erlang.monotonic_time()})
end

@doc """
Detach the reporter to stop delivering spans to your process inbox.
If still attached, triggers span delivery before detaching.
"""
def detach do
if handler_attached?(), do: trigger_and_wait_for_span_delivery()
:telemetry.detach(__MODULE__)
end

@doc "Detach the reporter to stop delivering spans to your process inbox."
def detach, do: :telemetry.detach(__MODULE__)
@doc """
Collect spans from your process inbox.
@doc "Collect spans from your process inbox."
If still attached, triggers span delivery before collection.
"""
@spec collect() :: list(%Span{})
def collect do
if handler_attached?(), do: trigger_and_wait_for_span_delivery()
collect_span_records([]) |> Enum.map(&Span.from/1)
end

defp trigger_and_wait_for_span_delivery do
send(:oc_reporter, :report_spans)
:timer.sleep(1)
end

defp handler_attached? do
:telemetry.list_handlers([__MODULE__]) != []
end

defp collect_span_records(acc) when is_list(acc) do
receive do
{:spans, spans} -> collect_span_records(acc ++ spans)
after
10 -> acc
1 -> acc
end
end
end
43 changes: 43 additions & 0 deletions test/opencensus_test_support_span_capture_reporter_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule Opencensus.TestSupport.SpanCaptureReporterTest do
use ExUnit.Case, async: false
import Opencensus.Trace

alias Opencensus.TestSupport.SpanCaptureReporter

describe "Opencensus.TestSupport.SpanCaptureReporter.collect/3" do
defp loop_count do
case System.get_env("CI") do
nil -> 10
_ -> 1000
end
end

test "before detach, gets the just-finished span" do
for _ <- 1..loop_count() do
SpanCaptureReporter.attach()

with_child_span "inner" do
[0, 1, 1, 2, 2, 2, 2, 3, 3, 4] |> Enum.random() |> :timer.sleep()
:...
end

assert SpanCaptureReporter.collect() |> length() == 1
SpanCaptureReporter.detach()
end
end

test "after detach, gets the just-finished span" do
for _ <- 1..loop_count() do
SpanCaptureReporter.attach()

with_child_span "inner" do
[0, 1, 1, 2, 2, 2, 2, 3, 3, 4] |> Enum.random() |> :timer.sleep()
:...
end

SpanCaptureReporter.detach()
assert SpanCaptureReporter.collect() |> length() == 1
end
end
end
end

0 comments on commit 3af2473

Please sign in to comment.