defmodule Microwaveprop.Workers.PropagationGridWorkerTest do @moduledoc """ Tests the chain-orchestration behavior of PropagationGridWorker. The worker processes forecast hours f00–f18 across the CONUS grid, but a single full sweep takes ~2 hours of wall time — longer than a typical pod restart window. To survive deploys, the worker processes ONE forecast hour per `perform/1` call and enqueues the next hour as a fresh Oban job. The tests here cover the dispatch + chain logic without mocking the full HRRR / scoring stack. """ use Microwaveprop.DataCase, async: false use Oban.Testing, repo: Microwaveprop.Repo alias Microwaveprop.Workers.MrmsFetchWorker alias Microwaveprop.Workers.PropagationGridWorker alias Microwaveprop.Workers.PropagationPruneWorker describe "queue priority" do test "PropagationGridWorker runs at the highest priority on :propagation" do assert PropagationGridWorker.__opts__()[:priority] == 0 end test "MrmsFetchWorker and PropagationPruneWorker yield to the grid chain" do # Same :propagation queue — must be lower priority so hourly chain # steps jump ahead of a MRMS or pruner backlog. assert MrmsFetchWorker.__opts__()[:priority] > 0 assert PropagationPruneWorker.__opts__()[:priority] > 0 end end describe "compute_scores_algorithm/3" do test "accepts a map of {{lat, lon} => profile} without raising" do # grid_data is a map keyed by {lat, lon}, not a list. # A regression guard against using length/1 on the map. valid_time = ~U[2026-04-19 15:00:00Z] assert [] = PropagationGridWorker.compute_scores_algorithm( %{}, valid_time, false ) end end describe "perform/1 — chain seeding (empty args)" do test "enqueues all 19 forecast-hour jobs at once, all pointing at the same run_time" do Oban.Testing.with_testing_mode(:manual, fn -> assert :ok = PropagationGridWorker.perform(%Oban.Job{args: %{}}) jobs = all_enqueued(worker: PropagationGridWorker) assert length(jobs) == 19 fhs = jobs |> Enum.map(& &1.args["forecast_hour"]) |> Enum.sort() assert fhs == Enum.to_list(0..18) # Every child job shares the same run_time and it's normalized # to top-of-hour UTC. run_times = jobs |> Enum.map(& &1.args["run_time"]) |> Enum.uniq() assert [rt] = run_times {:ok, dt, _} = DateTime.from_iso8601(rt) assert dt.minute == 0 assert dt.second == 0 assert DateTime.before?(dt, DateTime.utc_now()) end) end end end