towerops/test/snmpkit/snmp_lib/mib/utilities_test.exs

414 lines
11 KiB
Elixir

defmodule SnmpKit.SnmpLib.MIB.UtilitiesTest do
use ExUnit.Case, async: true
alias SnmpKit.SnmpLib.MIB.Utilities
describe "register_oid/4" do
test "registers a new OID" do
oid_table = %{}
result = Utilities.register_oid("sysDescr", [1, 3, 6, 1, 2, 1, 1, 1], :resolved, oid_table)
assert Map.has_key?(result, "sysDescr")
entry = result["sysDescr"]
assert entry.name == "sysDescr"
assert entry.oid == [1, 3, 6, 1, 2, 1, 1, 1]
assert entry.status == :resolved
assert entry.parent == [1, 3, 6, 1, 2, 1, 1]
end
test "registers root OID without parent" do
oid_table = %{}
result = Utilities.register_oid("root", [1], :resolved, oid_table)
entry = result["root"]
assert entry.parent == nil
end
end
describe "resolve_oids/1" do
test "resolves OID tree successfully" do
oid_table = %{
"root" => %{
name: "root",
oid: [1],
status: :resolved,
parent: nil,
children: []
},
"child" => %{
name: "child",
oid: [%{name: "root", value: 3}],
status: :unresolved,
parent: nil,
children: []
}
}
# This tests OID resolution - should either succeed or return error
result = Utilities.resolve_oids(oid_table)
# Should return either ok or error
valid? = match?({:ok, _}, result) or match?({:error, _}, result)
assert valid?
end
test "handles already resolved OIDs" do
oid_table = %{
"sysDescr" => %{
name: "sysDescr",
oid: [1, 3, 6, 1, 2, 1, 1, 1],
status: :resolved,
parent: [1, 3, 6, 1, 2, 1, 1],
children: []
}
}
assert {:ok, result} = Utilities.resolve_oids(oid_table)
assert result == oid_table
end
end
describe "tr_oid/2" do
test "translates resolved OID name to numeric" do
oid_table = %{
"sysDescr" => %{
name: "sysDescr",
oid: [1, 3, 6, 1, 2, 1, 1, 1],
status: :resolved,
parent: nil,
children: []
}
}
assert {:ok, [1, 3, 6, 1, 2, 1, 1, 1]} = Utilities.tr_oid("sysDescr", oid_table)
end
test "returns error for unresolved OID" do
oid_table = %{
"test" => %{
name: "test",
oid: [1, 2, 3],
status: :unresolved,
parent: nil,
children: []
}
}
assert {:error, :unresolved} = Utilities.tr_oid("test", oid_table)
end
test "returns error for unknown OID" do
oid_table = %{}
assert {:error, :not_found} = Utilities.tr_oid("unknown", oid_table)
end
end
describe "update_me_oids/3" do
test "updates MIB entries with resolved OIDs" do
oid_table = %{
"system" => %{
name: "system",
oid: [1, 3, 6, 1, 2, 1, 1],
status: :resolved,
parent: nil,
children: []
}
}
entries = [
%{name: "sysDescr", oid: "system"},
%{name: "other", value: 123}
]
result = Utilities.update_me_oids(entries, oid_table, :silent)
# First entry should have resolved OID
first = Enum.at(result, 0)
assert first.oid == [1, 3, 6, 1, 2, 1, 1]
# Second entry has no oid field, should remain unchanged
second = Enum.at(result, 1)
assert second.value == 123
end
test "handles entries without OIDs" do
entries = [%{name: "test", value: 123}]
result = Utilities.update_me_oids(entries, %{}, :debug)
assert result == entries
end
end
describe "make_asn1_type/1" do
test "validates integer type" do
assert {:ok, type_def} = Utilities.make_asn1_type({:integer, []})
assert type_def.type == :integer
end
test "validates integer with range constraint" do
assert {:ok, type_def} = Utilities.make_asn1_type({:integer, [{:range, 0, 100}]})
assert type_def.type == :integer
assert type_def.constraints == [{:range, 0, 100}]
end
test "validates octet string type" do
assert {:ok, type_def} = Utilities.make_asn1_type({:octet_string, []})
assert type_def.type == :octet_string
end
test "validates octet string with size constraint" do
assert {:ok, type_def} = Utilities.make_asn1_type({:octet_string, [1, {:range, 0, 255}]})
assert type_def.type == :octet_string
end
test "validates object identifier type" do
assert {:ok, type_def} = Utilities.make_asn1_type({:object_identifier})
assert type_def.type == :object_identifier
end
test "validates named type" do
assert {:ok, type_def} = Utilities.make_asn1_type({:named_type, "DisplayString"})
assert type_def.type == :named_type
assert type_def.name == "DisplayString"
end
test "validates atom type" do
assert {:ok, type_def} = Utilities.make_asn1_type(:integer)
assert type_def.type == :integer
end
test "rejects invalid type" do
assert {:error, msg} = Utilities.make_asn1_type({:invalid_type, "bad"})
assert msg =~ "Invalid type definition"
end
test "rejects invalid integer constraint" do
assert {:error, msg} = Utilities.make_asn1_type({:integer, [{:range, 100, 0}]})
assert msg =~ "Invalid integer constraint"
end
test "rejects invalid size constraint" do
assert {:error, msg} = Utilities.make_asn1_type({:octet_string, [-1]})
assert msg =~ "Invalid size constraint"
end
end
describe "test_kibbles/2" do
test "validates unique bit names and values" do
bits = [
%{name: "bit1", value: 0},
%{name: "bit2", value: 1},
%{name: "bit3", value: 2}
]
assert :ok = Utilities.test_kibbles(bits, :debug)
end
test "rejects duplicate bit names" do
bits = [
%{name: "bit1", value: 0},
%{name: "bit1", value: 1}
]
assert {:error, msg} = Utilities.test_kibbles(bits, :warning)
assert msg =~ "Duplicate bit names"
end
test "rejects duplicate bit values" do
bits = [
%{name: "bit1", value: 0},
%{name: "bit2", value: 0}
]
assert {:error, msg} = Utilities.test_kibbles(bits, :warning)
assert msg =~ "Duplicate bit values"
end
end
describe "allow_size_rfc1902/1" do
test "allows size for octet_string" do
assert Utilities.allow_size_rfc1902(:octet_string)
end
test "disallows size for integer" do
refute Utilities.allow_size_rfc1902(:integer)
end
test "disallows size for object_identifier" do
refute Utilities.allow_size_rfc1902(:object_identifier)
end
end
describe "check_sub_ids/3" do
test "accepts valid sub-identifiers" do
assert :ok = Utilities.check_sub_ids([1, 3, 6, 1, 2, 1], 0, 255)
end
test "rejects sub-identifier below minimum" do
assert {:error, msg} = Utilities.check_sub_ids([1, 3, -1], 0, 255)
assert msg =~ "out of range"
end
test "rejects sub-identifier above maximum" do
assert {:error, msg} = Utilities.check_sub_ids([1, 3, 300], 0, 255)
assert msg =~ "out of range"
end
end
describe "print_error/2" do
test "prints error when not silent" do
assert :ok = Utilities.print_error("Test error", :warning)
end
test "suppresses error when silent" do
assert :ok = Utilities.print_error("Test error", :silent)
end
end
describe "print_error/3" do
test "prints formatted error when not silent" do
assert :ok = Utilities.print_error("Error: ~p", ["test"], :info)
end
test "suppresses formatted error when silent" do
assert :ok = Utilities.print_error("Error: ~p", ["test"], :silent)
end
end
describe "compilation_error/1" do
test "throws error with message" do
assert catch_throw(Utilities.compilation_error("Test error")) == {:error, "Test error"}
end
end
describe "compilation_error/2" do
test "throws formatted error" do
result = catch_throw(Utilities.compilation_error("Error: ~s", ["test"]))
assert {:error, msg} = result
assert msg =~ "Error: test"
end
end
describe "vprint/6" do
test "prints debug message when verbosity is high enough" do
assert :ok =
Utilities.vprint(:debug, :debug, "TestModule", "test_function", "Message: ~s", [
"test"
])
end
test "suppresses message when verbosity is too low" do
assert :ok =
Utilities.vprint(:silent, :debug, "TestModule", "test_function", "Message", [])
end
end
describe "printable?/2" do
test "returns true when current >= required" do
assert Utilities.printable?(:debug, :warning)
assert Utilities.printable?(:info, :warning)
assert Utilities.printable?(:warning, :warning)
end
test "returns false when current < required" do
refute Utilities.printable?(:warning, :debug)
refute Utilities.printable?(:silent, :info)
end
end
describe "vvalidate/1" do
test "validates valid verbosity levels" do
assert {:ok, :silent} = Utilities.vvalidate(:silent)
assert {:ok, :warning} = Utilities.vvalidate(:warning)
assert {:ok, :info} = Utilities.vvalidate(:info)
assert {:ok, :debug} = Utilities.vvalidate(:debug)
end
test "rejects invalid verbosity" do
assert {:error, msg} = Utilities.vvalidate(:invalid)
assert msg =~ "Invalid verbosity level"
end
test "rejects non-atom verbosity" do
assert {:error, msg} = Utilities.vvalidate("debug")
assert msg =~ "Invalid verbosity level"
end
end
describe "key1search/2" do
test "finds tuple by first element" do
list = [{:a, 1}, {:b, 2}, {:c, 3}]
assert {:value, {:b, 2}} = Utilities.key1search(:b, list)
end
test "returns false when not found" do
list = [{:a, 1}, {:b, 2}]
assert false == Utilities.key1search(:c, list)
end
end
describe "key1search/3" do
test "returns tuple when found" do
list = [{:a, 1}, {:b, 2}]
assert {:b, 2} = Utilities.key1search(:b, list, :default)
end
test "returns default when not found" do
list = [{:a, 1}]
assert :default = Utilities.key1search(:b, list, :default)
end
end
describe "set_dir/2" do
test "joins directory when filename has no path" do
result = Utilities.set_dir("test.mib", "/usr/share/mibs")
assert result == "/usr/share/mibs/test.mib"
end
test "preserves absolute path" do
result = Utilities.set_dir("/home/user/test.mib", "/usr/share/mibs")
assert result == "/home/user/test.mib"
end
test "preserves relative path with directory" do
result = Utilities.set_dir("mibs/test.mib", "/usr/share/mibs")
assert result == "mibs/test.mib"
end
end
describe "lookup/2" do
test "finds item by key in tuple list" do
list = [{:a, 1}, {:b, 2}]
assert {:ok, {:b, 2}} = Utilities.lookup(:b, list)
end
test "finds item by name in map list" do
list = [%{name: "test1", value: 1}, %{name: "test2", value: 2}]
assert {:ok, %{name: "test2", value: 2}} = Utilities.lookup("test2", list)
end
test "finds item by id in map list" do
list = [%{id: 1, data: "a"}, %{id: 2, data: "b"}]
assert {:ok, %{id: 2, data: "b"}} = Utilities.lookup(2, list)
end
test "returns error when not found" do
list = [{:a, 1}]
assert {:error, :not_found} = Utilities.lookup(:b, list)
end
end
end