Remove :slow test tag; make slow tests run fast via configurable timeouts
- Make LeaderElection check_interval, max_cluster_wait, and cluster_check_interval configurable via Application env so tests can override with short values - Slow LeaderElection tests now use 50-150ms timeouts instead of 3-6s - Remove :slow tag from unused_test (compile cache makes reruns cheap) - Drop :slow from test_helper exclude list All 2490 tests now run in ~45s (up from 2485 with 5 excluded).
This commit is contained in:
parent
001af22286
commit
1ddc817f50
4 changed files with 34 additions and 24 deletions
|
|
@ -8,9 +8,16 @@ defmodule Aprsme.Cluster.LeaderElection do
|
|||
require Logger
|
||||
|
||||
@election_key {:aprs_is_leader, __MODULE__}
|
||||
@check_interval 5_000
|
||||
@default_check_interval 5_000
|
||||
# Maximum time to wait for cluster formation before proceeding with election (30 seconds)
|
||||
@max_cluster_wait 30_000
|
||||
@default_max_cluster_wait 30_000
|
||||
@default_cluster_check_interval 2_000
|
||||
|
||||
defp check_interval, do: Application.get_env(:aprsme, :election_check_interval_ms, @default_check_interval)
|
||||
defp max_cluster_wait, do: Application.get_env(:aprsme, :election_max_cluster_wait_ms, @default_max_cluster_wait)
|
||||
|
||||
defp cluster_check_interval,
|
||||
do: Application.get_env(:aprsme, :election_cluster_check_interval_ms, @default_cluster_check_interval)
|
||||
|
||||
defstruct is_leader: false,
|
||||
leader_node: nil,
|
||||
|
|
@ -63,7 +70,7 @@ defmodule Aprsme.Cluster.LeaderElection do
|
|||
schedule_initial_election(cluster_enabled)
|
||||
|
||||
# Schedule periodic checks
|
||||
Process.send_after(self(), :check_leadership, @check_interval)
|
||||
Process.send_after(self(), :check_leadership, check_interval())
|
||||
|
||||
# Initialize cached leadership state
|
||||
:persistent_term.put({__MODULE__, :is_leader}, false)
|
||||
|
|
@ -74,8 +81,8 @@ defmodule Aprsme.Cluster.LeaderElection do
|
|||
# Clustered mode: wait for formation, then elect; schedule a backstop timeout.
|
||||
defp schedule_initial_election(true) do
|
||||
Logger.info("Clustering enabled - waiting for cluster formation before leader election")
|
||||
Process.send_after(self(), :check_cluster_and_elect, 2_000)
|
||||
Process.send_after(self(), :force_election_timeout, @max_cluster_wait)
|
||||
Process.send_after(self(), :check_cluster_and_elect, cluster_check_interval())
|
||||
Process.send_after(self(), :force_election_timeout, max_cluster_wait())
|
||||
end
|
||||
|
||||
# Non-clustered mode: elect immediately.
|
||||
|
|
@ -118,12 +125,12 @@ defmodule Aprsme.Cluster.LeaderElection do
|
|||
|
||||
if connected_nodes == [] do
|
||||
Logger.warning(
|
||||
"Cluster formation timeout reached after #{@max_cluster_wait}ms with no connected nodes. " <>
|
||||
"Cluster formation timeout reached after #{max_cluster_wait()}ms with no connected nodes. " <>
|
||||
"Proceeding with leader election in single-node mode to ensure APRS-IS connection."
|
||||
)
|
||||
else
|
||||
Logger.info(
|
||||
"Forcing leader election after #{@max_cluster_wait}ms wait with #{length(connected_nodes)} connected nodes"
|
||||
"Forcing leader election after #{max_cluster_wait()}ms wait with #{length(connected_nodes)} connected nodes"
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -165,7 +172,7 @@ defmodule Aprsme.Cluster.LeaderElection do
|
|||
end
|
||||
|
||||
# Schedule next check
|
||||
_ = Process.send_after(self(), :check_leadership, @check_interval)
|
||||
_ = Process.send_after(self(), :check_leadership, check_interval())
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -161,15 +161,17 @@ defmodule Aprsme.Cluster.LeaderElectionTest do
|
|||
assert :global.whereis_name(@election_key) == :undefined
|
||||
end
|
||||
|
||||
@tag :slow
|
||||
test "periodic leadership check continues running" do
|
||||
Application.put_env(:aprsme, :election_check_interval_ms, 50)
|
||||
on_exit(fn -> Application.delete_env(:aprsme, :election_check_interval_ms) end)
|
||||
|
||||
{:ok, _pid} = LeaderElection.start_link([])
|
||||
|
||||
# Initial state - might not be leader yet
|
||||
_initial_leader = LeaderElection.leader?()
|
||||
|
||||
# Wait for periodic check
|
||||
Process.sleep(6000)
|
||||
# Wait for periodic check (50ms interval, plus buffer)
|
||||
Process.sleep(150)
|
||||
|
||||
# Should still be able to query leadership
|
||||
current_leader = LeaderElection.leader?()
|
||||
|
|
@ -208,12 +210,11 @@ defmodule Aprsme.Cluster.LeaderElectionTest do
|
|||
end
|
||||
|
||||
describe "stale registration cleanup" do
|
||||
@tag :slow
|
||||
test "cleans up registration when process dies" do
|
||||
# Register a dead process
|
||||
dead_pid = spawn(fn -> :ok end)
|
||||
# Ensure it's dead
|
||||
Process.sleep(50)
|
||||
Process.sleep(10)
|
||||
|
||||
# Force register it globally (simulating stale registration)
|
||||
:global.re_register_name(@election_key, dead_pid)
|
||||
|
|
@ -222,8 +223,8 @@ defmodule Aprsme.Cluster.LeaderElectionTest do
|
|||
Application.put_env(:aprsme, :cluster_enabled, false)
|
||||
{:ok, _pid} = LeaderElection.start_link([])
|
||||
|
||||
# Wait longer for cleanup and election to occur
|
||||
Process.sleep(500)
|
||||
# Wait for cleanup and election to occur
|
||||
Process.sleep(150)
|
||||
|
||||
# Should have taken over leadership
|
||||
assert LeaderElection.leader?() == true
|
||||
|
|
@ -236,16 +237,20 @@ defmodule Aprsme.Cluster.LeaderElectionTest do
|
|||
:ok
|
||||
end
|
||||
|
||||
@tag :slow
|
||||
test "waits for cluster formation when enabled" do
|
||||
Application.put_env(:aprsme, :election_max_cluster_wait_ms, 100)
|
||||
Application.put_env(:aprsme, :election_cluster_check_interval_ms, 50)
|
||||
|
||||
on_exit(fn ->
|
||||
Application.delete_env(:aprsme, :election_max_cluster_wait_ms)
|
||||
Application.delete_env(:aprsme, :election_cluster_check_interval_ms)
|
||||
end)
|
||||
|
||||
{:ok, _pid} = LeaderElection.start_link([])
|
||||
|
||||
# Immediately after start, might not be leader yet
|
||||
Process.sleep(100)
|
||||
|
||||
# In cluster mode with no other nodes, it will eventually become leader
|
||||
# but might take longer than non-clustered mode
|
||||
Process.sleep(3000)
|
||||
# after the (now shortened) max_cluster_wait timeout fires
|
||||
Process.sleep(250)
|
||||
|
||||
# Should eventually attempt election
|
||||
assert is_boolean(LeaderElection.leader?())
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ defmodule Mix.Tasks.Compile.UnusedTest do
|
|||
assert Unused.clean() == :ok
|
||||
end
|
||||
|
||||
@tag :slow
|
||||
test "runs against the project and returns either :ok or :error tuple" do
|
||||
ExUnit.CaptureIO.capture_io(fn ->
|
||||
result = Unused.run([])
|
||||
|
|
@ -37,7 +36,6 @@ defmodule Mix.Tasks.Compile.UnusedTest do
|
|||
end)
|
||||
end
|
||||
|
||||
@tag :slow
|
||||
test "accepts --severity warning, info, and unknown values" do
|
||||
for severity <- ["warning", "info", "garbage"] do
|
||||
ExUnit.CaptureIO.capture_io(fn ->
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ExUnit.start(
|
|||
max_cases: max_cases,
|
||||
timeout: 30_000,
|
||||
capture_log: true,
|
||||
exclude: [:slow, :integration]
|
||||
exclude: [:integration]
|
||||
)
|
||||
|
||||
Ecto.Adapters.SQL.Sandbox.mode(Aprsme.Repo, :manual)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue