From eeec857d01ad828b06cb283c289f73479129adfc Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 8 May 2026 17:13:32 -0500 Subject: [PATCH] Add tests for batch_dispatch out-of-bounds removal and load_historical_batch matching generation --- .../live/map_live/integration_test.exs | 105 +++++++++++++++++- 1 file changed, 100 insertions(+), 5 deletions(-) diff --git a/test/aprsme_web/live/map_live/integration_test.exs b/test/aprsme_web/live/map_live/integration_test.exs index e7c5012..1c07024 100644 --- a/test/aprsme_web/live/map_live/integration_test.exs +++ b/test/aprsme_web/live/map_live/integration_test.exs @@ -364,8 +364,20 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do {:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=10", on_error: :warn) render_hook(view, "map_ready", %{}) - # Use the loading_generation that the LV currently has (default 0). - send(view.pid, {:load_historical_batch, 0, 0}) + # Force loading_generation to a known value so the matching-branch + # (line 957) is exercised. + :sys.replace_state(view.pid, fn channel_state -> + inner_socket = channel_state.socket + + new_socket = %{ + inner_socket + | assigns: Map.put(inner_socket.assigns, :loading_generation, 7) + } + + %{channel_state | socket: new_socket} + end) + + send(view.pid, {:load_historical_batch, 0, 7}) Process.sleep(20) assert render(view) =~ "aprs-map" end @@ -756,6 +768,59 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do assert render_hook(view, "clear_and_reload_markers", %{}) end + test "{:packet_batch, _} with out-of-bounds known marker triggers remove_markers_if_needed 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", %{}) + + render_hook(view, "bounds_changed", %{ + "bounds" => %{"north" => 34.0, "south" => 32.0, "east" => -95.0, "west" => -97.0} + }) + + # Pre-populate visible_packets with a marker we'll later send out-of-bounds. + :sys.replace_state(view.pid, fn channel_state -> + inner_socket = channel_state.socket + + existing_packet = %{ + sender: "MOVE", + base_callsign: "MOVE", + ssid: "0", + lat: 33.5, + lon: -96.0, + has_position: true, + received_at: DateTime.utc_now() + } + + new_socket = %{ + inner_socket + | assigns: Map.put(inner_socket.assigns, :visible_packets, %{"MOVE" => existing_packet}) + } + + %{channel_state | socket: new_socket} + end) + + # Now send a batch with the same callsign but moved out-of-bounds — this + # routes through batch_dispatch({false, true}, ...) and returns + # {socket, nil, callsign_key}, which feeds remove_markers_if_needed + # with a non-empty list. + out_of_bounds_packet = %{ + id: "move-out", + sender: "MOVE", + base_callsign: "MOVE", + ssid: "0", + lat: 50.0, + lon: -120.0, + has_position: true, + symbol_table_id: "/", + symbol_code: ">", + received_at: DateTime.utc_now(), + path: "" + } + + send(view.pid, {:packet_batch, [out_of_bounds_packet]}) + Process.sleep(50) + assert render(view) =~ "aprs-map" + end + test "set_location with string lat/lng exercises to_float(binary) parse paths", %{conn: conn} do {:ok, view, _html} = live(conn, "/", on_error: :warn) @@ -893,9 +958,23 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do {:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=6", on_error: :warn) render_hook(view, "map_ready", %{}) - render_hook(view, "bounds_changed", %{ - "bounds" => %{"north" => 40.0, "south" => 30.0, "east" => -90.0, "west" => -100.0} - }) + # Force-set map_bounds and zoom directly so the packet_batch processing + # reaches update_display_for_batch with a non-empty marker_data_list at + # low zoom (lines 1122-1123 heat map branch). + :sys.replace_state(view.pid, fn channel_state -> + inner_socket = channel_state.socket + + new_socket = %{ + inner_socket + | assigns: + inner_socket.assigns + |> Map.put(:map_bounds, %{north: 40.0, south: 30.0, east: -90.0, west: -100.0}) + |> Map.put(:map_zoom, 6) + |> Map.put(:initial_bounds_loaded, true) + } + + %{channel_state | socket: new_socket} + end) packets = [ %{ @@ -933,6 +1012,22 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do {:ok, view, _html} = live(conn, "/?call=LZTR&lat=33.0&lng=-96.0&z=6", 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(:map_bounds, %{north: 40.0, south: 30.0, east: -90.0, west: -100.0}) + |> Map.put(:map_zoom, 6) + |> Map.put(:initial_bounds_loaded, true) + |> Map.put(:tracked_callsign, "LZTR") + } + + %{channel_state | socket: new_socket} + end) + packets = [ %{ id: "lztr-1",