From c8c20add1f0146d62da372ec2a6ff48ac644891e Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Thu, 23 Apr 2026 17:56:03 -0500 Subject: [PATCH] test: expand Is backpressure, PacketReplay, CleanupScheduler coverage --- test/aprsme/cleanup_scheduler_test.exs | 15 ++++++++ test/aprsme/is_test.exs | 50 ++++++++++++++++++++++++++ test/aprsme/packet_replay_test.exs | 28 +++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/test/aprsme/cleanup_scheduler_test.exs b/test/aprsme/cleanup_scheduler_test.exs index 5fc8e6f..fba3ce5 100644 --- a/test/aprsme/cleanup_scheduler_test.exs +++ b/test/aprsme/cleanup_scheduler_test.exs @@ -48,5 +48,20 @@ defmodule Aprsme.CleanupSchedulerTest do state = %{interval: nil} assert CleanupScheduler.handle_info(:schedule_cleanup, state) == {:noreply, state} end + + test "runs cleanup and reschedules when interval is an integer" do + # Ensure BroadcastTaskSupervisor is up — it wraps Task.Supervisor. + _ = + case Process.whereis(Aprsme.BroadcastTaskSupervisor) do + nil -> start_supervised({Task.Supervisor, name: Aprsme.BroadcastTaskSupervisor}) + _ -> :ok + end + + state = %{interval: 100} + + assert {:noreply, ^state} = CleanupScheduler.handle_info(:schedule_cleanup, state) + # Next cleanup scheduled. + assert_receive :schedule_cleanup, 300 + end end end diff --git a/test/aprsme/is_test.exs b/test/aprsme/is_test.exs index 54c3627..338ed51 100644 --- a/test/aprsme/is_test.exs +++ b/test/aprsme/is_test.exs @@ -498,6 +498,56 @@ defmodule Aprsme.IsTest do end end + describe "backpressure handling" do + test "activate with nil socket is a no-op" do + state = build_state(%{socket: nil, backpressure_active: false}) + + assert {:noreply, ^state} = + Aprsme.Is.handle_info({:backpressure, :activate}, state) + end + + test "activate when already active is a no-op" do + state = build_state(%{socket: nil, backpressure_active: true}) + + assert {:noreply, ^state} = + Aprsme.Is.handle_info({:backpressure, :activate}, state) + end + + test "deactivate when already inactive is a no-op" do + state = build_state(%{socket: nil, backpressure_active: false}) + + assert {:noreply, ^state} = + Aprsme.Is.handle_info({:backpressure, :deactivate}, state) + end + + test "deactivate with nil socket clears flag but doesn't touch socket" do + state = build_state(%{socket: nil, backpressure_active: true}) + + assert {:noreply, new_state} = + Aprsme.Is.handle_info({:backpressure, :deactivate}, state) + + refute new_state.backpressure_active + assert is_nil(new_state.safety_valve_timer) + end + + test "safety_valve when not active is a no-op" do + state = build_state(%{backpressure_active: false}) + + assert {:noreply, ^state} = + Aprsme.Is.handle_info(:backpressure_safety_valve, state) + end + + test "safety_valve with nil socket clears flag" do + state = build_state(%{socket: nil, backpressure_active: true, safety_valve_timer: nil}) + + assert {:noreply, new_state} = + Aprsme.Is.handle_info(:backpressure_safety_valve, state) + + refute new_state.backpressure_active + assert is_nil(new_state.safety_valve_timer) + end + end + describe "APRS-IS mock functionality" do setup do case GenServer.start_link(AprsIsMock, [], name: AprsIsMock) do diff --git a/test/aprsme/packet_replay_test.exs b/test/aprsme/packet_replay_test.exs index db9021e..3e5003a 100644 --- a/test/aprsme/packet_replay_test.exs +++ b/test/aprsme/packet_replay_test.exs @@ -265,5 +265,33 @@ defmodule Aprsme.PacketReplayTest do # Timer should have been cancelled. assert Process.read_timer(timer_ref) == false end + + test "terminate is idempotent with no pending timer" do + {:ok, state} = PacketReplay.init(user_id: "noterm", bounds: [0, 0, 1, 1]) + + receive do + :start_replay -> :ok + after + 0 -> :ok + end + + assert :ok = PacketReplay.terminate(:normal, state) + end + end + + describe "handle_info(:start_replay, ...)" do + test "broadcasts replay_started then stops when no matching packets" do + {:ok, state} = PacketReplay.init(user_id: "empty_stream", bounds: [0, 0, 1, 1]) + + receive do + :start_replay -> :ok + after + 0 -> :ok + end + + # With no seeded packets in the DB, stream_packets_for_replay returns an + # empty stream and handle_info :start_replay should stop the server. + assert {:stop, :normal, _state} = PacketReplay.handle_info(:start_replay, state) + end end end