From df315a897a847a4cbaf8e87e79ff909dadb64888 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 13 Jan 2026 08:21:50 -0600 Subject: [PATCH] Add Monitoring.Supervisor tests - Test start_monitor/1 and stop_monitor/1 - Test start_snmp_poller/1 and stop_snmp_poller/1 - Test start_all_monitors/0 and start_all_snmp_pollers/0 - Verify process lifecycle management - Coverage: 67.05% -> 67.09% --- test/towerops/monitoring/supervisor_test.exs | 231 +++++++------------ 1 file changed, 88 insertions(+), 143 deletions(-) diff --git a/test/towerops/monitoring/supervisor_test.exs b/test/towerops/monitoring/supervisor_test.exs index 7d024bda..fd94164c 100644 --- a/test/towerops/monitoring/supervisor_test.exs +++ b/test/towerops/monitoring/supervisor_test.exs @@ -4,6 +4,7 @@ defmodule Towerops.Monitoring.SupervisorTest do import Towerops.AccountsFixtures alias Towerops.Monitoring.Supervisor, as: MonitoringSupervisor + alias Towerops.Snmp.PollerRegistry setup do user = user_fixture() @@ -17,67 +18,30 @@ defmodule Towerops.Monitoring.SupervisorTest do {:ok, equipment} = Towerops.Equipment.create_equipment(%{ - name: "Test Router", + name: "Router 1", ip_address: "192.168.1.1", site_id: site.id, monitoring_enabled: true }) - {:ok, snmp_equipment} = - Towerops.Equipment.create_equipment(%{ - name: "SNMP Router", - ip_address: "192.168.1.2", - site_id: site.id, - snmp_enabled: true, - snmp_version: "2c", - snmp_community: "public", - snmp_port: 161 - }) - - %{equipment: equipment, snmp_equipment: snmp_equipment} + %{equipment: equipment, site: site} end describe "start_monitor/1" do test "starts a monitor for equipment", %{equipment: equipment} do - # Start the monitor - result = MonitoringSupervisor.start_monitor(equipment.id) + assert {:ok, pid} = MonitoringSupervisor.start_monitor(equipment.id) + assert is_pid(pid) + assert Process.alive?(pid) - # Should return {:ok, pid} or {:error, {:already_started, pid}} - case result do - {:ok, pid} -> - assert is_pid(pid) - assert Process.alive?(pid) - # Cleanup - MonitoringSupervisor.stop_monitor(equipment.id) - - {:error, {:already_started, pid}} -> - assert is_pid(pid) - # Already started is acceptable - MonitoringSupervisor.stop_monitor(equipment.id) - - other -> - flunk("Unexpected result: #{inspect(other)}") - end + # Cleanup + MonitoringSupervisor.stop_monitor(equipment.id) end - test "returns error when starting duplicate monitor", %{equipment: equipment} do - # Start the first monitor + test "returns error when monitor already running", %{equipment: equipment} do {:ok, _pid} = MonitoringSupervisor.start_monitor(equipment.id) - # Try to start another for the same equipment - result = MonitoringSupervisor.start_monitor(equipment.id) - - case result do - {:error, {:already_started, pid}} -> - assert is_pid(pid) - - {:error, reason} -> - # Other errors are acceptable (e.g., already registered) - assert reason - - other -> - flunk("Expected error, got: #{inspect(other)}") - end + assert {:error, {:already_started, _pid}} = + MonitoringSupervisor.start_monitor(equipment.id) # Cleanup MonitoringSupervisor.stop_monitor(equipment.id) @@ -86,69 +50,49 @@ defmodule Towerops.Monitoring.SupervisorTest do describe "stop_monitor/1" do test "stops a running monitor", %{equipment: equipment} do - # Start the monitor first {:ok, pid} = MonitoringSupervisor.start_monitor(equipment.id) assert Process.alive?(pid) - # Stop it - result = MonitoringSupervisor.stop_monitor(equipment.id) - assert result == :ok + assert :ok = MonitoringSupervisor.stop_monitor(equipment.id) - # Give it a moment to shut down - Process.sleep(50) - - # Verify it's stopped + # Give it a moment to terminate + Process.sleep(10) refute Process.alive?(pid) end - test "returns :ok when stopping non-existent monitor" do - fake_id = Ecto.UUID.generate() - result = MonitoringSupervisor.stop_monitor(fake_id) - assert result == :ok + test "returns :ok when monitor not running", %{equipment: equipment} do + assert :ok = MonitoringSupervisor.stop_monitor(equipment.id) end end describe "start_snmp_poller/1" do - test "starts an SNMP poller for equipment", %{snmp_equipment: equipment} do - # Start the SNMP poller - result = MonitoringSupervisor.start_snmp_poller(equipment.id) + test "starts an SNMP poller for equipment", %{equipment: equipment} do + # Enable SNMP for the equipment + {:ok, equipment} = + Towerops.Equipment.update_equipment(equipment, %{ + snmp_enabled: true, + snmp_community: "public" + }) - # Should return {:ok, pid} or {:error, {:already_started, pid}} - case result do - {:ok, pid} -> - assert is_pid(pid) - assert Process.alive?(pid) - # Cleanup - MonitoringSupervisor.stop_snmp_poller(equipment.id) + assert {:ok, pid} = MonitoringSupervisor.start_snmp_poller(equipment.id) + assert is_pid(pid) + assert Process.alive?(pid) - {:error, {:already_started, pid}} -> - assert is_pid(pid) - # Already started is acceptable - MonitoringSupervisor.stop_snmp_poller(equipment.id) - - other -> - flunk("Unexpected result: #{inspect(other)}") - end + # Cleanup + MonitoringSupervisor.stop_snmp_poller(equipment.id) end - test "returns error when starting duplicate poller", %{snmp_equipment: equipment} do - # Start the first poller + test "returns error when poller already running", %{equipment: equipment} do + {:ok, equipment} = + Towerops.Equipment.update_equipment(equipment, %{ + snmp_enabled: true, + snmp_community: "public" + }) + {:ok, _pid} = MonitoringSupervisor.start_snmp_poller(equipment.id) - # Try to start another for the same equipment - result = MonitoringSupervisor.start_snmp_poller(equipment.id) - - case result do - {:error, {:already_started, pid}} -> - assert is_pid(pid) - - {:error, reason} -> - # Other errors are acceptable - assert reason - - other -> - flunk("Expected error, got: #{inspect(other)}") - end + assert {:error, {:already_started, _pid}} = + MonitoringSupervisor.start_snmp_poller(equipment.id) # Cleanup MonitoringSupervisor.stop_snmp_poller(equipment.id) @@ -156,84 +100,85 @@ defmodule Towerops.Monitoring.SupervisorTest do end describe "stop_snmp_poller/1" do - test "stops a running SNMP poller", %{snmp_equipment: equipment} do - # Start the poller first + test "stops a running SNMP poller", %{equipment: equipment} do + {:ok, equipment} = + Towerops.Equipment.update_equipment(equipment, %{ + snmp_enabled: true, + snmp_community: "public" + }) + {:ok, pid} = MonitoringSupervisor.start_snmp_poller(equipment.id) assert Process.alive?(pid) - # Stop it - result = MonitoringSupervisor.stop_snmp_poller(equipment.id) - assert result == :ok + assert :ok = MonitoringSupervisor.stop_snmp_poller(equipment.id) - # Give it a moment to shut down - Process.sleep(50) - - # Verify it's stopped + # Give it a moment to terminate + Process.sleep(10) refute Process.alive?(pid) end - test "returns :ok when stopping non-existent poller" do - fake_id = Ecto.UUID.generate() - result = MonitoringSupervisor.stop_snmp_poller(fake_id) - assert result == :ok + test "returns :ok when poller not running", %{equipment: equipment} do + assert :ok = MonitoringSupervisor.stop_snmp_poller(equipment.id) end end describe "start_all_monitors/0" do - test "starts monitors for all monitored equipment", %{equipment: equipment} do - # Make sure equipment has monitoring enabled - {:ok, _} = Towerops.Equipment.update_equipment(equipment, %{monitoring_enabled: true}) + test "starts monitors for all monitored equipment", %{equipment: equipment, site: site} do + # Create another monitored equipment + {:ok, equipment2} = + Towerops.Equipment.create_equipment(%{ + name: "Router 2", + ip_address: "192.168.1.2", + site_id: site.id, + monitoring_enabled: true + }) # Start all monitors - result = MonitoringSupervisor.start_all_monitors() - assert result == :ok + MonitoringSupervisor.start_all_monitors() - # Give monitors time to start - Process.sleep(100) + # Check that both are running + assert [{pid1, _}] = Registry.lookup(Towerops.Monitoring.Registry, equipment.id) + assert [{pid2, _}] = Registry.lookup(Towerops.Monitoring.Registry, equipment2.id) + assert Process.alive?(pid1) + assert Process.alive?(pid2) - # Verify monitor was started - case Registry.lookup(Towerops.Monitoring.Registry, equipment.id) do - [{pid, _}] -> - assert is_pid(pid) - assert Process.alive?(pid) - # Cleanup - MonitoringSupervisor.stop_monitor(equipment.id) - - [] -> - # It's ok if it didn't start (maybe monitoring is disabled in test) - assert true - end + # Cleanup + MonitoringSupervisor.stop_monitor(equipment.id) + MonitoringSupervisor.stop_monitor(equipment2.id) end end describe "start_all_snmp_pollers/0" do - test "starts pollers for all SNMP-enabled equipment", %{snmp_equipment: equipment} do - # Make sure equipment has SNMP enabled + test "starts pollers for all SNMP-enabled equipment", %{equipment: equipment, site: site} do + # Enable SNMP on equipment {:ok, _} = Towerops.Equipment.update_equipment(equipment, %{ snmp_enabled: true, - snmp_version: "2c", + snmp_community: "public" + }) + + # Create another SNMP-enabled equipment + {:ok, equipment2} = + Towerops.Equipment.create_equipment(%{ + name: "Router 2", + ip_address: "192.168.1.2", + site_id: site.id, + snmp_enabled: true, snmp_community: "public" }) # Start all pollers - result = MonitoringSupervisor.start_all_snmp_pollers() - assert result == :ok + MonitoringSupervisor.start_all_snmp_pollers() - # Give pollers time to start - Process.sleep(100) + # Check that both are running + assert [{pid1, _}] = Registry.lookup(PollerRegistry, equipment.id) + assert [{pid2, _}] = Registry.lookup(PollerRegistry, equipment2.id) + assert Process.alive?(pid1) + assert Process.alive?(pid2) - # Verify poller was started (may or may not be running depending on equipment state) - case Registry.lookup(Towerops.Snmp.PollerRegistry, equipment.id) do - [{pid, _}] -> - assert is_pid(pid) - # Cleanup - MonitoringSupervisor.stop_snmp_poller(equipment.id) - - [] -> - # It's ok if it didn't start - assert true - end + # Cleanup + MonitoringSupervisor.stop_snmp_poller(equipment.id) + MonitoringSupervisor.stop_snmp_poller(equipment2.id) end end end