defmodule Microwaveprop.CommercialTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.Commercial alias Microwaveprop.Commercial.Link setup do Repo.delete_all(Link) :ok end @link_attrs %{ label: "test-link", host: "10.0.0.1", community: "public", radio_type: "af11x", weather_station: "KTKI", enabled: true } describe "enabled_links/0" do test "returns only enabled links" do {:ok, _enabled} = Commercial.create_link(@link_attrs) {:ok, _disabled} = Commercial.create_link(%{@link_attrs | label: "disabled-link", enabled: false}) links = Commercial.enabled_links() assert length(links) == 1 assert hd(links).label == "test-link" end test "returns empty list when no enabled links" do assert Commercial.enabled_links() == [] end end describe "create_link/1" do test "creates a link with valid attrs" do assert {:ok, link} = Commercial.create_link(@link_attrs) assert link.label == "test-link" assert link.enabled == true end test "returns error for invalid attrs" do assert {:error, _changeset} = Commercial.create_link(%{}) end end describe "create_sample/1" do test "creates a sample for a link" do {:ok, link} = Commercial.create_link(@link_attrs) attrs = %{ link_id: link.id, sampled_at: DateTime.utc_now(), rx_power_0: -55.0, tx_power: 20.0, link_state: 1 } assert {:ok, sample} = Commercial.create_sample(attrs) assert sample.rx_power_0 == -55.0 assert sample.link_id == link.id end end describe "link_degradation_at/3" do @endpoint_dfw %{"lat" => 33.2, "lon" => -96.5} @far_point {0.0, 0.0} @near_point {33.2, -96.5} test "returns nil when no links are within the radius" do {:ok, _} = Commercial.create_link( Map.merge(@link_attrs, %{ endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw }) ) valid_time = ~U[2026-04-13 18:00:00Z] assert Commercial.link_degradation_at(@far_point, valid_time, radius_km: 50) == nil end test "returns nil when the link has no recent baseline samples" do {:ok, _link} = Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw})) valid_time = ~U[2026-04-13 18:00:00Z] assert Commercial.link_degradation_at(@near_point, valid_time) == nil end test "returns positive degradation when current rx_power is below baseline" do {:ok, link} = Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw})) valid_time = ~U[2026-04-13 18:00:00Z] # 7-day baseline: -52 dBm average for day_offset <- 1..6 do {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second), rx_power_0: -52.0, rx_power_1: -52.0, link_state: 1 }) end # Current (within 15 min) drops to -62 — 10 dB deep fade. {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -300, :second), rx_power_0: -62.0, rx_power_1: -62.0, link_state: 1 }) result = Commercial.link_degradation_at(@near_point, valid_time) assert result assert_in_delta result.degradation_db, 10.0, 0.5 assert result.n_links == 1 end test "returns 0 degradation when rx_power matches baseline" do {:ok, link} = Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw})) valid_time = ~U[2026-04-13 18:00:00Z] for day_offset <- 1..6 do {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second), rx_power_0: -55.0, link_state: 1 }) end {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -60, :second), rx_power_0: -55.0, link_state: 1 }) result = Commercial.link_degradation_at(@near_point, valid_time) assert result assert_in_delta result.degradation_db, 0.0, 0.5 end test "ignores links with link_state != 1 (down link isn't tropo)" do {:ok, link} = Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw})) valid_time = ~U[2026-04-13 18:00:00Z] for day_offset <- 1..6 do {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second), rx_power_0: -52.0, link_state: 1 }) end {:ok, _} = Commercial.create_sample(%{ link_id: link.id, sampled_at: DateTime.add(valid_time, -120, :second), rx_power_0: -90.0, link_state: 0 }) assert Commercial.link_degradation_at(@near_point, valid_time) == nil end end describe "weather_stations/0" do test "returns unique weather stations from enabled links" do {:ok, _} = Commercial.create_link(@link_attrs) {:ok, _} = Commercial.create_link(%{@link_attrs | label: "link-2", host: "10.0.0.2"}) {:ok, _} = Commercial.create_link(%{ @link_attrs | label: "link-3", host: "10.0.0.3", weather_station: "KDFW" }) stations = Commercial.weather_stations() assert Enum.sort(stations) == ["KDFW", "KTKI"] end test "excludes disabled links" do {:ok, _} = Commercial.create_link(%{@link_attrs | enabled: false}) assert Commercial.weather_stations() == [] end test "excludes nil weather stations" do {:ok, _} = Commercial.create_link(%{@link_attrs | weather_station: nil}) assert Commercial.weather_stations() == [] end end end