prop/test/mix/tasks/weather_rebatch_asos_test.exs
Graham McIntire 888701e627
test: bump coverage 80% -> 81.3% via more LiveView + module tests
- Pskr.Client: 0% -> 18% (init/standby/handle_info/terminate)
- RoverPlanningLive.PathShow: 0% -> 82% (mount/load_path)
- Rover.CandidateDetail: 0% -> partial (summarize/5 with stations)
- Mix.Tasks.Weather.RebatchAsos: 0% -> covered (wrapper run/1)
- HrrrNativeClient: 57% -> 67% (fetch_native_duct_grid error paths)
- RoverLive: 40% -> 48% (toggle/delete/update_station_grid logged-in)
- PathLive: 62% -> 63% (path_forecast_detail + rover_path_id branches)
- PathCompute: 64% -> 64% (compute/4 full pipeline + resolve_location)
- SkewtLive: 29% -> 31% (search/select_time event no-ops)
- SkewtLocationResolver: 38% -> 60%+ (callsign cache + error paths)

3557 tests passing.
2026-05-08 09:10:34 -05:00

109 lines
3.7 KiB
Elixir

defmodule Mix.Tasks.Weather.RebatchAsosTest do
use Microwaveprop.DataCase, async: false
alias Microwaveprop.Weather.IemClient
alias Microwaveprop.Weather.RebatchAsos
alias Microwaveprop.Workers.WeatherFetchWorker
setup do
# Oban runs inline in tests, so the batch job the task inserts
# actually executes. Stub IEM so that execution is a quiet no-op
# (stations don't exist, so the batch handler just logs "missing"
# and returns :ok).
Req.Test.stub(IemClient, fn conn ->
Req.Test.text(conn, "#DEBUG\nstation,valid,tmpf\n")
end)
:ok
end
# Oban runs `testing: :inline` in this project, so Oban.insert! would
# execute the job immediately. We stash raw Oban.Job rows so we can
# assert on the queue state the rebatch task would see in prod.
defp insert_asos_job(station_id, station_code, start_dt, end_dt) do
changeset =
WeatherFetchWorker.new(%{
"fetch_type" => "asos",
"station_id" => station_id,
"station_code" => station_code,
"start_dt" => start_dt,
"end_dt" => end_dt
})
# Force state=available so the task picks it up; Oban.Job defaults
# to :available already but we set it explicitly for clarity.
changeset
|> Ecto.Changeset.put_change(:state, "available")
|> Repo.insert!()
end
defp pending_count_by_type do
import Ecto.Query
from(j in Oban.Job,
where: j.state in ["available", "scheduled", "retryable"],
select: {fragment("?->>'fetch_type'", j.args), count(j.id)},
group_by: fragment("?->>'fetch_type'", j.args)
)
|> Repo.all()
|> Map.new()
end
test "collapses N single-station jobs sharing a window into one batch" do
insert_asos_job(Ecto.UUID.generate(), "KDFW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
insert_asos_job(Ecto.UUID.generate(), "KFTW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
insert_asos_job(Ecto.UUID.generate(), "KAFW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
output = ExUnit.CaptureIO.capture_io(fn -> RebatchAsos.run([]) end)
assert output =~ "3 pending `asos` jobs across 1 time windows"
assert output =~ "inserted 1 batch jobs"
assert output =~ "cancelled 3 single-station jobs"
end
test "groups per (start_dt, end_dt) window" do
insert_asos_job(Ecto.UUID.generate(), "KDFW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
insert_asos_job(Ecto.UUID.generate(), "KFTW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
insert_asos_job(Ecto.UUID.generate(), "KAUS", "2026-03-29T10:00:00Z", "2026-03-29T14:00:00Z")
output = ExUnit.CaptureIO.capture_io(fn -> RebatchAsos.run([]) end)
assert output =~ "3 pending `asos` jobs across 2 time windows"
assert output =~ "inserted 2 batch jobs"
end
test "dry-run does not mutate the queue" do
insert_asos_job(Ecto.UUID.generate(), "KDFW", "2026-03-28T16:00:00Z", "2026-03-28T20:00:00Z")
ExUnit.CaptureIO.capture_io(fn -> RebatchAsos.run(dry_run: true) end)
counts = pending_count_by_type()
assert counts["asos"] == 1
assert counts["asos_batch"] in [nil, 0]
end
test "no pending asos jobs — short-circuits" do
output = ExUnit.CaptureIO.capture_io(fn -> RebatchAsos.run([]) end)
assert output =~ "Nothing to do"
end
describe "Mix task wrapper" do
test "run/1 with no args is a no-op" do
output =
ExUnit.CaptureIO.capture_io(fn ->
assert :ok = Mix.Tasks.Weather.RebatchAsos.run([])
end)
assert output =~ "Nothing to do"
end
test "run/1 with --dry-run flag" do
output =
ExUnit.CaptureIO.capture_io(fn ->
assert :ok = Mix.Tasks.Weather.RebatchAsos.run(["--dry-run"])
end)
assert output =~ "Nothing to do"
end
end
end