defmodule Microwaveprop.DataCase do @moduledoc """ Test case template for tests that need database access. """ use ExUnit.CaseTemplate alias Ecto.Adapters.SQL.Sandbox alias Microwaveprop.Propagation.ScoreCache alias Microwaveprop.Weather.GridCache using do quote do import Ecto import Ecto.Changeset import Ecto.Query import Microwaveprop.DataCase alias Microwaveprop.Repo end end setup tags do _owner = Microwaveprop.DataCase.setup_sandbox(tags) Microwaveprop.DataCase.reset_test_state() Req.Test.set_req_test_from_context(tags) :ok end @doc """ Reset state that persists across tests within a single ExUnit run. The sandbox isolates the database, but ETS-backed caches (GridCache, ScoreCache) and on-disk score files survive across test boundaries because the cache GenServers and filesystem live in the app's BEAM process tree, not per-test. A single reset here avoids per-file setup duplication. """ @spec reset_test_state :: :ok def reset_test_state do dir = Application.get_env(:microwaveprop, :propagation_scores_dir) if is_binary(dir), do: File.rm_rf(dir) GridCache.clear() ScoreCache.clear() Req.Test.stub(Microwaveprop.Weather.NexradClient, fn conn -> Plug.Conn.send_resp(conn, 404, "not found") end) Req.Test.stub(Microwaveprop.Weather.HrrrClient, fn conn -> Plug.Conn.send_resp(conn, 404, "not found") end) Req.Test.stub(Microwaveprop.Weather.NarrClient, fn conn -> Plug.Conn.send_resp(conn, 404, "not found") end) Req.Test.stub(Microwaveprop.Weather.HrdpsClient, fn conn -> Plug.Conn.send_resp(conn, 404, "not found") end) :ok end @spec setup_sandbox(map()) :: pid() def setup_sandbox(tags) do shared? = not tags[:async] pid = Sandbox.start_owner!(Microwaveprop.Repo, shared: shared?) on_exit(fn -> Sandbox.stop_owner(pid) end) pid end @spec errors_on(Ecto.Changeset.t()) :: map() def errors_on(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> Regex.replace(~r"%{(\w+)}", message, fn _, key -> opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() end) end) end end