towerops/test/towerops/workers/monitor_worker_test.exs
Graham McIntire fcc1fbbe73
Refactor MonitorWorker to use ping adapter and eliminate real network traffic from tests
Changes:
- Updated MonitorWorker to use configured ping_module adapter instead of System.cmd
- Removed direct ping command execution and regex parsing
- Simplified ping_device/1 to use adapter.ping/2 (mockable in tests)
- Added PingMock expectations to all MonitorWorker tests
- Removed @tag :integration from unreachable host test (now mocked)
- All ping calls now use mocked responses in tests

Benefits:
- MonitorWorker tests now run in 0.2s instead of 5+ seconds
- No real ICMP network traffic during test runs
- Tests are deterministic and don't depend on network conditions
- Follows same adapter pattern as SNMP (testable, configurable)

All 1041 tests passing with no real network operations.
2026-01-20 12:29:12 -06:00

154 lines
4.3 KiB
Elixir

defmodule Towerops.Workers.MonitorWorkerTest do
use Towerops.DataCase, async: true
import Mox
import Towerops.AccountsFixtures
alias Towerops.Monitoring
alias Towerops.Monitoring.PingMock
alias Towerops.Workers.MonitorWorker
setup :verify_on_exit!
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
# Mock successful ping
expect(PingMock, :ping, fn _ip, _timeout ->
{:ok, 10.5}
end)
result = MonitorWorker.perform(device.id)
# Should return :ok
assert result == :ok
# Verify a successful check was created
checks = Monitoring.list_devices_checks(device.id, 10)
assert length(checks) == 1
check = hd(checks)
assert check.device_id == device.id
assert check.status == :success
assert check.checked_at
assert check.response_time_ms == 10.5
end
test "skips check when monitoring is disabled", %{device: device} do
# Disable monitoring
{:ok, device} = Towerops.Devices.update_device(device, %{monitoring_enabled: false})
assert :ok = MonitorWorker.perform(device.id)
# Verify no check was created
checks = Monitoring.list_devices_checks(device.id, 10)
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
# Mock successful ping
expect(PingMock, :ping, fn _ip, _timeout ->
{:ok, 10.5}
end)
# 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
})
{:ok, device} =
Towerops.Devices.create_device(%{
name: "Unreachable Device",
ip_address: "192.0.2.1",
monitoring_enabled: true,
site_id: site.id
})
# Mock failed ping
expect(PingMock, :ping, fn _ip, _timeout ->
{:error, :timeout}
end)
assert :ok = MonitorWorker.perform(device.id)
# Verify check was created as failure
checks = Monitoring.list_devices_checks(device.id, 10)
assert length(checks) == 1
check = hd(checks)
assert check.status == :failure
assert check.response_time_ms == nil
end
test "successfully completes monitoring check", %{device: device} do
# Mock successful ping
expect(PingMock, :ping, fn _ip, _timeout ->
{:ok, 15.0}
end)
assert :ok = MonitorWorker.perform(device.id)
# Verify a successful check was created
checks = Monitoring.list_devices_checks(device.id, 10)
assert length(checks) >= 1
check = hd(checks)
assert check.device_id == device.id
assert check.status == :success
assert check.checked_at
assert check.response_time_ms == 15.0
end
test "correctly skips monitoring when disabled", %{device: device} do
{:ok, device} = Towerops.Devices.update_device(device, %{monitoring_enabled: false})
assert :ok = MonitorWorker.perform(device.id)
# Verify no check was created
checks = Monitoring.list_devices_checks(device.id, 10)
assert length(checks) == 0
end
end
end