test: Profiles.Base storage/printer/processor/Cambium branches
This commit is contained in:
parent
0f87ec5b89
commit
19d9ef9e52
1 changed files with 277 additions and 0 deletions
277
test/towerops/snmp/profiles/base_extra_test.exs
Normal file
277
test/towerops/snmp/profiles/base_extra_test.exs
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
defmodule Towerops.Snmp.Profiles.BaseExtraTest do
|
||||
@moduledoc """
|
||||
Additional `Towerops.Snmp.Profiles.Base` coverage targeting branches that
|
||||
remained uncovered after the existing test files.
|
||||
|
||||
Covered here:
|
||||
* `discover_ipv6_addresses/1` via the modern RFC 4293 ipAddressTable
|
||||
(the prior tests only hit the IPV6-MIB fallback)
|
||||
* `discover_transceivers/1` empty-result and walk-failure branches
|
||||
* `discover_printer_supplies/1` empty / supplies parsing including
|
||||
`parse_supply_capacity` for binary values
|
||||
* `discover_processors/1` UCD-SNMP-MIB three-value branch
|
||||
* `discover_storage/1` happy path covering disk types
|
||||
* `discover_physical_entities/1` for entity_class string mapping
|
||||
* `identify_device/1` Cambium ePMP and other Ubiquiti antenna branches
|
||||
"""
|
||||
|
||||
use Towerops.DataCase, async: true
|
||||
|
||||
alias Towerops.Snmp.Adapters.Replay
|
||||
alias Towerops.Snmp.Profiles.Base
|
||||
|
||||
describe "discover_ipv6_addresses/1 via ipAddressTable (RFC 4293)" do
|
||||
test "ipAddressTable with only IPv4 entries returns empty list (then falls through to IPV6-MIB)" do
|
||||
# Modern table has IPv4 addresses (type 1), but discover_ipv6_addresses
|
||||
# should return [] from the modern path, then fall through to IPV6-MIB
|
||||
# which is also empty -> empty list.
|
||||
ipv4_suffix = "1.4.10.0.0.1"
|
||||
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
("1.3.6.1.2.1.4.34.1.3." <> ipv4_suffix) => "1"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, []} = Base.discover_ipv6_addresses(client_opts)
|
||||
end
|
||||
end
|
||||
|
||||
describe "discover_transceivers/1 empty paths" do
|
||||
test "returns empty list when no entity descriptions exist" do
|
||||
assert {:ok, []} = Base.discover_transceivers(adapter: Replay, oid_map: %{})
|
||||
end
|
||||
|
||||
test "filters out entities that lack transceiver keywords in description" do
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
# entPhysicalDescr that doesn't match transceiver keywords
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.1" => "Power Module",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.1" => "9"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, []} = Base.discover_transceivers(client_opts)
|
||||
end
|
||||
end
|
||||
|
||||
describe "discover_printer_supplies/1" do
|
||||
test "returns empty list when no supplies present" do
|
||||
assert {:ok, []} = Base.discover_printer_supplies(adapter: Replay, oid_map: %{})
|
||||
end
|
||||
|
||||
test "discovers printer supplies with all attributes including capacity parsing" do
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
# prtMarkerSuppliesType: 3 = toner, 10 = drum
|
||||
"1.3.6.1.2.1.43.11.1.1.3.1.1" => "3",
|
||||
"1.3.6.1.2.1.43.11.1.1.3.1.2" => "10",
|
||||
# prtMarkerSuppliesDescription
|
||||
"1.3.6.1.2.1.43.11.1.1.4.1.1" => "Black Toner Cartridge",
|
||||
"1.3.6.1.2.1.43.11.1.1.4.1.2" => "Imaging Drum",
|
||||
# prtMarkerSuppliesUnit: 19=percent, 18=items
|
||||
"1.3.6.1.2.1.43.11.1.1.7.1.1" => "19",
|
||||
"1.3.6.1.2.1.43.11.1.1.7.1.2" => "18",
|
||||
# prtMarkerSuppliesMaxCapacity (string -> tests parse_supply_capacity binary branch)
|
||||
"1.3.6.1.2.1.43.11.1.1.8.1.1" => "100",
|
||||
"1.3.6.1.2.1.43.11.1.1.8.1.2" => "30000",
|
||||
# prtMarkerSuppliesLevel
|
||||
"1.3.6.1.2.1.43.11.1.1.9.1.1" => "75",
|
||||
"1.3.6.1.2.1.43.11.1.1.9.1.2" => "12500",
|
||||
# prtMarkerColorantValue
|
||||
"1.3.6.1.2.1.43.11.1.1.12.1.1" => "black",
|
||||
"1.3.6.1.2.1.43.11.1.1.12.1.2" => "n/a"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, supplies} = Base.discover_printer_supplies(client_opts)
|
||||
assert length(supplies) == 2
|
||||
|
||||
toner = Enum.find(supplies, &(&1.supply_index == "1"))
|
||||
assert toner.supply_type == "toner"
|
||||
assert toner.supply_description == "Black Toner Cartridge"
|
||||
assert toner.supply_unit == "percent"
|
||||
assert toner.max_capacity == 100
|
||||
assert toner.current_level == 75
|
||||
assert toner.color_name == "black"
|
||||
|
||||
drum = Enum.find(supplies, &(&1.supply_index == "2"))
|
||||
assert drum.supply_type == "drum"
|
||||
assert drum.max_capacity == 30_000
|
||||
assert drum.current_level == 12_500
|
||||
end
|
||||
|
||||
test "handles unknown supply type code by mapping to 'unknown'" do
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
# Unknown supply type code 999
|
||||
"1.3.6.1.2.1.43.11.1.1.3.1.1" => "999"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, [supply]} = Base.discover_printer_supplies(client_opts)
|
||||
assert supply.supply_type == "unknown"
|
||||
end
|
||||
end
|
||||
|
||||
describe "discover_processors/1 UCD-SNMP path" do
|
||||
test "synthesizes a UCD CPU when other MIBs are silent" do
|
||||
# This path exercises discover_ucd_cpu when both HR and Cisco return [].
|
||||
# The Replay adapter with empty oid_map returns nil for UCD OIDs which
|
||||
# parse as 0; we still get a synthetic processor.
|
||||
assert {:ok, processors} = Base.discover_processors(adapter: Replay, oid_map: %{})
|
||||
assert length(processors) == 1
|
||||
[cpu] = processors
|
||||
assert cpu.processor_type == "ucd_cpu"
|
||||
assert cpu.processor_index == "ucd_0"
|
||||
assert is_map(cpu.metadata)
|
||||
end
|
||||
end
|
||||
|
||||
describe "discover_storage/1 (Replay)" do
|
||||
test "discovers fixed disks while ignoring RAM/swap entries" do
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
# hrStorageType: RAM (1.3.6.1.2.1.25.2.1.2) - filtered out
|
||||
"1.3.6.1.2.1.25.2.3.1.2.1" => "1.3.6.1.2.1.25.2.1.2",
|
||||
# fixed disk (1.3.6.1.2.1.25.2.1.4)
|
||||
"1.3.6.1.2.1.25.2.3.1.2.2" => "1.3.6.1.2.1.25.2.1.4",
|
||||
# flash memory (1.3.6.1.2.1.25.2.1.9)
|
||||
"1.3.6.1.2.1.25.2.3.1.2.3" => "1.3.6.1.2.1.25.2.1.9",
|
||||
# Descriptions
|
||||
"1.3.6.1.2.1.25.2.3.1.3.2" => "/var",
|
||||
"1.3.6.1.2.1.25.2.3.1.3.3" => "/boot",
|
||||
# Allocation units
|
||||
"1.3.6.1.2.1.25.2.3.1.4.2" => "4096",
|
||||
"1.3.6.1.2.1.25.2.3.1.4.3" => "1024",
|
||||
# Sizes (in units)
|
||||
"1.3.6.1.2.1.25.2.3.1.5.2" => "1000000",
|
||||
"1.3.6.1.2.1.25.2.3.1.5.3" => "100000",
|
||||
# Used (in units)
|
||||
"1.3.6.1.2.1.25.2.3.1.6.2" => "500000",
|
||||
"1.3.6.1.2.1.25.2.3.1.6.3" => "75000"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, storage} = Base.discover_storage(client_opts)
|
||||
assert length(storage) == 2
|
||||
|
||||
fixed = Enum.find(storage, &(&1.storage_type == "fixed_disk"))
|
||||
assert fixed.description == "/var"
|
||||
assert fixed.total_bytes == 1_000_000 * 4096
|
||||
|
||||
flash = Enum.find(storage, &(&1.storage_type == "flash_memory"))
|
||||
assert flash.description == "/boot"
|
||||
assert flash.used_bytes == 75_000 * 1024
|
||||
end
|
||||
|
||||
test "returns empty list when storage walk has no entries" do
|
||||
assert {:ok, []} = Base.discover_storage(adapter: Replay, oid_map: %{})
|
||||
end
|
||||
end
|
||||
|
||||
describe "discover_physical_entities/1 entity class mapping" do
|
||||
test "discovers entities with class strings mapped from class codes" do
|
||||
client_opts = [
|
||||
adapter: Replay,
|
||||
oid_map: %{
|
||||
# entPhysicalDescr
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.1" => "Chassis",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.2" => "PSU",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.3" => "Fan Module",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.4" => "Sensor X",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.5" => "Linecard",
|
||||
"1.3.6.1.2.1.47.1.1.1.1.2.6" => "Port 1",
|
||||
# entPhysicalClass
|
||||
# chassis
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.1" => "3",
|
||||
# power
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.2" => "6",
|
||||
# fan
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.3" => "7",
|
||||
# sensor
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.4" => "8",
|
||||
# module
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.5" => "9",
|
||||
# port
|
||||
"1.3.6.1.2.1.47.1.1.1.1.5.6" => "10"
|
||||
}
|
||||
]
|
||||
|
||||
assert {:ok, entities} = Base.discover_physical_entities(client_opts)
|
||||
assert length(entities) == 6
|
||||
|
||||
classes = entities |> Enum.map(& &1.entity_class) |> Enum.sort()
|
||||
assert "chassis" in classes
|
||||
assert "power" in classes
|
||||
assert "fan" in classes
|
||||
assert "sensor" in classes
|
||||
assert "module" in classes
|
||||
assert "port" in classes
|
||||
end
|
||||
|
||||
test "returns empty list when entity walk has no descriptions" do
|
||||
assert {:ok, []} = Base.discover_physical_entities(adapter: Replay, oid_map: %{})
|
||||
end
|
||||
end
|
||||
|
||||
describe "identify_device/1 additional vendor patterns" do
|
||||
test "identifies Cambium ePMP with model number from sysDescr" do
|
||||
info = %{sys_descr: "Cambium ePMP 3000 AP", sys_object_id: ""}
|
||||
device = Base.identify_device(info)
|
||||
assert device.manufacturer == "Cambium Networks"
|
||||
assert device.model == "ePMP 3000"
|
||||
end
|
||||
|
||||
test "identifies bare Cambium ePMP without model number" do
|
||||
info = %{sys_descr: "Cambium ePMP wireless", sys_object_id: ""}
|
||||
device = Base.identify_device(info)
|
||||
# The regex matches "ePMP" followed by no digits and the
|
||||
# extract_model_with_number helper returns "ePMP" only
|
||||
assert device.manufacturer == "Cambium Networks"
|
||||
assert device.model == "ePMP"
|
||||
end
|
||||
|
||||
test "identifies Cambium PMP from sysDescr with model number" do
|
||||
info = %{sys_descr: "Cambium PMP 450 SM", sys_object_id: ""}
|
||||
device = Base.identify_device(info)
|
||||
assert device.manufacturer == "Cambium Networks"
|
||||
assert device.model == "PMP 450"
|
||||
end
|
||||
|
||||
test "Ubiquiti AF-prefix antenna model extraction" do
|
||||
info = %{sys_descr: "Ubiquiti AF-5XHD wireless", sys_object_id: ""}
|
||||
device = Base.identify_device(info)
|
||||
assert device.manufacturer == "Ubiquiti"
|
||||
assert String.starts_with?(device.model, "AF")
|
||||
end
|
||||
|
||||
test "Cambium with no specific descr falls back to product line via sysObjectID (ePMP)" do
|
||||
info = %{
|
||||
sys_descr: "Generic device",
|
||||
sys_object_id: "1.3.6.1.4.1.17713.21.5.1"
|
||||
}
|
||||
|
||||
device = Base.identify_device(info)
|
||||
assert device.manufacturer == "Cambium Networks"
|
||||
assert device.model == "ePMP"
|
||||
end
|
||||
|
||||
test "Cambium with no descr and no matching OID line falls back to Wireless" do
|
||||
info = %{
|
||||
sys_descr: "Cambium device",
|
||||
# 17713 prefix but unknown product line (.99)
|
||||
sys_object_id: "1.3.6.1.4.1.17713.99.1"
|
||||
}
|
||||
|
||||
device = Base.identify_device(info)
|
||||
assert device.manufacturer == "Cambium Networks"
|
||||
assert device.model == "Wireless"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue