prop/test/microwaveprop/cache_test.exs
Graham McIntire 9db2cd20f5
fix: resolve 7 pre-existing test failures and ScoreCache DateTime bug
- CacheTest: fix sweep timing race by using negative TTL (-1)
  instead of positive TTL (1) for already-expired entries
- ScoreCache: replace ETS match-spec DateTime comparisons with
  :ets.foldl + DateTime.compare — DateTime structs are maps in
  Elixir >= 1.15 and ETS can't compare maps with :< / :> guards
- Accounts: drop unsupported returning: true on delete_all,
  return [] for expired tokens list
- Backtest: catch ArgumentError from String.to_existing_atom
  for unknown feature names, preserving the helpful Mix.Error
- ContactLive IndexTest: invalidate monthly_bars cache before
  assertion so test data is visible
- RoverLocationsLive MapTest: invalidate cached points before
  assertion
- StatusLiveTest: add DB cleanup in setup to reduce test
  interference; parameterize NARR candidate coordinates
2026-06-10 13:50:24 -05:00

74 lines
2.3 KiB
Elixir

defmodule Microwaveprop.CacheTest do
use ExUnit.Case, async: false
alias Microwaveprop.Cache
setup do
Cache.clear()
:ok
end
describe "fetch_or_store/3" do
test "invokes the function and returns the value on a cold cache" do
assert Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end) == 42
end
test "returns the cached value without invoking the function on a warm hit" do
Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end)
assert Cache.fetch_or_store(:the_key, 1_000, fn -> raise "should not run" end) == 42
end
test "re-invokes the function once the TTL expires" do
Cache.put(:the_key, 1, -1)
assert Cache.fetch_or_store(:the_key, 1_000, fn -> 2 end) == 2
end
test "isolates values by key" do
assert Cache.fetch_or_store(:a, 1_000, fn -> 1 end) == 1
assert Cache.fetch_or_store(:b, 1_000, fn -> 2 end) == 2
assert Cache.fetch_or_store(:a, 1_000, fn -> raise "no" end) == 1
assert Cache.fetch_or_store(:b, 1_000, fn -> raise "no" end) == 2
end
end
describe "put/3 and invalidate/1" do
test "put/3 stores a value with the given TTL" do
Cache.put(:k, "hello", 1_000)
assert Cache.fetch_or_store(:k, 1_000, fn -> "other" end) == "hello"
end
test "invalidate/1 removes an entry, forcing the next fetch to recompute" do
Cache.put(:k, "stale", 60_000)
Cache.invalidate(:k)
assert Cache.fetch_or_store(:k, 1_000, fn -> "fresh" end) == "fresh"
end
end
describe "sweep/0" do
test "removes expired entries" do
Cache.put(:expired, "old", -1)
Cache.sweep()
assert :ets.lookup(:microwaveprop_cache, :expired) == []
end
test "leaves unexpired entries in place" do
Cache.put(:fresh, "new", 60_000)
_ = Cache.sweep()
assert [{:fresh, "new", _}] = :ets.lookup(:microwaveprop_cache, :fresh)
end
test "handles a mix of expired and unexpired entries" do
Cache.put(:expired_a, 1, -1)
Cache.put(:expired_b, 2, -1)
Cache.put(:fresh, 3, 60_000)
Cache.sweep()
assert :ets.lookup(:microwaveprop_cache, :expired_a) == []
assert :ets.lookup(:microwaveprop_cache, :expired_b) == []
assert [{:fresh, 3, _}] = :ets.lookup(:microwaveprop_cache, :fresh)
end
end
end