more tests
This commit is contained in:
parent
094a50d183
commit
6b624e1365
8 changed files with 77 additions and 61 deletions
|
|
@ -43,6 +43,9 @@ config :aprsme, AprsmeWeb.Telemetry, enabled: false
|
|||
# Disable cleanup scheduler in test environment
|
||||
config :aprsme, :cleanup_scheduler, enabled: false
|
||||
|
||||
# Speed up ConnectionManager init in test environment
|
||||
config :aprsme, :connection_manager_init_delay, 0
|
||||
|
||||
# Disable initialize replay delay in test environment
|
||||
config :aprsme, :initialize_replay_delay, 0
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,14 @@ defmodule Aprsme.Application do
|
|||
Aprsme.PacketPipelineSupervisor
|
||||
]
|
||||
|
||||
# Skip packet pipeline in test to avoid Sandbox ownership errors
|
||||
children =
|
||||
if Application.get_env(:aprsme, :env) == :test do
|
||||
List.delete(children, Aprsme.PacketPipelineSupervisor)
|
||||
else
|
||||
children
|
||||
end
|
||||
|
||||
children = children ++ redis_children()
|
||||
|
||||
# Add shutdown handlers at the end, after everything else is started
|
||||
|
|
|
|||
|
|
@ -20,14 +20,15 @@ defmodule Aprsme.Cluster.ConnectionManager do
|
|||
Phoenix.PubSub.subscribe(Aprsme.PubSub, "cluster:leadership")
|
||||
|
||||
# Check initial leadership state
|
||||
Process.send_after(self(), :check_initial_state, 1000)
|
||||
delay = Application.get_env(:aprsme, :connection_manager_init_delay, 1000)
|
||||
Process.send_after(self(), :check_initial_state, delay)
|
||||
|
||||
{:ok, %{connection_started: false}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(:check_initial_state, state) do
|
||||
if LeaderElection.leader?() do
|
||||
if leader_check() do
|
||||
Logger.info("This node is the leader, starting APRS-IS connection")
|
||||
start_aprs_connection()
|
||||
{:noreply, %{state | connection_started: true}}
|
||||
|
|
@ -55,6 +56,12 @@ defmodule Aprsme.Cluster.ConnectionManager do
|
|||
end
|
||||
end
|
||||
|
||||
defp leader_check do
|
||||
LeaderElection.leader?()
|
||||
catch
|
||||
:exit, _ -> false
|
||||
end
|
||||
|
||||
defp start_aprs_connection do
|
||||
# Start the APRS-IS connection supervisor if not already started
|
||||
case DynamicSupervisor.start_child(
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ defmodule Aprsme.LogSanitizer do
|
|||
@doc """
|
||||
Sanitize any data structure recursively
|
||||
"""
|
||||
def sanitize(%{__struct__: _} = data) when is_exception(data) do
|
||||
sanitize_string(Exception.message(data))
|
||||
end
|
||||
|
||||
def sanitize(%{__struct__: _} = data) do
|
||||
data
|
||||
|> Map.from_struct()
|
||||
|> sanitize()
|
||||
end
|
||||
|
||||
def sanitize(data) when is_map(data) do
|
||||
data
|
||||
|> sanitize_map()
|
||||
|
|
|
|||
|
|
@ -21,14 +21,27 @@ defmodule Aprsme.PacketPipelineSetup do
|
|||
config = Application.get_env(:aprsme, :packet_pipeline, [])
|
||||
max_demand = config[:max_demand] || 50
|
||||
|
||||
case GenStage.sync_subscribe(Aprsme.PacketConsumer, to: Aprsme.PacketProducer, max_demand: max_demand) do
|
||||
{:ok, _subscription} ->
|
||||
require Logger
|
||||
try do
|
||||
case GenStage.sync_subscribe(Aprsme.PacketConsumer,
|
||||
to: Aprsme.PacketProducer,
|
||||
max_demand: max_demand
|
||||
) do
|
||||
{:ok, _subscription} ->
|
||||
require Logger
|
||||
|
||||
Logger.info("GenStage packet pipeline subscription established")
|
||||
{:noreply, state}
|
||||
Logger.info("GenStage packet pipeline subscription established")
|
||||
{:noreply, state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason} ->
|
||||
require Logger
|
||||
|
||||
Logger.error("Failed to establish GenStage subscription: #{inspect(reason)}")
|
||||
# Retry after a delay
|
||||
Process.send_after(self(), :setup_subscription, 1000)
|
||||
{:noreply, state}
|
||||
end
|
||||
catch
|
||||
:exit, reason ->
|
||||
require Logger
|
||||
|
||||
Logger.error("Failed to establish GenStage subscription: #{inspect(reason)}")
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
# Start a minimal LeaderElection to prevent crashes
|
||||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _} = LeaderElection.start_link([])
|
||||
Process.sleep(200)
|
||||
Process.sleep(150)
|
||||
:ok
|
||||
end
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
)
|
||||
|
||||
# Give time for message processing
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Process should still be alive after receiving message
|
||||
assert Process.whereis(ConnectionManager)
|
||||
|
|
@ -103,8 +103,8 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
test "schedules initial state check" do
|
||||
{:ok, pid} = ConnectionManager.start_link([])
|
||||
|
||||
# Should receive :check_initial_state message after init
|
||||
Process.sleep(1100)
|
||||
# With delay set to 0 in test config, the check fires immediately
|
||||
Process.sleep(50)
|
||||
|
||||
# Process should still be alive
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -116,8 +116,8 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
# Start LeaderElection in non-clustered mode so it becomes leader
|
||||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _} = LeaderElection.start_link([])
|
||||
# Wait for election
|
||||
Process.sleep(200)
|
||||
# Wait for election (100ms timer + processing)
|
||||
Process.sleep(150)
|
||||
|
||||
# Start ConnectionManager
|
||||
{:ok, pid} = ConnectionManager.start_link([])
|
||||
|
|
@ -127,20 +127,16 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
test "handles initial state check when leader", %{pid: pid} do
|
||||
# Send initial state check
|
||||
send(pid, :check_initial_state)
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle without crashing
|
||||
assert Process.alive?(pid)
|
||||
end
|
||||
|
||||
test "handles initial state check when not leader", %{pid: pid} do
|
||||
# ConnectionManager will check with LeaderElection
|
||||
# In test environment, it will get that it's the leader
|
||||
# This is OK - we're just testing that it handles the check without crashing
|
||||
|
||||
# Send initial state check
|
||||
send(pid, :check_initial_state)
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle without crashing
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -152,18 +148,18 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
# Ensure LeaderElection is started
|
||||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _} = LeaderElection.start_link([])
|
||||
Process.sleep(200)
|
||||
Process.sleep(150)
|
||||
|
||||
{:ok, pid} = ConnectionManager.start_link([])
|
||||
# Wait for initial check
|
||||
Process.sleep(1100)
|
||||
# With delay=0, initial check fires immediately; just wait for processing
|
||||
Process.sleep(50)
|
||||
{:ok, pid: pid}
|
||||
end
|
||||
|
||||
test "starts connection when becoming leader", %{pid: pid} do
|
||||
# Send leadership change - this node became leader
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle the message without crashing
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -172,11 +168,11 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
test "stops connection when losing leadership", %{pid: pid} do
|
||||
# First become leader and start connection
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Then lose leadership
|
||||
send(pid, {:leadership_change, node(), false})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle the message without crashing
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -187,7 +183,7 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
|
||||
# Send leadership change for another node
|
||||
send(pid, {:leadership_change, other_node, true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should not affect this node
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -196,10 +192,10 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
test "does not start connection twice", %{pid: pid} do
|
||||
# Become leader twice
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle duplicate leadership without issues
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -211,20 +207,18 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
# Ensure LeaderElection is started
|
||||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _} = LeaderElection.start_link([])
|
||||
Process.sleep(200)
|
||||
Process.sleep(150)
|
||||
|
||||
{:ok, pid} = ConnectionManager.start_link([])
|
||||
Process.sleep(1100)
|
||||
# With delay=0, initial check fires immediately; just wait for processing
|
||||
Process.sleep(50)
|
||||
{:ok, pid: pid}
|
||||
end
|
||||
|
||||
test "handles IsSupervisor already started error", %{pid: pid} do
|
||||
# The APRS-IS connection is disabled in test environment,
|
||||
# but we can still test that the ConnectionManager handles errors gracefully
|
||||
|
||||
# Try to become leader
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle gracefully even if IsSupervisor fails to start
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -239,12 +233,9 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
end
|
||||
end
|
||||
|
||||
# Temporarily replace the module reference
|
||||
# This test is more conceptual as we can't easily mock module references
|
||||
|
||||
# Send leadership change
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Should handle failure gracefully
|
||||
assert Process.alive?(pid)
|
||||
|
|
@ -256,26 +247,26 @@ defmodule Aprsme.Cluster.ConnectionManagerTest do
|
|||
# Ensure LeaderElection is started
|
||||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _} = LeaderElection.start_link([])
|
||||
Process.sleep(200)
|
||||
Process.sleep(150)
|
||||
|
||||
{:ok, pid} = ConnectionManager.start_link([])
|
||||
{:ok, pid: pid}
|
||||
end
|
||||
|
||||
test "full lifecycle - become leader, lose leadership", %{pid: pid} do
|
||||
# Wait for initial check
|
||||
Process.sleep(1100)
|
||||
# With delay=0, initial check fires immediately; just wait for processing
|
||||
Process.sleep(50)
|
||||
|
||||
# Become leader
|
||||
send(pid, {:leadership_change, node(), true})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Verify connection started (check state indirectly)
|
||||
assert Process.alive?(pid)
|
||||
|
||||
# Lose leadership
|
||||
send(pid, {:leadership_change, node(), false})
|
||||
Process.sleep(100)
|
||||
Process.sleep(50)
|
||||
|
||||
# Verify still alive after stopping connection
|
||||
assert Process.alive?(pid)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ defmodule AprsmeWeb.MapLive.MovementTest do
|
|||
|
||||
# The view should not push a new_packet event for GPS drift
|
||||
# Using a longer timeout to avoid flaky tests on slower systems
|
||||
refute_push_event(view, "new_packet", %{id: "TEST-1"}, 2000)
|
||||
refute_push_event(view, "new_packet", %{id: "TEST-1"}, 200)
|
||||
end
|
||||
|
||||
test "updates marker for significant movement", %{conn: conn} do
|
||||
|
|
|
|||
|
|
@ -5,18 +5,6 @@ defmodule Aprsme.MockHelpers do
|
|||
|
||||
def stub_packets_mock do
|
||||
# Stub the packets module to prevent external calls
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign, fn _callsign ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign_with_limit, fn _callsign, _limit ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign_with_date_range, fn _callsign, _start_date, _end_date ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_recent_packets, fn _opts ->
|
||||
[]
|
||||
end)
|
||||
|
|
@ -25,8 +13,4 @@ defmodule Aprsme.MockHelpers do
|
|||
[]
|
||||
end)
|
||||
end
|
||||
|
||||
def stub_badpackets_mock do
|
||||
Mox.stub_with(BadPacketsMock, BadPacketsStub)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue