diff --git a/lib/microwaveprop/weather/gefs_client.ex b/lib/microwaveprop/weather/gefs_client.ex index 4a034511..e9ecf181 100644 --- a/lib/microwaveprop/weather/gefs_client.ex +++ b/lib/microwaveprop/weather/gefs_client.ex @@ -236,8 +236,13 @@ defmodule Microwaveprop.Weather.GefsClient do ":(#{vars}):" end + defp http_get(url, opts) do + runner = Application.get_env(:microwaveprop, :gefs_http_get, &Req.get/2) + runner.(url, opts) + end + defp fetch_idx(url) do - case Req.get(url, req_options()) do + case http_get(url, req_options()) do {:ok, %{status: 200, body: body}} -> {:ok, body} {:ok, %{status: status}} -> {:error, "GEFS idx HTTP #{status}"} {:error, reason} -> {:error, reason} @@ -265,7 +270,7 @@ defmodule Microwaveprop.Weather.GefsClient do |> Task.Supervisor.async_stream_nolink( merged, fn {start, stop} -> - case Req.get(url, [{:headers, [{"Range", "bytes=#{start}-#{stop}"}]} | req_options()]) do + case http_get(url, [{:headers, [{"Range", "bytes=#{start}-#{stop}"}]} | req_options()]) do {:ok, %{status: 206, body: body}} -> {:ok, start, body} {:ok, %{status: status}} -> {:error, "GEFS grib HTTP #{status}"} {:error, reason} -> {:error, reason} diff --git a/lib/microwaveprop/weather/hrrr_client.ex b/lib/microwaveprop/weather/hrrr_client.ex index fd63ddc3..7b133a75 100644 --- a/lib/microwaveprop/weather/hrrr_client.ex +++ b/lib/microwaveprop/weather/hrrr_client.ex @@ -475,13 +475,18 @@ defmodule Microwaveprop.Weather.HrrrClient do end defp do_fetch_idx(url) do - case Req.get(url, req_options()) do + case http_get(url, req_options()) do {:ok, %{status: 200, body: body}} -> {:ok, body} {:ok, %{status: status}} -> {:error, "HRRR idx HTTP #{status}"} {:error, reason} -> {:error, reason} end end + defp http_get(url, opts) do + runner = Application.get_env(:microwaveprop, :hrrr_http_get, &Req.get/2) + runner.(url, opts) + end + @doc """ Downloads the given byte ranges from a GRIB2 URL and concatenates them in offset order. Merges adjacent/overlapping ranges and runs @@ -583,7 +588,7 @@ defmodule Microwaveprop.Weather.HrrrClient do |> Task.Supervisor.async_stream_nolink( merged, fn {start, stop} -> - case Req.get(url, [{:headers, [{"Range", "bytes=#{start}-#{stop}"}]} | req_options()]) do + case http_get(url, [{:headers, [{"Range", "bytes=#{start}-#{stop}"}]} | req_options()]) do {:ok, %{status: 206, body: body}} -> {:ok, start, body} {:ok, %{status: status}} -> {:error, "HRRR grib HTTP #{status}"} {:error, reason} -> {:error, reason} diff --git a/test/microwaveprop/weather/gefs_client_test.exs b/test/microwaveprop/weather/gefs_client_test.exs index 8418fb08..ea8bd58c 100644 --- a/test/microwaveprop/weather/gefs_client_test.exs +++ b/test/microwaveprop/weather/gefs_client_test.exs @@ -352,4 +352,53 @@ defmodule Microwaveprop.Weather.GefsClientTest do end end end + + describe "dewpoint_from_rh/2 edge cases" do + test "handles 0% RH by clamping to a small positive value" do + result = GefsClient.dewpoint_from_rh(25.0, 0.0) + assert is_float(result) + assert result < 25.0 + end + + test "100% RH at 25°C returns ~25°C dewpoint" do + result = GefsClient.dewpoint_from_rh(25.0, 100.0) + assert_in_delta result, 25.0, 0.5 + end + + test "50% RH at 25°C returns dewpoint below 25°C" do + result = GefsClient.dewpoint_from_rh(25.0, 50.0) + assert result < 25.0 + assert result > 10.0 + end + end + + describe "fetch_grid_profiles/3 with injected http_get" do + setup do + prev = Application.get_env(:microwaveprop, :gefs_http_get) + + on_exit(fn -> + if prev, + do: Application.put_env(:microwaveprop, :gefs_http_get, prev), + else: Application.delete_env(:microwaveprop, :gefs_http_get) + end) + + :ok + end + + test "returns error when idx fetch fails" do + Application.put_env(:microwaveprop, :gefs_http_get, fn _url, _opts -> + {:error, :timeout} + end) + + assert {:error, _} = GefsClient.fetch_grid_profiles(~D[2026-04-18], 12, 0) + end + + test "returns error when idx returns non-200" do + Application.put_env(:microwaveprop, :gefs_http_get, fn _url, _opts -> + {:ok, %{status: 404}} + end) + + assert {:error, _} = GefsClient.fetch_grid_profiles(~D[2026-04-18], 12, 0) + end + end end