diff --git a/test/aprsme_web/channels/mobile_channel_test.exs b/test/aprsme_web/channels/mobile_channel_test.exs index 4b53a89..a223082 100644 --- a/test/aprsme_web/channels/mobile_channel_test.exs +++ b/test/aprsme_web/channels/mobile_channel_test.exs @@ -583,4 +583,63 @@ defmodule AprsmeWeb.MobileChannelTest do assert_reply ref, :ok, %{message: "Subscribed to packet stream"} end end + + describe "packet data type conversions" do + setup %{socket: socket} do + ref = + push(socket, "subscribe_bounds", %{ + "north" => 33.2, + "south" => 33.0, + "east" => -96.0, + "west" => -96.2 + }) + + assert_reply ref, :ok, _ + :ok + end + + test "converts integer and binary coordinates to floats, handles NaiveDateTime timestamps", + %{socket: socket} do + # Covers to_float(integer), to_float(binary), and format_timestamp(NaiveDateTime). + {:ok, naive} = NaiveDateTime.new(2026, 1, 1, 12, 0, 0) + + packet = %{ + id: "mixed-1", + sender: "TYP-1", + lat: 33, + lon: "-96.5", + received_at: naive, + symbol_table_id: "/", + symbol_code: ">" + } + + send(socket.channel_pid, {:streaming_packet, packet}) + + assert_push "packet", pushed + assert pushed.lat == 33.0 + assert pushed.lng == -96.5 + # NaiveDateTime format_timestamp converts to ISO8601. + assert is_binary(pushed.timestamp) + end + + test "nil and unparseable coordinates get dropped from the payload", %{socket: socket} do + packet = %{ + id: "nil-1", + sender: "TYP-2", + # nil coordinates → to_float(nil) returns nil and the field is rejected. + lat: nil, + lon: nil, + received_at: DateTime.utc_now(), + symbol_table_id: "/", + symbol_code: ">" + } + + send(socket.channel_pid, {:streaming_packet, packet}) + + # Packet still pushes but lat/lng are missing (nil fields get stripped). + assert_push "packet", pushed + refute Map.has_key?(pushed, :lat) + refute Map.has_key?(pushed, :lng) + end + end end diff --git a/test/aprsme_web/live/status_live/index_test.exs b/test/aprsme_web/live/status_live/index_test.exs index 1f32827..fa99f68 100644 --- a/test/aprsme_web/live/status_live/index_test.exs +++ b/test/aprsme_web/live/status_live/index_test.exs @@ -164,4 +164,43 @@ defmodule AprsmeWeb.StatusLive.IndexTest do assert new_socket.assigns.loading == false end end + + describe "render with cluster_info populated" do + test "renders the Cluster Status section when cluster_info is present", %{conn: conn} do + _ = + case :ets.info(:query_cache) do + :undefined -> :ets.new(:query_cache, [:named_table, :public, :set]) + _ -> :ok + end + + status = %{ + connected: true, + server: "clustered.aprs.test", + port: 14_580, + connected_at: DateTime.add(DateTime.utc_now(), -60, :second), + uptime_seconds: 60, + login_id: "N0CALL", + filter: "r/33/-96/100", + packet_stats: %{total_packets: 10, packets_per_second: 1, last_packet_at: DateTime.utc_now()}, + stored_packet_count: 100, + oldest_packet_timestamp: DateTime.utc_now(), + cluster_info: %{ + total_nodes: 3, + connected_nodes: 2, + leader_node: "node-a", + all_nodes: ["node-a", "node-b", "node-c"] + } + } + + Aprsme.Cache.put(:query_cache, "aprs_status", status) + + {:ok, _lv, html} = live(conn, ~p"/status", on_error: :warn) + assert html =~ "Cluster Status" + assert html =~ "Total Nodes" + assert html =~ "node-a" + assert html =~ "node-b" + + Aprsme.Cache.del(:query_cache, "aprs_status") + end + end end