defmodule Microwaveprop.Weather.GefsProfileTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.Weather alias Microwaveprop.Weather.GefsProfile @valid_time ~U[2026-04-18 18:00:00Z] defp base_attrs(overrides \\ %{}) do Map.merge( %{ valid_time: @valid_time, lat: 32.9, lon: -97.0, run_time: ~U[2026-04-18 12:00:00Z], forecast_hour: 6, surface_temp_c: 20.0, surface_dewpoint_c: 10.0, surface_pressure_mb: 1013.0, pwat_mm: 20.0, wind_u_mps: 2.0, wind_v_mps: -1.0, cloud_cover_pct: 50.0, precip_mm: 0.0 }, overrides ) end describe "changeset/2" do test "is valid with the minimum required fields" do cs = GefsProfile.changeset(%GefsProfile{}, base_attrs()) assert cs.valid? end test "requires valid_time, lat, and lon" do cs = GefsProfile.changeset(%GefsProfile{}, %{}) refute cs.valid? assert %{valid_time: _, lat: _, lon: _} = errors_on(cs) end test "accepts an optional pressure-level profile array" do profile = [%{"pres" => 1000.0, "tmpc" => 20.0, "dwpc" => 10.0, "hght" => 100.0}] cs = GefsProfile.changeset(%GefsProfile{}, base_attrs(%{profile: profile})) assert cs.valid? assert Ecto.Changeset.get_field(cs, :profile) == profile end end describe "Weather.upsert_gefs_profile/1" do test "inserts a new profile" do assert {:ok, %GefsProfile{} = profile} = Weather.upsert_gefs_profile(base_attrs()) assert profile.lat == 32.9 assert profile.surface_temp_c == 20.0 end test "is a no-op on conflict (lat, lon, valid_time)" do {:ok, _} = Weather.upsert_gefs_profile(base_attrs()) {:ok, second} = Weather.upsert_gefs_profile(base_attrs(%{surface_temp_c: 999.0})) # on_conflict: :nothing leaves the existing row alone; the returned # struct just carries the changeset values, but the DB keeps the old # record. persisted = Microwaveprop.Repo.get_by(GefsProfile, lat: 32.9, lon: -97.0, valid_time: @valid_time) assert persisted.surface_temp_c == 20.0 assert second.lat == 32.9 end test "rejects invalid attributes with a changeset error" do assert {:error, %Ecto.Changeset{valid?: false}} = Weather.upsert_gefs_profile(%{}) end end describe "Weather.upsert_gefs_profiles_batch/1" do test "inserts many rows at once" do attrs = for fh <- [3, 6, 9] do valid = DateTime.add(~U[2026-04-18 12:00:00Z], fh * 3600, :second) base_attrs(%{valid_time: valid, forecast_hour: fh}) end {count, _} = Weather.upsert_gefs_profiles_batch(attrs) assert count == 3 rows = Microwaveprop.Repo.all(GefsProfile) assert length(rows) == 3 end test "skips conflicting rows quietly" do attrs = [base_attrs()] {1, _} = Weather.upsert_gefs_profiles_batch(attrs) {0, _} = Weather.upsert_gefs_profiles_batch(attrs) assert Microwaveprop.Repo.aggregate(GefsProfile, :count, :id) == 1 end end end