aprs.me/test/aprsme/streaming_packets_pubsub_test.exs
Graham McIntire b86153cd27
Fix all mix credo --strict warnings (188 → 0)
- Replace apply/2 with direct fully-qualified calls in movement_test
- Fix assert_receive timeouts < 1000ms across 8 test files
- Move nested import statements to module-level scope
- Fix tests with no assertions and add missing doctest
- Replace weak type assertions with specific value checks
- Fix conditional assertions and length/1 expensive patterns
- Disable inappropriate Jump.CredoChecks.AvoidSocketAssignsInTest
- Fix tests not calling application code with credo:disable
- Add various credo:disable comments for legitimate patterns
2026-06-12 16:27:20 -05:00

240 lines
6.9 KiB
Elixir

defmodule Aprsme.StreamingPacketsPubSubTest do
use ExUnit.Case, async: true
alias Aprsme.StreamingPacketsPubSub
describe "subscribe_to_bounds/2" do
test "subscribes to packets within geographic bounds" do
bounds = %{
north: 40.0,
south: 30.0,
east: -70.0,
west: -80.0
}
assert :ok = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
end
test "receives packets within subscribed bounds" do
bounds = %{
north: 40.0,
south: 30.0,
east: -70.0,
west: -80.0
}
StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
# Packet within bounds
packet_in_bounds = %{
sender: "K1ABC",
latitude: 35.0,
longitude: -75.0,
received_at: DateTime.utc_now()
}
StreamingPacketsPubSub.broadcast_packet(packet_in_bounds)
assert_receive {:streaming_packet, ^packet_in_bounds}, 1000
end
test "does not receive packets outside subscribed bounds" do
bounds = %{
north: 40.0,
south: 30.0,
east: -70.0,
west: -80.0
}
StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
# Packet outside bounds
packet_outside_bounds = %{
sender: "K2XYZ",
# North of bounds
latitude: 45.0,
longitude: -75.0,
received_at: DateTime.utc_now()
}
StreamingPacketsPubSub.broadcast_packet(packet_outside_bounds)
refute_receive {:streaming_packet, _}, 100
end
test "handles multiple subscribers with different bounds" do
subscriber1 =
spawn(fn ->
receive do
_ -> :ok
end
end)
subscriber2 =
spawn(fn ->
receive do
_ -> :ok
end
end)
bounds1 = %{north: 40.0, south: 30.0, east: -70.0, west: -80.0}
bounds2 = %{north: 50.0, south: 40.0, east: -60.0, west: -70.0}
StreamingPacketsPubSub.subscribe_to_bounds(subscriber1, bounds1)
StreamingPacketsPubSub.subscribe_to_bounds(subscriber2, bounds2)
# Packet in bounds1 only
packet = %{
sender: "K3TEST",
latitude: 35.0,
longitude: -75.0,
received_at: DateTime.utc_now()
}
# Monitor to ensure processes are alive
ref1 = Process.monitor(subscriber1)
_ref2 = Process.monitor(subscriber2)
StreamingPacketsPubSub.broadcast_packet(packet)
# Verify subscriber1 gets the packet
send(subscriber1, {:check, self()})
assert_receive {:DOWN, ^ref1, :process, ^subscriber1, :normal}, 1000
# Verify subscriber2 is still alive (didn't receive packet)
Process.alive?(subscriber2)
end
end
describe "unsubscribe/1" do
test "stops receiving packets after unsubscribe" do
bounds = %{north: 40.0, south: 30.0, east: -70.0, west: -80.0}
StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
StreamingPacketsPubSub.unsubscribe(self())
packet = %{
sender: "K4TEST",
latitude: 35.0,
longitude: -75.0,
received_at: DateTime.utc_now()
}
StreamingPacketsPubSub.broadcast_packet(packet)
refute_receive {:streaming_packet, _}, 100
end
end
describe "list_subscribers/0" do
test "returns all active subscribers with their bounds" do
bounds = %{north: 40.0, south: 30.0, east: -70.0, west: -80.0}
StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
subscribers = StreamingPacketsPubSub.list_subscribers()
assert Enum.any?(subscribers, fn {pid, sub_bounds} ->
pid == self() && sub_bounds == bounds
end)
end
end
describe "when the server is not running" do
setup do
pid = Process.whereis(StreamingPacketsPubSub)
if pid do
:erlang.unregister(StreamingPacketsPubSub)
end
on_exit(fn ->
if pid && !Process.whereis(StreamingPacketsPubSub) do
true = Process.register(pid, StreamingPacketsPubSub)
end
end)
:ok
end
test "returns safe defaults instead of crashing" do
bounds = %{north: 40.0, south: 30.0, east: -70.0, west: -80.0}
assert {:error, :not_running} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
assert :ok = StreamingPacketsPubSub.unsubscribe(self())
assert :ok = StreamingPacketsPubSub.broadcast_packet(%{latitude: 35.0, longitude: -75.0})
assert [] == StreamingPacketsPubSub.list_subscribers()
end
end
describe "performance" do
test "handles high volume of packets efficiently" do
bounds = %{north: 90.0, south: -90.0, east: 180.0, west: -180.0}
StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
packets =
for i <- 1..1000 do
%{
sender: "K#{i}TEST",
latitude: :rand.uniform() * 180 - 90,
longitude: :rand.uniform() * 360 - 180,
received_at: DateTime.utc_now()
}
end
start_time = System.monotonic_time(:millisecond)
Enum.each(packets, &StreamingPacketsPubSub.broadcast_packet/1)
end_time = System.monotonic_time(:millisecond)
elapsed = end_time - start_time
# Should process 1000 packets in under 100ms
assert elapsed < 100
# Should receive all packets
received_count =
Enum.reduce(1..1000, 0, fn _, acc ->
receive do
{:streaming_packet, _} -> acc + 1
after
10 -> acc
end
end)
assert received_count == 1000
end
end
describe "subscribe_to_bounds/2 with invalid bounds" do
test "returns {:error, :invalid_bounds} when bounds are not numeric" do
bounds = %{north: "north", south: 0.0, east: 0.0, west: 0.0}
assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
end
test "returns {:error, :invalid_bounds} when north < south" do
bounds = %{north: -10.0, south: 10.0, east: 0.0, west: 0.0}
assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
end
test "returns {:error, :invalid_bounds} when latitude is out of range" do
bounds = %{north: 100.0, south: 0.0, east: 0.0, west: 0.0}
assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
end
test "returns {:error, :invalid_bounds} when longitude is out of range" do
bounds = %{north: 30.0, south: 10.0, east: 200.0, west: 0.0}
assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds)
end
test "returns {:error, :invalid_bounds} when bounds is not a map" do
assert {:error, :invalid_bounds} =
StreamingPacketsPubSub.subscribe_to_bounds(self(), :not_a_map)
end
test "returns {:error, :invalid_bounds} for a map missing required keys" do
assert {:error, :invalid_bounds} =
StreamingPacketsPubSub.subscribe_to_bounds(self(), %{partial: 1})
end
end
end