prop/test/microwaveprop/weather/gefs_profile_test.exs
Graham McIntire 079346a1b9
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m38s
fix: resolve all 281 credo issues across source and test files
- F-level (228): replace length/1 with Enum.count_until/2 or pattern
  matching; convert Enum.flat_map+if to Enum.filter+Enum.map; fix
  identity case in narr_client
- W-level (46): normalize dual atom/string key access in weather_layers,
  beacon_measurements, surface, skewt_live, contact_live/show; add
  :data_provider and weather-map assigns to ignored_assigns in credo
  config (consumed by child components credo can't trace); remove
  weak is_list assertion; remove explicit assert_receive timeout
- R-level (6): replace 'This module provides...' moduledocs with
  meaningful descriptions
- Also fix 4 compile-connected xref issues by deferring
  BandConfig.band_options() from module attribute to runtime

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 09:04:21 -05:00

99 lines
3.1 KiB
Elixir

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 Enum.count_until(rows, 4) == 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