- Batch real-time packet push_events: collect marker data across the packet batch and send a single "new_packets" WebSocket message instead of one per packet. JS handler processes all live→historical conversions before adding new markers to avoid intra-batch conflicts. - Batch RF path station queries: replace N+1 get_latest_packet_for_callsign calls with a single DISTINCT ON query selecting only callsign + lat/lng. - Add read_concurrency: true to streaming_packets_subscribers and :aprsme ETS tables (read-heavy, rarely written). - Remove dead GC code in PacketConsumer (threshold > 1000 unreachable with max batch_size of 100).
113 lines
3.2 KiB
Elixir
113 lines
3.2 KiB
Elixir
defmodule Aprsme.Packets.PreparedQueriesTest do
|
|
use Aprsme.DataCase, async: false
|
|
|
|
alias Aprsme.Packet
|
|
alias Aprsme.Packets.PreparedQueries
|
|
alias Aprsme.Repo
|
|
|
|
defp create_positioned_packet(attrs) do
|
|
defaults = %{
|
|
sender: "TEST-1",
|
|
base_callsign: "TEST",
|
|
ssid: "1",
|
|
destination: "APRS",
|
|
data_type: "position",
|
|
lat: Decimal.new("33.0000"),
|
|
lon: Decimal.new("-96.0000"),
|
|
received_at: DateTime.truncate(DateTime.utc_now(), :second)
|
|
}
|
|
|
|
merged = Map.merge(defaults, attrs)
|
|
|
|
%Packet{}
|
|
|> Packet.changeset(Map.from_struct(Map.merge(%Packet{}, merged)))
|
|
|> Repo.insert()
|
|
end
|
|
|
|
describe "get_latest_positions_for_callsigns/1" do
|
|
test "returns positions for multiple callsigns" do
|
|
{:ok, _} =
|
|
create_positioned_packet(%{
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: Decimal.new("33.1000"),
|
|
lon: Decimal.new("-96.6000")
|
|
})
|
|
|
|
{:ok, _} =
|
|
create_positioned_packet(%{
|
|
sender: "N5TXZ-10",
|
|
base_callsign: "N5TXZ",
|
|
ssid: "10",
|
|
lat: Decimal.new("33.2000"),
|
|
lon: Decimal.new("-96.5000")
|
|
})
|
|
|
|
result = PreparedQueries.get_latest_positions_for_callsigns(["K5GVL-10", "N5TXZ-10"])
|
|
|
|
assert length(result) == 2
|
|
callsigns = Enum.map(result, & &1.callsign)
|
|
assert "K5GVL-10" in callsigns
|
|
assert "N5TXZ-10" in callsigns
|
|
|
|
k5gvl = Enum.find(result, &(&1.callsign == "K5GVL-10"))
|
|
assert_in_delta k5gvl.lat, 33.1, 0.01
|
|
assert_in_delta k5gvl.lng, -96.6, 0.01
|
|
end
|
|
|
|
test "returns empty list for empty input" do
|
|
assert PreparedQueries.get_latest_positions_for_callsigns([]) == []
|
|
end
|
|
|
|
test "returns empty list for nonexistent callsigns" do
|
|
result = PreparedQueries.get_latest_positions_for_callsigns(["NONEXIST-1", "FAKE-2"])
|
|
assert result == []
|
|
end
|
|
|
|
test "is case-insensitive" do
|
|
{:ok, _} =
|
|
create_positioned_packet(%{
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: Decimal.new("33.1000"),
|
|
lon: Decimal.new("-96.6000")
|
|
})
|
|
|
|
result = PreparedQueries.get_latest_positions_for_callsigns(["k5gvl-10"])
|
|
|
|
assert length(result) == 1
|
|
assert hd(result).callsign == "K5GVL-10"
|
|
end
|
|
|
|
test "returns latest position when multiple packets exist for a callsign" do
|
|
{:ok, _} =
|
|
create_positioned_packet(%{
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: Decimal.new("33.1000"),
|
|
lon: Decimal.new("-96.6000"),
|
|
received_at: DateTime.add(DateTime.utc_now(), -3600, :second)
|
|
})
|
|
|
|
{:ok, _} =
|
|
create_positioned_packet(%{
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: Decimal.new("34.0000"),
|
|
lon: Decimal.new("-97.0000"),
|
|
received_at: DateTime.truncate(DateTime.utc_now(), :second)
|
|
})
|
|
|
|
result = PreparedQueries.get_latest_positions_for_callsigns(["K5GVL-10"])
|
|
|
|
assert length(result) == 1
|
|
position = hd(result)
|
|
assert_in_delta position.lat, 34.0, 0.01
|
|
assert_in_delta position.lng, -97.0, 0.01
|
|
end
|
|
end
|
|
end
|