prop/test/microwaveprop/weather/mrms_cache_test.exs
Graham McIntire ea0cbf5205
test: cover mrms_cache + mrms_fetch_worker, add Req.Test seam
Same fix as rtma_client: MrmsClient had a hardcoded req_options/0 —
switched to a Keyword.merge with Application.get_env so tests can stub
HTTP. 13 new characterization tests: cache put/get/clear/broadcast and
worker listing/download/up-to-date paths. Full GRIB2 parse happy path
deferred to the wgrib2 coverage task.
2026-04-16 14:58:54 -05:00

97 lines
2.9 KiB
Elixir

defmodule Microwaveprop.Weather.MrmsCacheTest do
# async: false — MrmsCache is started at the application level and owns a
# named ETS table. Tests mutate shared state and must not race.
use ExUnit.Case, async: false
alias Microwaveprop.Weather.MrmsCache
@topic "mrms:cache"
@pubsub Microwaveprop.PubSub
setup do
MrmsCache.clear()
:ok
end
describe "fetch/0" do
test "returns :miss when nothing is cached" do
assert MrmsCache.fetch() == :miss
end
test "returns {:ok, valid_time, grid} after put/2" do
valid_time = ~U[2026-04-12 19:24:00Z]
grid = %{{32.0, -97.0} => 1.2, {32.125, -97.0} => 0.0}
assert :ok = MrmsCache.put(valid_time, grid)
assert {:ok, ^valid_time, ^grid} = MrmsCache.fetch()
end
test "put/2 overwrites the single current entry" do
first_vt = ~U[2026-04-12 19:24:00Z]
second_vt = ~U[2026-04-12 19:26:00Z]
MrmsCache.put(first_vt, %{{32.0, -97.0} => 1.0})
MrmsCache.put(second_vt, %{{32.0, -97.0} => 2.0})
assert {:ok, ^second_vt, %{{32.0, -97.0} => 2.0}} = MrmsCache.fetch()
end
end
describe "valid_time/0" do
test "returns nil when cache is empty" do
assert MrmsCache.valid_time() == nil
end
test "returns the cached valid_time when present" do
vt = ~U[2026-04-12 19:24:00Z]
MrmsCache.put(vt, %{{32.0, -97.0} => 5.4})
assert MrmsCache.valid_time() == vt
end
end
describe "broadcast_put/2" do
test "inserts locally and broadcasts on the mrms:cache topic" do
Phoenix.PubSub.subscribe(@pubsub, @topic)
vt = ~U[2026-04-12 19:28:00Z]
grid = %{{32.0, -97.0} => 3.3}
assert :ok = MrmsCache.broadcast_put(vt, grid)
assert {:ok, ^vt, ^grid} = MrmsCache.fetch()
# The cache subscribes to its own topic, so we should observe the
# message via our own subscription too.
assert_receive {:mrms_cache_refresh, ^vt, ^grid}
end
end
describe "clear/0" do
test "empties the cache" do
MrmsCache.put(~U[2026-04-12 19:24:00Z], %{{32.0, -97.0} => 1.0})
assert {:ok, _, _} = MrmsCache.fetch()
assert :ok = MrmsCache.clear()
assert MrmsCache.fetch() == :miss
assert MrmsCache.valid_time() == nil
end
end
describe "peer broadcast handling" do
test "applies refreshes received from peers on the PubSub topic" do
# Simulate a peer node pushing a refresh. The cache GenServer is
# subscribed to @topic in init/1; broadcasting directly exercises the
# handle_info({:mrms_cache_refresh, ...}) clause.
vt = ~U[2026-04-12 19:30:00Z]
grid = %{{32.0, -97.0} => 7.7}
Phoenix.PubSub.broadcast(@pubsub, @topic, {:mrms_cache_refresh, vt, grid})
# Round-trip through the MrmsCache GenServer mailbox: send it a sync
# call so we know the previous broadcast has been processed.
_ = :sys.get_state(MrmsCache)
assert {:ok, ^vt, ^grid} = MrmsCache.fetch()
end
end
end