defmodule Microwaveprop.Weather.HrdpsProfileTest do use Microwaveprop.DataCase, async: false alias Microwaveprop.Repo alias Microwaveprop.Weather.HrdpsProfile describe "changeset/2" do test "valid with required fields" do attrs = %{valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42} cs = HrdpsProfile.changeset(%HrdpsProfile{}, attrs) assert cs.valid? end test "rejects missing required fields" do cs = HrdpsProfile.changeset(%HrdpsProfile{}, %{}) refute cs.valid? assert %{valid_time: ["can't be blank"]} = errors_on(cs) assert %{lat: ["can't be blank"]} = errors_on(cs) assert %{lon: ["can't be blank"]} = errors_on(cs) end test "casts the full set of derived fields" do attrs = %{ valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42, run_time: ~U[2026-04-29 12:00:00Z], profile: [%{"pres" => 1000.0, "tmpc" => 12.0, "dwpc" => 7.0, "hght" => 100.0}], hpbl_m: 800.0, pwat_mm: nil, surface_temp_c: 12.0, surface_dewpoint_c: 7.0, surface_pressure_mb: 1000.0, surface_refractivity: 312.0, min_refractivity_gradient: -50.0, ducting_detected: false, duct_characteristics: [], is_grid_point: true } cs = HrdpsProfile.changeset(%HrdpsProfile{}, attrs) assert cs.valid? assert Ecto.Changeset.get_field(cs, :surface_refractivity) == 312.0 assert Ecto.Changeset.get_field(cs, :is_grid_point) == true end end describe "persistence" do test "inserts and reads back via the partitioned hrdps_profiles table" do attrs = %{ valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42, run_time: ~U[2026-04-29 12:00:00Z], surface_temp_c: 7.8 } {:ok, %HrdpsProfile{id: id}} = %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert() reloaded = Repo.get!(HrdpsProfile, id) assert reloaded.lat == 53.32 assert reloaded.surface_temp_c == 7.8 end test "enforces unique constraint on (lat, lon, valid_time) at the DB level" do # The partitioned table propagates the unique index per partition, so # Postgres rejects duplicate (lat, lon, valid_time) inserts. Schema- # level `unique_constraint/2` matching against changeset errors # doesn't apply because the partition's index name varies per # partition; callers that need upserts go through # `on_conflict: {:replace_all_except, ...}` in the worker. attrs = %{valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42} assert {:ok, _} = %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert() assert_raise Ecto.ConstraintError, fn -> %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert() end end end end