Push coverage past 90% with MapLive postgres_packet/packet_batch and preferred_tracked_packet tests
This commit is contained in:
parent
3f7170cfa2
commit
446497d60b
1 changed files with 363 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue