Push coverage past 90% with MapLive postgres_packet/packet_batch and preferred_tracked_packet tests

This commit is contained in:
Graham McIntire 2026-05-08 14:24:47 -05:00
parent 3f7170cfa2
commit 446497d60b
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59

View file

@ -445,5 +445,368 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "{:DOWN, ref, _, batcher_pid, _} restarts the PacketBatcher", %{conn: conn} do
{:ok, view, _html} = live(conn, "/", on_error: :warn)
original_pid =
:sys.get_state(view.pid).socket.assigns.batcher_pid
# Send a fake DOWN message to simulate the batcher dying.
send(view.pid, {:DOWN, make_ref(), :process, original_pid, :test_kill})
Process.sleep(30)
# The handle_info DOWN handler should have spawned a new batcher.
new_pid = :sys.get_state(view.pid).socket.assigns.batcher_pid
assert is_pid(new_pid)
end
test "{:process_pending_bounds} with pending_bounds set triggers handle_bounds_update", %{conn: conn} do
{:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=10", on_error: :warn)
render_hook(view, "map_ready", %{})
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
new_socket = %{
inner_socket
| assigns:
inner_socket.assigns
|> Map.put(:pending_bounds, %{north: 35.0, south: 31.0, east: -94.0, west: -98.0})
|> Map.put(:historical_loading, false)
}
%{channel_state | socket: new_socket}
end)
send(view.pid, {:process_pending_bounds})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "stale bounds-update Logger.debug branch with :debug log level", %{conn: conn} do
original_level = Logger.level()
Logger.configure(level: :debug)
try do
{:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=10", on_error: :warn)
# The LV channel state nests the socket under :socket. Set pending_bounds
# via :sys.replace_state with that wrapper structure.
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
new_socket = %{
inner_socket
| assigns: Map.put(inner_socket.assigns, :pending_bounds, %{north: 99.0, south: 0.0, east: 1.0, west: 0.0})
}
%{channel_state | socket: new_socket}
end)
# Send a different bounds — should hit the "stale" Logger.debug branch
# (line 1003 in index.ex), evaluating the format string at :debug level.
send(view.pid, {:process_bounds_update, %{north: 34.0, south: 32.0, east: -95.0, west: -97.0}})
Process.sleep(30)
assert render(view) =~ "aprs-map"
after
Logger.configure(level: original_level)
end
end
test "tracked-callsign postgres_packet path with batcher_pid forced nil", %{conn: conn} do
# Force batcher_pid to nil so {:postgres_packet, _} flows through
# handle_info_postgres_packet (lines 1053+).
{:ok, view, _html} = live(conn, "/?call=PGTRK", on_error: :warn)
render_hook(view, "map_ready", %{})
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
new_socket = %{inner_socket | assigns: Map.put(inner_socket.assigns, :batcher_pid, nil)}
%{channel_state | socket: new_socket}
end)
# Send a packet with sender matching tracked callsign — exercises the
# tracked-callsign branch in handle_info_postgres_packet.
packet = %{
id: "pgtrk-1",
sender: "PGTRK",
base_callsign: "PGTRK",
ssid: "0",
lat: 33.0,
lon: -96.0,
has_position: true,
symbol_table_id: "/",
symbol_code: ">",
received_at: DateTime.utc_now(),
path: "WIDE1-1"
}
send(view.pid, {:postgres_packet, packet})
Process.sleep(50)
# Send a packet with a different sender — exercises the no-match branch.
send(view.pid, {:postgres_packet, %{packet | sender: "OTHER", base_callsign: "OTHER"}})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "untracked postgres_packet path with batcher_pid nil hits handle_info_postgres_packet else branch", %{
conn: conn
} do
{:ok, view, _html} = live(conn, "/", on_error: :warn)
render_hook(view, "map_ready", %{})
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
new_socket = %{inner_socket | assigns: Map.put(inner_socket.assigns, :batcher_pid, nil)}
%{channel_state | socket: new_socket}
end)
packet = %{
id: "untracked-1",
sender: "UNT",
base_callsign: "UNT",
ssid: "1",
lat: 33.0,
lon: -96.0,
has_position: true,
symbol_table_id: "/",
symbol_code: ">",
received_at: DateTime.utc_now(),
path: "WIDE1-1"
}
send(view.pid, {:postgres_packet, packet})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "spatial_packet path with batcher_pid nil hits handle_info_postgres_packet branch", %{conn: conn} do
{:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=12", on_error: :warn)
render_hook(view, "map_ready", %{})
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
new_socket = %{inner_socket | assigns: Map.put(inner_socket.assigns, :batcher_pid, nil)}
%{channel_state | socket: new_socket}
end)
packet = %{
id: "spatial-x",
sender: "SPX",
base_callsign: "SPX",
ssid: "1",
lat: 33.0,
lon: -96.0,
has_position: true,
symbol_table_id: "/",
symbol_code: ">",
received_at: DateTime.utc_now(),
path: "WIDE1-1"
}
send(view.pid, {:spatial_packet, packet})
Process.sleep(50)
send(view.pid, {:streaming_packet, packet})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "tracked-callsign positionless packets with NaiveDateTime received_at hits newer_packet? NaiveDateTime branch",
%{
conn: conn
} do
{:ok, view, _html} = live(conn, "/?call=NAIV&lat=33.0&lng=-96.0&z=12", on_error: :warn)
render_hook(view, "map_ready", %{})
# Pre-load tracked latest packet without position with a NaiveDateTime.
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
current = %{
sender: "NAIV",
base_callsign: "NAIV",
ssid: "0",
lat: nil,
lon: nil,
has_position: false,
received_at: ~N[2026-01-01 00:00:00]
}
new_socket = %{
inner_socket
| assigns: Map.put(inner_socket.assigns, :tracked_callsign_latest_packet, current)
}
%{channel_state | socket: new_socket}
end)
naive_packet = %{
id: "naiv-1",
sender: "NAIV",
base_callsign: "NAIV",
ssid: "0",
lat: nil,
lon: nil,
has_position: false,
received_at: ~N[2026-06-01 00:00:00],
path: ""
}
send(view.pid, {:packet_batch, [naive_packet]})
Process.sleep(50)
# Now exercise the unrelated-types fallback (DateTime vs nil).
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
current = %{
sender: "NAIV",
base_callsign: "NAIV",
ssid: "0",
lat: nil,
lon: nil,
has_position: false,
received_at: nil
}
new_socket = %{
inner_socket
| assigns: Map.put(inner_socket.assigns, :tracked_callsign_latest_packet, current)
}
%{channel_state | socket: new_socket}
end)
send(view.pid, {:packet_batch, [Map.put(naive_packet, :received_at, nil)]})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "tracked-callsign with positionless incoming exercises preferred_tracked_packet branches", %{conn: conn} do
# Set up a tracked callsign with a current packet that has position.
# Send incoming packets without position to walk through the cond
# branches in preferred_tracked_packet/2.
{:ok, view, _html} = live(conn, "/?call=PREF&lat=33.0&lng=-96.0&z=12", on_error: :warn)
render_hook(view, "map_ready", %{})
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
# Pre-load tracked_callsign_latest_packet so preferred_tracked_packet/2
# has a non-nil current_packet to compare against.
current = %{
sender: "PREF",
base_callsign: "PREF",
ssid: "0",
lat: 33.0,
lon: -96.0,
has_position: true,
received_at: DateTime.add(DateTime.utc_now(), -120, :second)
}
new_socket = %{
inner_socket
| assigns: Map.put(inner_socket.assigns, :tracked_callsign_latest_packet, current)
}
%{channel_state | socket: new_socket}
end)
# Incoming packet without position — exercises lines 1842, 1843
# (current has position, incoming doesn't → current returned).
no_pos_packet = %{
id: "nopos-1",
sender: "PREF",
base_callsign: "PREF",
ssid: "0",
lat: nil,
lon: nil,
has_position: false,
received_at: DateTime.utc_now(),
path: ""
}
send(view.pid, {:packet_batch, [no_pos_packet]})
Process.sleep(50)
# Both nil-position; newer DateTime returned.
:sys.replace_state(view.pid, fn channel_state ->
inner_socket = channel_state.socket
current_no_pos = %{
sender: "PREF",
base_callsign: "PREF",
ssid: "0",
lat: nil,
lon: nil,
has_position: false,
received_at: DateTime.add(DateTime.utc_now(), -1000, :second)
}
new_socket = %{
inner_socket
| assigns: Map.put(inner_socket.assigns, :tracked_callsign_latest_packet, current_no_pos)
}
%{channel_state | socket: new_socket}
end)
send(view.pid, {:packet_batch, [no_pos_packet]})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
test "tracked-callsign packet_batch processes the matching-sender branch", %{conn: conn} do
{:ok, view, _html} = live(conn, "/?call=BATCH&lat=33.0&lng=-96.0&z=12", on_error: :warn)
render_hook(view, "map_ready", %{})
render_hook(view, "bounds_changed", %{
"bounds" => %{
"north" => 34.0,
"south" => 32.0,
"east" => -95.0,
"west" => -97.0
}
})
packets = [
%{
id: "btr-1",
sender: "BATCH",
base_callsign: "BATCH",
ssid: "0",
lat: 33.5,
lon: -96.0,
has_position: true,
symbol_table_id: "/",
symbol_code: ">",
received_at: DateTime.utc_now(),
path: ""
},
%{
id: "btr-2",
sender: "OTHER",
base_callsign: "OTHER",
ssid: "1",
lat: 33.5,
lon: -96.5,
has_position: true,
symbol_table_id: "/",
symbol_code: ">",
received_at: DateTime.utc_now(),
path: ""
}
]
send(view.pid, {:packet_batch, packets})
Process.sleep(50)
assert render(view) =~ "aprs-map"
end
end
end