defmodule Microwaveprop.SpaceWeatherTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.SpaceWeather alias Microwaveprop.SpaceWeather.GeomagneticObservation alias Microwaveprop.SpaceWeather.SolarFluxObservation alias Microwaveprop.SpaceWeather.SolarXrayObservation describe "upsert_kp/1" do test "inserts new rows and returns the count" do rows = [ %{valid_time: ~U[2026-04-15 18:00:00Z], kp_index: 2, estimated_kp: 1.67}, %{valid_time: ~U[2026-04-15 18:01:00Z], kp_index: 2, estimated_kp: 2.0} ] assert {:ok, 2} = SpaceWeather.upsert_kp(rows) assert Repo.aggregate(GeomagneticObservation, :count, :id) == 2 end test "re-upsert replaces by valid_time (no dupes)" do row = %{valid_time: ~U[2026-04-15 18:00:00Z], kp_index: 2, estimated_kp: 1.67} {:ok, 1} = SpaceWeather.upsert_kp([row]) updated = %{row | kp_index: 5, estimated_kp: 5.3} assert {:ok, 1} = SpaceWeather.upsert_kp([updated]) assert [stored] = Repo.all(GeomagneticObservation) assert stored.kp_index == 5 assert stored.estimated_kp == 5.3 end test "empty list is a no-op returning {:ok, 0}" do assert {:ok, 0} = SpaceWeather.upsert_kp([]) end end describe "upsert_solar_flux/1" do test "inserts rows and replaces by valid_time" do rows = [ %{ valid_time: ~U[2026-04-15 17:00:00Z], frequency_mhz: 2800, flux_sfu: 112.0, reporting_schedule: "Morning", ninety_day_mean: nil } ] assert {:ok, 1} = SpaceWeather.upsert_solar_flux(rows) updated = rows |> List.first() |> Map.put(:flux_sfu, 120.0) assert {:ok, 1} = SpaceWeather.upsert_solar_flux([updated]) assert [stored] = Repo.all(SolarFluxObservation) assert stored.flux_sfu == 120.0 end test "empty list is a no-op returning {:ok, 0}" do assert {:ok, 0} = SpaceWeather.upsert_solar_flux([]) assert Repo.aggregate(SolarFluxObservation, :count, :id) == 0 end end describe "upsert_xray/1" do test "inserts rows and replaces by (valid_time, energy_band)" do rows = [ %{ valid_time: ~U[2026-04-14 19:49:00Z], satellite: 18, flux_wm2: 3.5e-7, energy_band: "0.1-0.8nm", electron_contaminated: false } ] assert {:ok, 1} = SpaceWeather.upsert_xray(rows) assert Repo.aggregate(SolarXrayObservation, :count, :id) == 1 # Re-upserting updates existing row updated = rows |> List.first() |> Map.put(:flux_wm2, 4.0e-7) assert {:ok, 1} = SpaceWeather.upsert_xray([updated]) assert Repo.aggregate(SolarXrayObservation, :count, :id) == 1 [stored] = Repo.all(SolarXrayObservation) assert stored.flux_wm2 == 4.0e-7 end test "rows with same valid_time but different energy_band coexist" do rows = [ %{ valid_time: ~U[2026-04-14 19:49:00Z], satellite: 18, flux_wm2: 3.5e-7, energy_band: "0.1-0.8nm" }, %{ valid_time: ~U[2026-04-14 19:49:00Z], satellite: 18, flux_wm2: 1.2e-8, energy_band: "0.05-0.4nm" } ] assert {:ok, 2} = SpaceWeather.upsert_xray(rows) assert Repo.aggregate(SolarXrayObservation, :count, :id) == 2 end test "empty list is a no-op returning {:ok, 0}" do assert {:ok, 0} = SpaceWeather.upsert_xray([]) assert Repo.aggregate(SolarXrayObservation, :count, :id) == 0 end end describe "latest_kp/0" do test "returns the most recent geomagnetic observation, or nil" do assert SpaceWeather.latest_kp() == nil {:ok, _} = SpaceWeather.upsert_kp([ %{valid_time: ~U[2026-04-15 17:00:00Z], kp_index: 2, estimated_kp: 2.0}, %{valid_time: ~U[2026-04-15 18:00:00Z], kp_index: 3, estimated_kp: 3.0} ]) row = SpaceWeather.latest_kp() assert row.valid_time == ~U[2026-04-15 18:00:00Z] assert row.kp_index == 3 end end describe "latest_f107/0 and latest_xray/0" do test "return the most recent rows, or nil" do assert SpaceWeather.latest_f107() == nil assert SpaceWeather.latest_xray() == nil {:ok, _} = SpaceWeather.upsert_solar_flux([ %{valid_time: ~U[2026-04-15 17:00:00Z], frequency_mhz: 2800, flux_sfu: 112.0} ]) {:ok, _} = SpaceWeather.upsert_xray([ %{ valid_time: ~U[2026-04-15 17:00:00Z], satellite: 18, flux_wm2: 1.0e-7, energy_band: "0.1-0.8nm" } ]) assert %SolarFluxObservation{flux_sfu: 112.0} = SpaceWeather.latest_f107() assert %SolarXrayObservation{flux_wm2: 1.0e-7} = SpaceWeather.latest_xray() end test "latest_f107/0 picks newest across multiple observations" do {:ok, _} = SpaceWeather.upsert_solar_flux([ %{valid_time: ~U[2026-04-14 20:00:00Z], frequency_mhz: 2800, flux_sfu: 100.0}, %{valid_time: ~U[2026-04-15 20:00:00Z], frequency_mhz: 2800, flux_sfu: 115.0}, %{valid_time: ~U[2026-04-13 20:00:00Z], frequency_mhz: 2800, flux_sfu: 90.0} ]) row = SpaceWeather.latest_f107() assert row.valid_time == ~U[2026-04-15 20:00:00Z] assert row.flux_sfu == 115.0 end test "latest_xray/0 picks newest across multiple energy bands" do {:ok, _} = SpaceWeather.upsert_xray([ %{ valid_time: ~U[2026-04-15 17:00:00Z], satellite: 18, flux_wm2: 1.0e-7, energy_band: "0.1-0.8nm" }, %{ valid_time: ~U[2026-04-15 18:00:00Z], satellite: 18, flux_wm2: 2.0e-7, energy_band: "0.05-0.4nm" }, %{ valid_time: ~U[2026-04-15 17:30:00Z], satellite: 18, flux_wm2: 3.0e-7, energy_band: "0.1-0.8nm" } ]) row = SpaceWeather.latest_xray() assert row.valid_time == ~U[2026-04-15 18:00:00Z] assert row.flux_wm2 == 2.0e-7 end end end