649 lines
20 KiB
Elixir
649 lines
20 KiB
Elixir
defmodule Towerops.Snmp.ClientTest do
|
|
use ExUnit.Case, async: true
|
|
use ExUnitProperties
|
|
|
|
import Mox
|
|
|
|
alias Towerops.Snmp.Client
|
|
alias Towerops.Snmp.SnmpMock
|
|
|
|
doctest Client
|
|
|
|
# Set up mocks
|
|
setup :verify_on_exit!
|
|
|
|
@test_opts [ip: "192.168.1.1", community: "public", version: "2c"]
|
|
|
|
describe "get/2" do
|
|
test "returns ok tuple with extracted value on success" do
|
|
expect(SnmpMock, :get, fn "192.168.1.1", "1.3.6.1.2.1.1.3.0", _opts ->
|
|
{:ok, {:timeticks, 12_345}}
|
|
end)
|
|
|
|
assert {:ok, 12_345} = Client.get(@test_opts, "1.3.6.1.2.1.1.3.0")
|
|
end
|
|
|
|
test "extracts value from different SNMP types" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:ok, {:octet_string, "test"}} end)
|
|
assert {:ok, "test"} = Client.get(@test_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "returns error tuple on failure" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:error, :timeout} end)
|
|
assert {:error, :timeout} = Client.get(@test_opts, "1.3.6.1.2.1.1.3.0")
|
|
end
|
|
|
|
test "handles no_such_object error" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:error, :no_such_object} end)
|
|
assert {:error, :no_such_object} = Client.get(@test_opts, "1.3.6.1.99.99.99")
|
|
end
|
|
|
|
test "handles no_such_instance error" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:error, :no_such_instance} end)
|
|
assert {:error, :no_such_instance} = Client.get(@test_opts, "1.3.6.1.2.1.1.99.0")
|
|
end
|
|
|
|
test "handles end_of_mib_view error" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:error, :end_of_mib_view} end)
|
|
assert {:error, :end_of_mib_view} = Client.get(@test_opts, "1.3.6.1.9.9.9.9")
|
|
end
|
|
|
|
test "accepts list OID format" do
|
|
expect(SnmpMock, :get, fn _, [1, 3, 6, 1, 2, 1, 1, 3, 0], _ ->
|
|
{:ok, {:timeticks, 12_345}}
|
|
end)
|
|
|
|
assert {:ok, 12_345} = Client.get(@test_opts, [1, 3, 6, 1, 2, 1, 1, 3, 0])
|
|
end
|
|
|
|
property "extracts all SNMP value types correctly" do
|
|
check all(
|
|
{type, value} <-
|
|
StreamData.one_of([
|
|
StreamData.tuple({
|
|
StreamData.constant(:integer),
|
|
StreamData.integer()
|
|
}),
|
|
StreamData.tuple({
|
|
StreamData.constant(:octet_string),
|
|
StreamData.string(:alphanumeric)
|
|
}),
|
|
StreamData.tuple({
|
|
StreamData.constant(:counter32),
|
|
StreamData.integer(0..4_294_967_295)
|
|
}),
|
|
StreamData.tuple({
|
|
StreamData.constant(:gauge32),
|
|
StreamData.integer(0..4_294_967_295)
|
|
})
|
|
])
|
|
) do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:ok, {type, value}} end)
|
|
assert {:ok, ^value} = Client.get(@test_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "get_multiple/2" do
|
|
test "returns ok with list of values when all succeed using batched GET" do
|
|
expect(SnmpMock, :get_multiple, fn _, oids, _ ->
|
|
result_map = %{
|
|
"1.3.6.1.2.1.1.1.0" => {:octet_string, "Router"},
|
|
"1.3.6.1.2.1.1.3.0" => {:timeticks, 12_345}
|
|
}
|
|
|
|
# Verify requested OIDs match
|
|
assert MapSet.new(oids) == MapSet.new(Map.keys(result_map))
|
|
{:ok, result_map}
|
|
end)
|
|
|
|
oids = ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0"]
|
|
assert {:ok, ["Router", 12_345]} = Client.get_multiple(@test_opts, oids)
|
|
end
|
|
|
|
test "returns error when any OID fails in batched GET" do
|
|
expect(SnmpMock, :get_multiple, fn _, _oids, _ ->
|
|
{:ok,
|
|
%{
|
|
"1.3.6.1.2.1.1.1.0" => {:octet_string, "Router"},
|
|
"1.3.6.1.2.1.99.99.0" => {:error, :no_such_object}
|
|
}}
|
|
end)
|
|
|
|
oids = ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.99.99.0"]
|
|
assert {:error, :partial_failure} = Client.get_multiple(@test_opts, oids)
|
|
end
|
|
|
|
test "falls back to sequential GET when batched GET fails" do
|
|
# First expect batched GET to fail
|
|
expect(SnmpMock, :get_multiple, fn _, _oids, _ ->
|
|
{:error, :timeout}
|
|
end)
|
|
|
|
# Then expect sequential GET calls
|
|
expect(SnmpMock, :get, 2, fn _, oid, _ ->
|
|
case oid do
|
|
"1.3.6.1.2.1.1.1.0" -> {:ok, {:octet_string, "Router"}}
|
|
"1.3.6.1.2.1.1.3.0" -> {:ok, {:timeticks, 12_345}}
|
|
end
|
|
end)
|
|
|
|
oids = ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0"]
|
|
assert {:ok, ["Router", 12_345]} = Client.get_multiple(@test_opts, oids)
|
|
end
|
|
|
|
test "maintains order of results matching input order" do
|
|
expect(SnmpMock, :get_multiple, fn _, _oids, _ ->
|
|
# Return in different order than requested
|
|
{:ok,
|
|
%{
|
|
"1.3.6.1.2.1.1.3.0" => {:timeticks, 12_345},
|
|
"1.3.6.1.2.1.1.5.0" => {:octet_string, "hostname"},
|
|
"1.3.6.1.2.1.1.1.0" => {:octet_string, "Router"}
|
|
}}
|
|
end)
|
|
|
|
# Request in specific order
|
|
oids = ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0", "1.3.6.1.2.1.1.5.0"]
|
|
|
|
# Should return in same order as requested
|
|
assert {:ok, ["Router", 12_345, "hostname"]} = Client.get_multiple(@test_opts, oids)
|
|
end
|
|
|
|
property "handles variable number of OIDs with batched GET" do
|
|
check all(count <- StreamData.integer(1..10)) do
|
|
expect(SnmpMock, :get_multiple, fn _, oids, _ ->
|
|
result_map =
|
|
Map.new(oids, fn oid ->
|
|
{oid, {:integer, 42}}
|
|
end)
|
|
|
|
{:ok, result_map}
|
|
end)
|
|
|
|
oids = Enum.map(1..count, fn i -> "1.3.6.1.2.1.1.#{i}.0" end)
|
|
assert {:ok, values} = Client.get_multiple(@test_opts, oids)
|
|
assert length(values) == count
|
|
assert Enum.all?(values, &(&1 == 42))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "walk/2" do
|
|
test "returns map of OID to value on success" do
|
|
expect(SnmpMock, :walk, fn _, "1.3.6.1.2.1.2.2.1.2", _ ->
|
|
{:ok,
|
|
[
|
|
%{oid: "1.3.6.1.2.1.2.2.1.2.1", value: "eth0"},
|
|
%{oid: "1.3.6.1.2.1.2.2.1.2.2", value: "eth1"}
|
|
]}
|
|
end)
|
|
|
|
assert {:ok, results} = Client.walk(@test_opts, "1.3.6.1.2.1.2.2.1.2")
|
|
assert is_map(results) and map_size(results) > 0
|
|
assert results["1.3.6.1.2.1.2.2.1.2.1"] == "eth0"
|
|
assert results["1.3.6.1.2.1.2.2.1.2.2"] == "eth1"
|
|
end
|
|
|
|
test "returns error tuple on failure" do
|
|
expect(SnmpMock, :walk, fn _, _, _ -> {:error, :timeout} end)
|
|
assert {:error, :timeout} = Client.walk(@test_opts, "1.3.6.1.2.1.2.2.1.2")
|
|
end
|
|
|
|
test "handles empty walk results" do
|
|
expect(SnmpMock, :walk, fn _, _, _ -> {:ok, []} end)
|
|
assert {:ok, results} = Client.walk(@test_opts, "1.3.6.1.2.1.99.99")
|
|
assert results == %{}
|
|
end
|
|
|
|
property "converts list of results to map" do
|
|
check all(count <- StreamData.integer(1..20)) do
|
|
results =
|
|
Enum.map(1..count, fn i ->
|
|
%{oid: "1.3.6.1.2.1.2.2.1.2.#{i}", value: "eth#{i}"}
|
|
end)
|
|
|
|
expect(SnmpMock, :walk, fn _, _, _ -> {:ok, results} end)
|
|
assert {:ok, walked} = Client.walk(@test_opts, "1.3.6.1.2.1.2.2.1.2")
|
|
assert map_size(walked) == count
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "get_bulk/3" do
|
|
test "returns map of OID to value on success" do
|
|
expect(SnmpMock, :get_bulk, fn _, "1.3.6.1.2.1.2.2.1.10", opts ->
|
|
assert opts[:max_repetitions] == 10
|
|
|
|
{:ok,
|
|
[
|
|
%{oid: "1.3.6.1.2.1.2.2.1.10.1", value: 1000},
|
|
%{oid: "1.3.6.1.2.1.2.2.1.10.2", value: 2000}
|
|
]}
|
|
end)
|
|
|
|
assert {:ok, results} = Client.get_bulk(@test_opts, "1.3.6.1.2.1.2.2.1.10", max_repetitions: 10)
|
|
assert is_map(results) and map_size(results) > 0
|
|
assert results["1.3.6.1.2.1.2.2.1.10.1"] == 1000
|
|
end
|
|
|
|
test "uses default max_repetitions of 10" do
|
|
expect(SnmpMock, :get_bulk, fn _, _, opts ->
|
|
assert opts[:max_repetitions] == 10
|
|
{:ok, []}
|
|
end)
|
|
|
|
Client.get_bulk(@test_opts, "1.3.6.1.2.1.2.2.1.10")
|
|
end
|
|
|
|
test "uses custom max_repetitions" do
|
|
expect(SnmpMock, :get_bulk, fn _, _, opts ->
|
|
assert opts[:max_repetitions] == 50
|
|
{:ok, []}
|
|
end)
|
|
|
|
Client.get_bulk(@test_opts, "1.3.6.1.2.1.2.2.1.10", max_repetitions: 50)
|
|
end
|
|
|
|
test "returns error tuple on failure" do
|
|
expect(SnmpMock, :get_bulk, fn _, _, _ -> {:error, :timeout} end)
|
|
assert {:error, :timeout} = Client.get_bulk(@test_opts, "1.3.6.1.2.1.2.2.1.10")
|
|
end
|
|
end
|
|
|
|
describe "test_connection/1" do
|
|
test "returns success when sysUpTime is retrieved" do
|
|
expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.3.0", _ ->
|
|
{:ok, {:timeticks, 12_345}}
|
|
end)
|
|
|
|
assert {:ok, "Connection successful"} = Client.test_connection(@test_opts)
|
|
end
|
|
|
|
test "returns error when connection fails" do
|
|
expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.3.0", _ ->
|
|
{:error, :timeout}
|
|
end)
|
|
|
|
assert {:error, :timeout} = Client.test_connection(@test_opts)
|
|
end
|
|
|
|
test "returns error when host is unreachable" do
|
|
expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.3.0", _ ->
|
|
{:error, :network_unreachable}
|
|
end)
|
|
|
|
assert {:error, :network_unreachable} = Client.test_connection(@test_opts)
|
|
end
|
|
end
|
|
|
|
describe "connection options" do
|
|
property "valid connection options include all required fields" do
|
|
check all(
|
|
ip <- StreamData.string(:alphanumeric, min_length: 7, max_length: 15),
|
|
community <- StreamData.string(:alphanumeric, min_length: 1, max_length: 32),
|
|
version <- StreamData.member_of(["1", "2c"]),
|
|
port <- StreamData.integer(1..65_535),
|
|
timeout <- StreamData.integer(1000..30_000)
|
|
) do
|
|
opts = [
|
|
ip: ip,
|
|
community: community,
|
|
version: version,
|
|
port: port,
|
|
timeout: timeout
|
|
]
|
|
|
|
# Should have all required fields
|
|
assert Keyword.has_key?(opts, :ip)
|
|
assert Keyword.has_key?(opts, :community)
|
|
assert Keyword.has_key?(opts, :version)
|
|
|
|
# Optional fields with valid values
|
|
assert opts[:port] > 0 and opts[:port] <= 65_535
|
|
assert opts[:timeout] >= 1000
|
|
end
|
|
end
|
|
|
|
test "minimal valid options" do
|
|
opts = [ip: "192.168.1.1", community: "public", version: "2c"]
|
|
|
|
assert Keyword.has_key?(opts, :ip)
|
|
assert Keyword.has_key?(opts, :community)
|
|
assert Keyword.has_key?(opts, :version)
|
|
end
|
|
end
|
|
|
|
describe "OID formats" do
|
|
property "accepts string OIDs" do
|
|
check all(oid_parts <- StreamData.list_of(StreamData.positive_integer(), min_length: 3, max_length: 10)) do
|
|
oid = Enum.join(oid_parts, ".")
|
|
|
|
# Valid OID format
|
|
assert oid =~ ~r/^[\d.]+$/
|
|
assert is_binary(oid)
|
|
end
|
|
end
|
|
|
|
property "accepts list OIDs" do
|
|
check all(oid_list <- StreamData.list_of(StreamData.non_negative_integer(), min_length: 3, max_length: 10)) do
|
|
# All elements are integers
|
|
assert Enum.all?(oid_list, &is_integer/1)
|
|
|
|
# All elements are non-negative
|
|
assert Enum.all?(oid_list, &(&1 >= 0))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "IP address formats" do
|
|
property "IP addresses are strings" do
|
|
check all(octets <- StreamData.list_of(StreamData.integer(0..255), length: 4)) do
|
|
ip = Enum.join(octets, ".")
|
|
opts = [ip: ip, community: "public", version: "2c"]
|
|
|
|
assert is_binary(opts[:ip])
|
|
end
|
|
end
|
|
|
|
test "IPv4 format" do
|
|
valid_ips = [
|
|
"192.168.1.1",
|
|
"10.0.0.1",
|
|
"172.16.0.1",
|
|
"8.8.8.8",
|
|
"127.0.0.1"
|
|
]
|
|
|
|
for ip <- valid_ips do
|
|
opts = [ip: ip, community: "public", version: "2c"]
|
|
assert opts[:ip] == ip
|
|
end
|
|
end
|
|
|
|
test "hostname format" do
|
|
valid_hosts = [
|
|
"router.example.com",
|
|
"switch-01",
|
|
"device123"
|
|
]
|
|
|
|
for host <- valid_hosts do
|
|
opts = [ip: host, community: "public", version: "2c"]
|
|
assert opts[:ip] == host
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "SNMP version handling" do
|
|
test "supports SNMPv1" do
|
|
opts = [ip: "192.168.1.1", community: "public", version: "1"]
|
|
assert opts[:version] == "1"
|
|
end
|
|
|
|
test "supports SNMPv2c" do
|
|
opts = [ip: "192.168.1.1", community: "public", version: "2c"]
|
|
assert opts[:version] == "2c"
|
|
end
|
|
|
|
property "version is always v1 or v2c" do
|
|
check all(version <- StreamData.member_of(["1", "2c", :v1, :v2c])) do
|
|
opts = [ip: "192.168.1.1", community: "public", version: version]
|
|
|
|
normalized_version =
|
|
case opts[:version] do
|
|
"1" -> :v1
|
|
"2c" -> :v2c
|
|
:v1 -> :v1
|
|
:v2c -> :v2c
|
|
end
|
|
|
|
assert normalized_version in [:v1, :v2c]
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "community strings" do
|
|
property "community strings can be any non-empty string" do
|
|
check all(community <- StreamData.string(:alphanumeric, min_length: 1, max_length: 64)) do
|
|
opts = [ip: "192.168.1.1", community: community, version: "2c"]
|
|
|
|
assert is_binary(opts[:community])
|
|
assert String.length(opts[:community]) > 0
|
|
end
|
|
end
|
|
|
|
test "common community strings" do
|
|
common_communities = ["public", "private", "community", "snmp"]
|
|
|
|
for community <- common_communities do
|
|
opts = [ip: "192.168.1.1", community: community, version: "2c"]
|
|
assert opts[:community] == community
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "return value formats" do
|
|
property "error reasons are atoms" do
|
|
check all(
|
|
reason <-
|
|
StreamData.member_of([
|
|
:timeout,
|
|
:no_such_object,
|
|
:no_such_instance,
|
|
:end_of_mib_view,
|
|
:network_unreachable
|
|
])
|
|
) do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:error, reason} end)
|
|
assert {:error, ^reason} = Client.get(@test_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "v3 credential parsing — exercises private parse_* helpers" do
|
|
test "v3 with full authPriv credentials propagates through to adapter" do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "user1",
|
|
security_level: "authPriv",
|
|
auth_protocol: "SHA-256",
|
|
auth_password: "auth-secret",
|
|
priv_protocol: "AES-256",
|
|
priv_password: "priv-secret"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:version] == :v3
|
|
assert snmp_opts[:security_level] == :auth_priv
|
|
assert snmp_opts[:security_name] == "user1"
|
|
assert snmp_opts[:auth_protocol] == :sha256
|
|
assert snmp_opts[:priv_protocol] == :aes256
|
|
{:ok, {:integer, 1}}
|
|
end)
|
|
|
|
assert {:ok, 1} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "v3 with noAuthNoPriv security level" do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "user2",
|
|
security_level: "noAuthNoPriv"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:security_level] == :no_auth_no_priv
|
|
assert snmp_opts[:security_name] == "user2"
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "v3 unknown auth protocol falls back to sha256" do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "u",
|
|
security_level: "authNoPriv",
|
|
auth_protocol: "BANANA",
|
|
auth_password: "p"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:auth_protocol] == :sha256
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "v3 unknown priv protocol falls back to aes" do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "u",
|
|
security_level: "authPriv",
|
|
auth_protocol: "MD5",
|
|
auth_password: "ap",
|
|
priv_protocol: "ZEPHYR",
|
|
priv_password: "pp"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:auth_protocol] == :md5
|
|
assert snmp_opts[:priv_protocol] == :aes
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "v3 SHA, SHA-224, SHA-384, SHA-512 protocols round-trip correctly" do
|
|
for {input, expected} <- [
|
|
{"SHA", :sha},
|
|
{"SHA-224", :sha224},
|
|
{"SHA-384", :sha384},
|
|
{"SHA-512", :sha512}
|
|
] do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "u",
|
|
security_level: "authNoPriv",
|
|
auth_protocol: input,
|
|
auth_password: "p"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:auth_protocol] == expected
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
|
|
test "v3 DES, AES-192, AES-256-C priv protocols round-trip correctly" do
|
|
for {input, expected} <- [
|
|
{"DES", :des},
|
|
{"AES-192", :aes192},
|
|
{"AES-256-C", :aes256c}
|
|
] do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "u",
|
|
security_level: "authPriv",
|
|
auth_protocol: "MD5",
|
|
auth_password: "ap",
|
|
priv_protocol: input,
|
|
priv_password: "pp"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:priv_protocol] == expected
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
|
|
test "version atom passthrough for v1, v2c" do
|
|
for {input, expected} <- [{:v1, :v1}, {:v2c, :v2c}] do
|
|
opts = [ip: "10.0.0.1", community: "public", version: input]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:version] == expected
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
|
|
test "version atom passthrough for v3" do
|
|
opts = [
|
|
ip: "10.0.0.1",
|
|
version: :v3,
|
|
security_name: "u",
|
|
security_level: "noAuthNoPriv"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:version] == :v3
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "unknown version string falls back to v2c" do
|
|
opts = [ip: "10.0.0.1", community: "public", version: "999"]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:version] == :v2c
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
|
|
test "unknown security_level falls back to no_auth_no_priv" do
|
|
v3_opts = [
|
|
ip: "10.0.0.1",
|
|
version: "3",
|
|
security_name: "u",
|
|
security_level: "WHATEVER"
|
|
]
|
|
|
|
expect(SnmpMock, :get, fn _, _, snmp_opts ->
|
|
assert snmp_opts[:security_level] == :no_auth_no_priv
|
|
{:ok, {:integer, 0}}
|
|
end)
|
|
|
|
assert {:ok, 0} = Client.get(v3_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
|
|
describe "extract_snmp_value via get/2" do
|
|
for {tag_tuple, expected} <- [
|
|
{{:counter32, 100}, 100},
|
|
{{:counter64, 1_000_000}, 1_000_000},
|
|
{{:gauge32, 50}, 50},
|
|
{{:ip_address, "1.2.3.4"}, "1.2.3.4"},
|
|
{{:object_identifier, "1.3.6.1"}, "1.3.6.1"},
|
|
{{:opaque, "x"}, "x"}
|
|
] do
|
|
test "extracts #{elem(tag_tuple, 0)} value" do
|
|
expect(SnmpMock, :get, fn _, _, _ -> {:ok, unquote(Macro.escape(tag_tuple))} end)
|
|
|
|
assert {:ok, unquote(expected)} = Client.get(@test_opts, "1.3.6.1.2.1.1.1.0")
|
|
end
|
|
end
|
|
end
|
|
end
|