defmodule Microwaveprop.Workers.IonosphereFetchWorkerTest do use Microwaveprop.DataCase, async: false use Oban.Testing, repo: Microwaveprop.Repo alias Microwaveprop.Ionosphere alias Microwaveprop.Ionosphere.GiroClient alias Microwaveprop.Ionosphere.Observation alias Microwaveprop.Workers.IonosphereFetchWorker @sample File.read!("test/fixtures/giro/mhj45_sample.txt") describe "perform/1" do test "pulls each configured station and upserts the parsed rows" do Req.Test.stub(GiroClient, fn conn -> assert conn.method == "GET" params = Plug.Conn.fetch_query_params(conn).query_params assert params["ursiCode"] in ~w(MHJ45 AL945) Plug.Conn.resp(conn, 200, @sample) end) assert :ok = perform_job(IonosphereFetchWorker, %{}) # 25 observations per station × 2 stations = 50 rows (fixture has 25 # data lines; upserts go to each station code separately). assert Repo.aggregate(Observation, :count, :id) == 50 assert Ionosphere.latest_observation("MHJ45") assert Ionosphere.latest_observation("AL945") end test "survives a station's fetch error and still ingests the others" do Req.Test.stub(GiroClient, fn conn -> params = Plug.Conn.fetch_query_params(conn).query_params if params["ursiCode"] == "MHJ45" do Plug.Conn.resp(conn, 500, "boom") else Plug.Conn.resp(conn, 200, @sample) end end) assert :ok = perform_job(IonosphereFetchWorker, %{}) # MHJ45 failed, AL945 ingested. assert Ionosphere.latest_observation("MHJ45") == nil assert Ionosphere.latest_observation("AL945") end test "tolerates an HTTP transport failure with :ok + no rows inserted" do Req.Test.stub(GiroClient, fn conn -> Req.Test.transport_error(conn, :timeout) end) assert :ok = perform_job(IonosphereFetchWorker, %{}) assert Repo.aggregate(Observation, :count, :id) == 0 end end describe "stations/0" do test "exposes a non-empty list of CONUS ionosonde stations" do stations = IonosphereFetchWorker.stations() assert is_list(stations) assert length(stations) >= 2 # Every station entry has the shape the fetcher expects, with a # plausible CONUS lat/lon envelope. for s <- stations do assert is_binary(s.code) assert is_binary(s.name) assert is_float(s.lat) or is_integer(s.lat) assert is_float(s.lon) or is_integer(s.lon) assert s.lat > 20.0 and s.lat < 75.0 assert s.lon > -170.0 and s.lon < -60.0 end end end describe "perform/1 additional HTTP branches" do test "tolerates an HTTP 404 with :ok and zero rows inserted" do # 404 is returned by GIRO for stations with no data in the window. # The worker should treat it as a per-station no-op and return :ok. Req.Test.stub(GiroClient, fn conn -> Plug.Conn.send_resp(conn, 404, "not found") end) assert :ok = perform_job(IonosphereFetchWorker, %{}) assert Repo.aggregate(Observation, :count, :id) == 0 end test "tolerates a non-tabular response body gracefully" do # A body that doesn't match the expected comment/columns format # should parse to zero rows — no crash, no inserts. Req.Test.stub(GiroClient, fn conn -> Plug.Conn.resp(conn, 200, "not a tabular response at all") end) assert :ok = perform_job(IonosphereFetchWorker, %{}) assert Repo.aggregate(Observation, :count, :id) == 0 end test "tolerates an empty-body 200 response" do Req.Test.stub(GiroClient, fn conn -> Plug.Conn.resp(conn, 200, "") end) assert :ok = perform_job(IonosphereFetchWorker, %{}) assert Repo.aggregate(Observation, :count, :id) == 0 end end end