defmodule Towerops.Integration.SnmpIntegrationTest do @moduledoc """ Integration tests for SNMP functionality against real devices. These tests are excluded from the main test suite by default. To run them: mix test --only integration Requirements: - Network access to test devices - SNMP-enabled devices (configure IP/community below) """ use ExUnit.Case, async: false import Towerops.AccountsFixtures alias Towerops.Snmp.Client alias Towerops.Snmp.Poller alias Towerops.Snmp.Profiles.Base alias Towerops.Workers.DeviceMonitorWorker @moduletag :real_device setup do # Skip these tests - they require real SNMP devices # To run: mix test --include real_device :ok end # Configure your test device here @test_device_opts [ ip: "10.0.19.254", community: "kdyyJrT0Mm", version: "2c", port: 161, timeout: 5000 ] describe "SNMP Client against real device" do test "can perform GET operation" do case Client.get(@test_device_opts, "1.3.6.1.2.1.1.3.0") do {:ok, uptime} -> assert is_integer(uptime) {:error, reason} -> flunk("SNMP GET failed: #{inspect(reason)}") end end test "can perform WALK operation" do case Client.walk(@test_device_opts, "1.3.6.1.2.1.2.2.1.1") do {:ok, results} -> assert map_size(results) > 0 {:error, reason} -> flunk("SNMP WALK failed: #{inspect(reason)}") end end test "can test connection" do assert {:ok, _message} = Client.test_connection(@test_device_opts) end end describe "SNMP Poller against real device" do test "can check device reachability" do case Poller.check_device(@test_device_opts) do {:ok, response_time} -> assert is_float(response_time) assert response_time > 0 {:error, reason} -> flunk("Poller check failed: #{inspect(reason)}") end end end describe "Discovery against real device" do @tag :full_discovery test "can discover device using Base profile" do # Discover system info using Base profile {:ok, system_info} = Base.discover_system_info(@test_device_opts) assert byte_size(system_info.sys_descr) > 0 assert byte_size(system_info.sys_name) > 0 # Discover interfaces {:ok, interfaces} = Base.discover_interfaces(@test_device_opts) refute Enum.empty?(interfaces) # Discover sensors (may be empty if device doesn't support ENTITY-SENSOR-MIB) {:ok, _sensors} = Base.discover_sensors(@test_device_opts) # Identify device device_info = Base.identify_device(system_info) assert byte_size(device_info.manufacturer) > 0 assert byte_size(device_info.model) > 0 end end describe "Device Monitor with SNMP" do test "creates SNMP-specific alert messages when device goes down" do # This test makes real SNMP calls to an unreachable IP to verify timeout handling 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: "SNMP Router", ip_address: "192.0.2.1", site_id: site.id, organization_id: organization.id, snmp_enabled: true, snmp_version: "2c", snmp_community: "public", snmp_port: 161, monitoring_enabled: true }) # Set to up first so status change will trigger {:ok, device} = Towerops.Devices.update_device_status(device, :up) # Trigger check - will timeout trying to reach 192.0.2.1 DeviceMonitorWorker.perform(%Oban.Job{args: %{"device_id" => device.id}}) alerts = Towerops.Alerts.list_devices_alerts(device.id) refute Enum.empty?(alerts) alert = hd(alerts) assert alert.alert_type == :device_down assert String.contains?(alert.message, "SNMP") end end end