diff --git a/config/test.exs b/config/test.exs index 9b7a9ca6..d58481ed 100644 --- a/config/test.exs +++ b/config/test.exs @@ -90,4 +90,6 @@ config :towerops, snmp_adapter: Towerops.Snmp.SnmpMock, sql_sandbox: true, # Disable rate limiting in tests to avoid blocking concurrent test requests - rate_limiting_enabled: false + rate_limiting_enabled: false, + # Reduce debounce delay in tests for faster test execution (50ms vs 500ms in prod) + agent_channel_debounce_ms: 50 diff --git a/lib/towerops_web/channels/agent_channel.ex b/lib/towerops_web/channels/agent_channel.ex index 92150f83..700763af 100644 --- a/lib/towerops_web/channels/agent_channel.ex +++ b/lib/towerops_web/channels/agent_channel.ex @@ -236,7 +236,7 @@ defmodule ToweropsWeb.AgentChannel do end # Handle PubSub broadcast when device assignments change. - # Debounces rapid changes — cancels any pending refresh and schedules a new one in 500ms. + # Debounces rapid changes — cancels any pending refresh and schedules a new one. def handle_info({:assignments_changed, event}, socket) do Logger.info("Agent assignments changed, scheduling job refresh", agent_token_id: socket.assigns.agent_token_id, @@ -249,8 +249,9 @@ defmodule ToweropsWeb.AgentChannel do Process.cancel_timer(timer) end - # Schedule new refresh in 500ms - timer = Process.send_after(self(), :send_jobs, 500) + # Schedule new refresh after debounce delay (configurable, defaults to 500ms in prod, 50ms in test) + debounce_ms = Application.get_env(:towerops, :agent_channel_debounce_ms, 500) + timer = Process.send_after(self(), :send_jobs, debounce_ms) {:noreply, assign(socket, :job_refresh_timer, timer)} end diff --git a/test/towerops_web/channels/agent_channel_test.exs b/test/towerops_web/channels/agent_channel_test.exs index 7823be69..8afd498f 100644 --- a/test/towerops_web/channels/agent_channel_test.exs +++ b/test/towerops_web/channels/agent_channel_test.exs @@ -491,8 +491,8 @@ defmodule ToweropsWeb.AgentChannelTest do test "triggers debounced job refresh", %{socket: socket} do send(socket.channel_pid, {:assignments_changed, :assigned}) - # Jobs push should come after 500ms debounce - assert_push "jobs", %{binary: _jobs_binary}, 700 + # Jobs push should come after debounce delay (50ms in test) + assert_push "jobs", %{binary: _jobs_binary}, 150 end test "debounces rapid assignment changes", %{socket: socket} do @@ -501,9 +501,9 @@ defmodule ToweropsWeb.AgentChannelTest do send(socket.channel_pid, {:assignments_changed, :unassigned}) send(socket.channel_pid, {:assignments_changed, :assigned}) - # Should only get one push (debounced) - reduced timeout for faster tests - assert_push "jobs", %{binary: _}, 700 - refute_push "jobs", %{}, 100 + # Should only get one push (debounced) - 50ms debounce in test + assert_push "jobs", %{binary: _}, 150 + refute_push "jobs", %{}, 50 end end @@ -1283,7 +1283,7 @@ defmodule ToweropsWeb.AgentChannelTest do ) # Should receive jobs message with 2 devices - assert_push "jobs", %{binary: initial_jobs_binary}, 800 + assert_push "jobs", %{binary: initial_jobs_binary}, 150 {:ok, decoded_initial} = Base.decode64(initial_jobs_binary) initial_job_list = AgentJobList.decode(decoded_initial) initial_device_ids = initial_job_list.jobs |> Enum.map(& &1.device_id) |> Enum.uniq() @@ -1295,7 +1295,7 @@ defmodule ToweropsWeb.AgentChannelTest do {:ok, _deleted} = Towerops.Devices.delete_device(device) # Should receive updated jobs message with only 1 device - assert_push "jobs", %{binary: updated_jobs_binary}, 800 + assert_push "jobs", %{binary: updated_jobs_binary}, 150 {:ok, decoded_updated} = Base.decode64(updated_jobs_binary) updated_job_list = AgentJobList.decode(decoded_updated) updated_device_ids = updated_job_list.jobs |> Enum.map(& &1.device_id) |> Enum.uniq() @@ -1311,7 +1311,7 @@ defmodule ToweropsWeb.AgentChannelTest do {:ok, _deleted} = Towerops.Devices.delete_device(device) # Wait for jobs refresh - assert_push "jobs", _, 800 + assert_push "jobs", _, 150 # Try to send a result for the deleted device result = %SnmpResult{ @@ -1345,11 +1345,11 @@ defmodule ToweropsWeb.AgentChannelTest do Process.sleep(5) end - # Should only receive ONE jobs message (debounced) - assert_push "jobs", %{binary: _jobs_binary}, 1000 + # Should only receive ONE jobs message (debounced) - 50ms debounce in test + assert_push "jobs", %{binary: _jobs_binary}, 150 # Should NOT receive additional jobs messages - refute_push "jobs", _, 200 + refute_push "jobs", _, 50 end end end