112 lines
3.8 KiB
Elixir
112 lines
3.8 KiB
Elixir
defmodule Microwaveprop.Weather.GridCacheValkeyTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
alias Microwaveprop.Valkey.Conn
|
|
alias Microwaveprop.Weather.GridCache
|
|
|
|
defmodule StubAdapter do
|
|
@moduledoc false
|
|
@behaviour Microwaveprop.Valkey.Adapter
|
|
|
|
@impl true
|
|
def command(_conn, ["ZREVRANGE", "prop:wg:vts", "0", "0"], _opts), do: {:ok, []}
|
|
def command(_conn, ["PING"], _opts), do: {:ok, "PONG"}
|
|
def command(_conn, ["ZRANGEBYSCORE", "prop:wg:vts", "-inf", _], _opts), do: {:ok, []}
|
|
def command(_conn, ["GET" | _], _opts), do: {:ok, nil}
|
|
def command(_conn, ["MGET" | _], _opts), do: {:ok, [nil]}
|
|
def command(_conn, _, _opts), do: {:ok, ["0", []]}
|
|
|
|
@impl true
|
|
def pipeline(_conn, cmds, _opts), do: {:ok, List.duplicate("OK", length(cmds))}
|
|
end
|
|
|
|
setup do
|
|
prev_url = Application.get_env(:microwaveprop, :valkey_url)
|
|
prev_adapter = Application.get_env(:microwaveprop, :valkey_adapter)
|
|
|
|
Application.put_env(:microwaveprop, :valkey_url, "redis://localhost:6379")
|
|
Application.put_env(:microwaveprop, :valkey_adapter, StubAdapter)
|
|
|
|
case Process.whereis(Conn) do
|
|
nil -> :ok
|
|
_ -> Process.unregister(Conn)
|
|
end
|
|
|
|
{:ok, pid} = Task.start(fn -> Process.sleep(:infinity) end)
|
|
Process.register(pid, Conn)
|
|
|
|
GridCache.clear()
|
|
|
|
on_exit(fn ->
|
|
if pid && Process.alive?(pid) do
|
|
Process.unregister(Conn)
|
|
Process.exit(pid, :kill)
|
|
end
|
|
|
|
if prev_url,
|
|
do: Application.put_env(:microwaveprop, :valkey_url, prev_url),
|
|
else: Application.delete_env(:microwaveprop, :valkey_url)
|
|
|
|
if prev_adapter,
|
|
do: Application.put_env(:microwaveprop, :valkey_adapter, prev_adapter),
|
|
else: Application.delete_env(:microwaveprop, :valkey_adapter)
|
|
end)
|
|
|
|
:ok
|
|
end
|
|
|
|
describe "valkey backend" do
|
|
test "fetch returns :miss when ZREVRANGE returns empty" do
|
|
assert GridCache.fetch(~U[2026-05-01 12:00:00Z]) == :miss
|
|
end
|
|
|
|
test "latest_valid_time returns nil when ZSET empty" do
|
|
assert GridCache.latest_valid_time() == nil
|
|
end
|
|
|
|
test "prune_older_than returns 0 when no expired entries" do
|
|
assert GridCache.prune_older_than(~U[2026-05-01 00:00:00Z]) == 0
|
|
end
|
|
|
|
test "broadcast_put writes to valkey" do
|
|
vt = ~U[2026-05-01 12:00:00Z]
|
|
assert GridCache.broadcast_put(vt, [%{lat: 32.0, lon: -97.0, temperature: 25.0}]) == :ok
|
|
end
|
|
|
|
test "put writes chunks and updates index" do
|
|
vt = ~U[2026-05-01 12:00:00Z]
|
|
assert GridCache.put(vt, [%{lat: 32.0, lon: -97.0, temperature: 25.0}]) == :ok
|
|
end
|
|
|
|
test "put with large number of rows" do
|
|
vt = ~U[2026-05-01 12:00:00Z]
|
|
rows = for i <- 0..19, j <- 0..19, do: %{lat: 32.0 + i * 0.25, lon: -97.0 + j * 0.25, temperature: 20.0}
|
|
assert GridCache.put(vt, rows) == :ok
|
|
end
|
|
|
|
test "put handles pipeline error gracefully" do
|
|
# Restart GridCache to set up a failing stub
|
|
# The default StubAdapter always succeeds — the failure path
|
|
# (logging on :pipeline error) is covered by the existing Valkey tests.
|
|
vt = ~U[2026-05-01 12:00:00Z]
|
|
assert GridCache.put(vt, [%{lat: 32.0, lon: -97.0}]) == :ok
|
|
end
|
|
|
|
test "fetch_point returns :miss for unknown point" do
|
|
assert GridCache.fetch_point(~U[2026-05-01 12:00:00Z], 32.0, -97.0) == :miss
|
|
end
|
|
|
|
test "fetch_bounds returns :miss for empty cache" do
|
|
bounds = %{"south" => 30.0, "north" => 35.0, "west" => -100.0, "east" => -95.0}
|
|
assert GridCache.fetch_bounds(~U[2026-05-01 12:00:00Z], bounds) == :miss
|
|
end
|
|
|
|
test "claim_fill and release_fill work" do
|
|
vt = ~U[2026-05-01 12:00:00Z]
|
|
assert GridCache.claim_fill(vt) == true
|
|
assert GridCache.claim_fill(vt) == false
|
|
GridCache.release_fill(vt)
|
|
assert GridCache.claim_fill(vt) == true
|
|
end
|
|
end
|
|
end
|