prop/test/microwaveprop/weather/narr_client_test.exs
Graham McIntire b7e19e18cc
Add Microwaveprop.Weather.NarrClient URL/time helpers
First slice of the NARR backfill client: url_for/1,
url_for_inventory/1, and snap_to_analysis_hour/1. Pure functions,
no network. Validates that NARR analyses only exist at 3-hourly
slots (00/03/06/09/12/15/18/21 UTC). The byte-range fetch and
cdo-driven point extraction land in follow-up commits per
docs/plans/2026-04-15-merra2-historical-backfill.md.
2026-04-15 18:54:02 -05:00

76 lines
2.6 KiB
Elixir

defmodule Microwaveprop.Weather.NarrClientTest do
use ExUnit.Case, async: true
alias Microwaveprop.Weather.NarrClient
describe "url_for/1" do
test "builds the NCEI NARR HTTPS URL for a 3-hourly analysis time" do
vt = ~U[2010-06-15 12:00:00Z]
assert NarrClient.url_for(vt) ==
"https://www.ncei.noaa.gov/data/north-american-regional-reanalysis/access/3-hourly/201006/20100615/narr-a_221_20100615_1200_000.grb"
end
test "uses zero-padded HHMM for off-hour analyses" do
vt = ~U[2010-06-15 03:00:00Z]
assert NarrClient.url_for(vt) ==
"https://www.ncei.noaa.gov/data/north-american-regional-reanalysis/access/3-hourly/201006/20100615/narr-a_221_20100615_0300_000.grb"
end
test "raises ArgumentError on non-3-hourly hours" do
assert_raise ArgumentError, fn ->
NarrClient.url_for(~U[2010-06-15 13:00:00Z])
end
end
test "raises ArgumentError when minutes are non-zero" do
assert_raise ArgumentError, fn ->
NarrClient.url_for(~U[2010-06-15 12:30:00Z])
end
end
end
describe "url_for_inventory/1" do
test "swaps .grb for .inv" do
vt = ~U[2010-06-15 12:00:00Z]
assert NarrClient.url_for_inventory(vt) ==
"https://www.ncei.noaa.gov/data/north-american-regional-reanalysis/access/3-hourly/201006/20100615/narr-a_221_20100615_1200_000.inv"
end
end
describe "snap_to_analysis_hour/1" do
test "rounds down to the nearest 3-hourly NARR slot" do
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 13:42:00Z]) ==
~U[2010-06-15 12:00:00Z]
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 14:30:00Z]) ==
~U[2010-06-15 12:00:00Z]
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 15:00:00Z]) ==
~U[2010-06-15 15:00:00Z]
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 23:59:59Z]) ==
~U[2010-06-15 21:00:00Z]
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 00:00:00Z]) ==
~U[2010-06-15 00:00:00Z]
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 02:00:00Z]) ==
~U[2010-06-15 00:00:00Z]
end
test "preserves the date when snapping doesn't cross midnight" do
assert NarrClient.snap_to_analysis_hour(~U[2010-06-15 05:17:42Z]) ==
~U[2010-06-15 03:00:00Z]
end
test "snaps minutes and seconds to zero" do
snapped = NarrClient.snap_to_analysis_hour(~U[2010-06-15 13:42:37Z])
assert snapped.minute == 0
assert snapped.second == 0
assert snapped.microsecond == {0, 0}
end
end
end