towerops/test/towerops/workers/monitor_worker_test.exs
Graham McIntire a2466722b7
Add comprehensive tests for background workers
- DiscoveryWorker: Tests for SNMP device discovery
- MonitorWorker: Tests for ICMP ping monitoring checks
- PollWorker: Tests for SNMP polling of sensors, interfaces, and neighbors

These tests use fixtures and Mox for SNMP mocking to achieve good coverage
of the worker modules without requiring real SNMP devices.

Note: Some function names need correction based on actual Monitoring/Snmp context APIs.
2026-01-20 11:58:47 -06:00

141 lines
4.1 KiB
Elixir

defmodule Towerops.Workers.MonitorWorkerTest do
use Towerops.DataCase, async: true
import Towerops.AccountsFixtures
alias Towerops.Monitoring
alias Towerops.Workers.MonitorWorker
setup do
user = user_fixture()
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
{:ok, site} =
Towerops.Sites.create_site(%{
name: "Test Site",
organization_id: organization.id
})
{:ok, device} =
Towerops.Devices.create_device(%{
name: "Test Device",
# Use localhost for reliable testing
ip_address: "127.0.0.1",
monitoring_enabled: true,
site_id: site.id
})
{:ok, device: device, org: organization}
end
describe "perform/1" do
test "creates a check when monitoring is enabled", %{device: device} do
# Call perform - it will ping localhost
result = MonitorWorker.perform(device.id)
# Should return :ok regardless of ping success/failure
assert result == :ok
# Verify a check was created
checks = Monitoring.list_checks_for_device(device.id)
assert length(checks) == 1
check = hd(checks)
assert check.device_id == device.id
assert check.status in [:success, :failure]
assert check.checked_at
# If ping succeeded, should have response time
if check.status == :success do
assert is_float(check.response_time_ms)
assert check.response_time_ms >= 0
else
assert check.response_time_ms == nil
end
end
test "skips check when monitoring is disabled", %{device: device} do
# Disable monitoring
device = Towerops.Devices.update_device!(device, %{monitoring_enabled: false})
assert :ok = MonitorWorker.perform(device.id)
# Verify no check was created
checks = Monitoring.list_checks_for_device(device.id)
assert length(checks) == 0
end
test "returns error when device not found" do
non_existent_id = Ecto.UUID.generate()
assert {:error, :device_not_found} = MonitorWorker.perform(non_existent_id)
end
test "broadcasts update after check", %{device: device} do
# Subscribe to device topic
Phoenix.PubSub.subscribe(Towerops.PubSub, "device:#{device.id}")
MonitorWorker.perform(device.id)
# Verify broadcast was sent
assert_receive {:monitoring_check_updated, device_id}, 1000
assert device_id == device.id
end
test "creates failed check for unreachable host" do
user = user_fixture()
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
{:ok, site} =
Towerops.Sites.create_site(%{
name: "Test Site",
organization_id: organization.id
})
# Use a non-routable IP (documentation range)
{:ok, device} =
Towerops.Devices.create_device(%{
name: "Unreachable Device",
ip_address: "192.0.2.1",
monitoring_enabled: true,
site_id: site.id
})
assert :ok = MonitorWorker.perform(device.id)
# Verify check was created as failure
checks = Monitoring.list_checks_for_device(device.id)
assert length(checks) == 1
check = hd(checks)
assert check.status == :failure
assert check.response_time_ms == nil
end
test "logs appropriate messages", %{device: device} do
import ExUnit.CaptureLog
log =
capture_log([level: :debug], fn ->
MonitorWorker.perform(device.id)
end)
assert log =~ "Starting monitoring check for device #{device.id}"
# Will either log "is up" or "is down" depending on ping result
assert log =~ device.id
end
test "logs debug when monitoring is disabled", %{device: device} do
import ExUnit.CaptureLog
device = Towerops.Devices.update_device!(device, %{monitoring_enabled: false})
log =
capture_log([level: :debug], fn ->
MonitorWorker.perform(device.id)
end)
assert log =~ "Device #{device.id} does not have monitoring enabled"
end
end
end