defmodule MicrowavepropWeb.TelemetryTest do use Microwaveprop.DataCase, async: false alias Ecto.Adapters.SQL.Sandbox alias MicrowavepropWeb.Telemetry describe "metrics/0" do test "returns a flat list of Telemetry.Metrics structs" do metrics = Telemetry.metrics() assert is_list(metrics) assert Enum.any?(metrics) for m <- metrics do assert is_struct(m) # Every metric carries its event path as a list of atoms. assert is_list(m.event_name) assert Enum.all?(m.event_name, &is_atom/1) end end test "covers each of the metric categories defined in the module" do # The categories are private functions that build distinct event # name prefixes; check one canonical metric per category exists. names = Enum.map(Telemetry.metrics(), & &1.name) name_strings = Enum.map(names, &Enum.join(&1, ".")) assert "phoenix.endpoint.stop.duration" in name_strings assert "microwaveprop.repo.query.total_time" in name_strings assert Enum.any?(name_strings, &String.starts_with?(&1, "vm.")) assert Enum.any?(name_strings, &String.starts_with?(&1, "microwaveprop.oban.")) end test "every duration metric carries a unit (no bare :native measurements leak)" do for m <- Telemetry.metrics(), String.ends_with?(to_string(List.last(m.name)), "duration") do assert m.unit != :unit, "#{inspect(m.name)} should declare a display unit" end end end describe "dispatch_oban_queue_depth/0" do test "emits one `oban.queue.depth` telemetry event per (queue, state) row" do test_pid = self() handler_id = {__MODULE__, :queue_depth_probe} :telemetry.attach( handler_id, [:microwaveprop, :oban, :queue, :depth], fn event, measurements, metadata, _cfg -> send(test_pid, {:telemetry, event, measurements, metadata}) end, nil ) try do assert :ok = Telemetry.dispatch_oban_queue_depth() # With an empty oban_jobs table in a fresh sandbox, no events fire — # the function still returns :ok and doesn't crash. If any rows # happen to be there, each must carry a queue+state tag. receive do {:telemetry, [:microwaveprop, :oban, :queue, :depth], %{count: n}, meta} -> assert is_integer(n) assert is_binary(meta.queue) assert Map.has_key?(meta, :state) after 200 -> :ok end after :telemetry.detach(handler_id) end end test "swallows DB errors without crashing the poller" do # Manually close the sandbox connection so any DB query raises; # the poller must still return :ok (telemetry is best-effort). Sandbox.checkin(Microwaveprop.Repo) assert :ok = Telemetry.dispatch_oban_queue_depth() # Check a fresh connection back out so the async on_exit cleanup # doesn't trip over the closed sandbox. Sandbox.checkout(Microwaveprop.Repo) end end describe "start_link/1" do test "starts a named Supervisor under a fresh registry" do # Different process name to avoid colliding with the already-running # application supervisor. # credo:disable-for-this-line Credo.Check.Warning.UnsafeToAtom sup_name = :"telemetry_under_test_#{System.unique_integer([:positive])}" {:ok, pid} = Supervisor.start_link(Telemetry, :ok, name: sup_name) assert Process.whereis(sup_name) == pid # Unlink before tearing down so the brutal-kill exit signal doesn't # propagate to the test process (which trap_exit defaults to off). Process.unlink(pid) Process.exit(pid, :kill) end end end