prop/test/microwaveprop/workers/hrrr_fetch_worker_test.exs
Graham McIntire e2f5376355
Cancel HRRR jobs on permanent failures (404, outside_grid)
HTTP 404 means the HRRR data doesn't exist on NOAA S3 (pre-2014
dates, etc.) and will never succeed. Return {:cancel, reason}
instead of {:error, reason} so Oban stops retrying immediately.
2026-03-30 07:53:49 -05:00

124 lines
3.6 KiB
Elixir

defmodule Microwaveprop.Workers.HrrrFetchWorkerTest do
use Microwaveprop.DataCase, async: true
alias Microwaveprop.Weather
alias Microwaveprop.Weather.HrrrProfile
alias Microwaveprop.Workers.HrrrFetchWorker
@sample_profile [
%{"pres" => 1000.0, "hght" => 110.0, "tmpc" => 25.0, "dwpc" => 18.0},
%{"pres" => 975.0, "hght" => 350.0, "tmpc" => 23.0, "dwpc" => 16.0},
%{"pres" => 950.0, "hght" => 590.0, "tmpc" => 21.0, "dwpc" => 14.0}
]
@sample_client_result %{
surface_temp_c: 25.0,
surface_dewpoint_c: 18.0,
surface_pressure_mb: 1013.0,
hpbl_m: 1500.0,
pwat_mm: 25.0,
run_time: ~U[2026-03-28 18:00:00Z],
profile: @sample_profile
}
describe "perform/1" do
test "skips if HRRR profile already exists" do
Weather.upsert_hrrr_profile(%{
valid_time: ~U[2026-03-28 18:00:00Z],
lat: 32.90,
lon: -97.04,
profile: @sample_profile
})
job =
HrrrFetchWorker.new(%{
"lat" => 32.90,
"lon" => -97.04,
"valid_time" => "2026-03-28T18:00:00Z"
})
assert :ok = HrrrFetchWorker.perform(%Oban.Job{args: job.changes.args})
end
test "stores profile when client returns success" do
# We test the perform logic by mocking at the module level
# The actual HTTP calls are tested in HrrrClientTest
# Here we verify the worker's coordination logic
lat = 32.90
lon = -97.04
valid_time = ~U[2026-03-28 18:00:00Z]
# Verify no profile exists initially
refute Weather.has_hrrr_profile?(lat, lon, valid_time)
# Simulate what perform does after a successful fetch
attrs = build_profile_attrs(lat, lon, valid_time, @sample_client_result)
{:ok, profile} = Weather.upsert_hrrr_profile(attrs)
assert profile.lat == lat
assert profile.lon == lon
assert profile.hpbl_m == 1500.0
assert profile.surface_temp_c == 25.0
assert Weather.has_hrrr_profile?(lat, lon, valid_time)
end
test "rounds lat/lon before checking existence" do
# Profile at rounded coordinates
Weather.upsert_hrrr_profile(%{
valid_time: ~U[2026-03-28 18:00:00Z],
lat: 32.90,
lon: -97.04,
profile: []
})
# Worker called with slightly different coords that round to same
job =
HrrrFetchWorker.new(%{
"lat" => 32.904,
"lon" => -97.039,
"valid_time" => "2026-03-28T18:00:00Z"
})
# Should skip because rounded coords match
assert :ok = HrrrFetchWorker.perform(%Oban.Job{args: job.changes.args})
# Only one profile should exist
count = Repo.aggregate(HrrrProfile, :count)
assert count == 1
end
end
describe "permanent_failure?/1" do
test "cancels on 404 idx" do
job = %Oban.Job{
args: %{
"lat" => 32.90,
"lon" => -97.04,
"valid_time" => "1995-06-15T12:00:00Z"
}
}
Req.Test.stub(Microwaveprop.Weather.HrrrClient, fn conn ->
Plug.Conn.send_resp(conn, 404, "not found")
end)
assert {:cancel, "HRRR idx HTTP 404"} = HrrrFetchWorker.perform(job)
end
end
defp build_profile_attrs(lat, lon, valid_time, client_result) do
%{
valid_time: valid_time,
lat: lat,
lon: lon,
run_time: client_result.run_time,
profile: client_result.profile,
hpbl_m: client_result.hpbl_m,
pwat_mm: client_result.pwat_mm,
surface_temp_c: client_result.surface_temp_c,
surface_dewpoint_c: client_result.surface_dewpoint_c,
surface_pressure_mb: client_result.surface_pressure_mb
}
end
end