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.
97 lines
2.9 KiB
Elixir
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
|