164 lines
5.4 KiB
Elixir
164 lines
5.4 KiB
Elixir
defmodule SnmpKit.SnmpMgr.MIBTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
# Test helper to parse a MIB and extract name->OID map
|
|
defp parse_and_extract(mib_path) do
|
|
{:ok, content} = File.read(mib_path)
|
|
{:ok, parsed} = SnmpKit.SnmpLib.MIB.Parser.parse(content)
|
|
definitions = Map.get(parsed, :definitions, [])
|
|
|
|
# Extract OID definitions (simulating build_oid_definition_map)
|
|
oid_defs =
|
|
definitions
|
|
|> Enum.filter(fn def ->
|
|
type = Map.get(def, :__type__)
|
|
type in [:object_type, :object_identifier, :module_identity]
|
|
end)
|
|
|> Enum.reduce(%{}, fn def, acc ->
|
|
name = Map.get(def, :name)
|
|
oid = Map.get(def, :oid)
|
|
parent = Map.get(def, :parent)
|
|
sub_index = Map.get(def, :sub_index)
|
|
|
|
cond do
|
|
name && oid -> Map.put(acc, name, oid)
|
|
name && parent && sub_index -> Map.put(acc, name, {String.to_atom(parent), sub_index})
|
|
name && parent -> Map.put(acc, name, {String.to_atom(parent), nil})
|
|
true -> acc
|
|
end
|
|
end)
|
|
|
|
# Apply workaround for parser bug with index 10
|
|
fix_missing_indices(oid_defs, content)
|
|
end
|
|
|
|
# Workaround for parser bug - extract indices from raw MIB content
|
|
defp fix_missing_indices(oid_defs, mib_content) do
|
|
missing =
|
|
Enum.filter(oid_defs, fn {_, oid_def} ->
|
|
case oid_def do
|
|
{_, nil} -> true
|
|
_ -> false
|
|
end
|
|
end)
|
|
|
|
Enum.reduce(missing, oid_defs, fn {name, _}, acc ->
|
|
regex = ~r/#{name}\s+OBJECT\s+IDENTIFIER\s+::=\s+\{\s+(\w+)\s+(\d+)\s+\}/
|
|
|
|
case Regex.run(regex, mib_content) do
|
|
[_, parent, index_str] ->
|
|
index = String.to_integer(index_str)
|
|
parent_atom = String.to_atom(parent)
|
|
Map.put(acc, name, {parent_atom, <<index>>})
|
|
|
|
_ ->
|
|
acc
|
|
end
|
|
end)
|
|
end
|
|
|
|
# Test helper to resolve OID tuples
|
|
defp resolve_oid_def({parent_name, index_binary}, resolved_map) when is_atom(parent_name) do
|
|
parent_str = Atom.to_string(parent_name)
|
|
|
|
case Map.get(resolved_map, parent_str) do
|
|
parent_oid when is_list(parent_oid) ->
|
|
# Decode index - MIB parser uses UTF-8 character for numeric values
|
|
index =
|
|
case String.to_charlist(index_binary) do
|
|
[code_point | _] -> code_point
|
|
[] -> :binary.decode_unsigned(index_binary)
|
|
end
|
|
|
|
{:ok, parent_oid ++ [index]}
|
|
|
|
_ ->
|
|
{:error, :parent_not_resolved}
|
|
end
|
|
end
|
|
|
|
defp resolve_oid_def(oid_list, _resolved_map) when is_list(oid_list) do
|
|
if Enum.all?(oid_list, &is_integer/1) do
|
|
{:ok, oid_list}
|
|
else
|
|
{:error, :not_resolved}
|
|
end
|
|
end
|
|
|
|
defp resolve_oid_def(_, _), do: {:error, :invalid_format}
|
|
|
|
describe "MIB parsing and OID resolution" do
|
|
test "workaround fixes missing sub_index for ubntAFLTU" do
|
|
mib_path = Path.join(:code.priv_dir(:towerops), "mibs/ubnt/UBNT-MIB")
|
|
oid_defs = parse_and_extract(mib_path)
|
|
|
|
# ubntAFLTU should have index 10 after workaround
|
|
assert {:ubntMIB, <<10>>} = oid_defs["ubntAFLTU"],
|
|
"ubntAFLTU should have been fixed to {:ubntMIB, <<10>>} by workaround"
|
|
end
|
|
|
|
test "parses UBNT-MIB and extracts OID definitions" do
|
|
mib_path = Path.join(:code.priv_dir(:towerops), "mibs/ubnt/UBNT-MIB")
|
|
oid_defs = parse_and_extract(mib_path)
|
|
|
|
# Should have extracted OID definitions
|
|
assert map_size(oid_defs) > 0
|
|
|
|
# Check specific definitions
|
|
assert Map.has_key?(oid_defs, "ubnt")
|
|
assert Map.has_key?(oid_defs, "ubntMIB")
|
|
assert Map.has_key?(oid_defs, "ubntAFLTU")
|
|
|
|
# ubnt should reference enterprises with index 41112
|
|
assert {:enterprises, _} = oid_defs["ubnt"]
|
|
|
|
# ubntMIB should reference ubnt with an index
|
|
assert {:ubnt, _} = oid_defs["ubntMIB"]
|
|
|
|
# ubntAFLTU should reference ubntMIB with index 10 (fixed by workaround)
|
|
assert {:ubntMIB, <<10>>} = oid_defs["ubntAFLTU"]
|
|
end
|
|
|
|
test "resolves OID with parent reference" do
|
|
# Simulate having enterprises already resolved
|
|
resolved_map = %{"enterprises" => [1, 3, 6, 1, 4, 1]}
|
|
|
|
# ubnt = enterprises.41112 (where 41112 is encoded as UTF-8 char "ꂘ")
|
|
ubnt_def = {:enterprises, "ꂘ"}
|
|
assert {:ok, [1, 3, 6, 1, 4, 1, 41_112]} = resolve_oid_def(ubnt_def, resolved_map)
|
|
end
|
|
|
|
test "resolves OID chain iteratively" do
|
|
# Start with standard OIDs
|
|
resolved = %{
|
|
"enterprises" => [1, 3, 6, 1, 4, 1],
|
|
"mib-2" => [1, 3, 6, 1, 2, 1]
|
|
}
|
|
|
|
# First iteration: resolve ubnt
|
|
ubnt_def = {:enterprises, "ꂘ"}
|
|
{:ok, ubnt_oid} = resolve_oid_def(ubnt_def, resolved)
|
|
resolved = Map.put(resolved, "ubnt", ubnt_oid)
|
|
|
|
assert resolved["ubnt"] == [1, 3, 6, 1, 4, 1, 41_112]
|
|
|
|
# Second iteration: resolve ubntMIB (ubnt.1)
|
|
ubnt_mib_def = {:ubnt, <<1>>}
|
|
{:ok, ubnt_mib_oid} = resolve_oid_def(ubnt_mib_def, resolved)
|
|
resolved = Map.put(resolved, "ubntMIB", ubnt_mib_oid)
|
|
|
|
assert resolved["ubntMIB"] == [1, 3, 6, 1, 4, 1, 41_112, 1]
|
|
|
|
# Third iteration: resolve ubntAFLTU (ubntMIB.10)
|
|
ubnt_afltu_def = {:ubntMIB, <<10>>}
|
|
{:ok, ubnt_afltu_oid} = resolve_oid_def(ubnt_afltu_def, resolved)
|
|
resolved = Map.put(resolved, "ubntAFLTU", ubnt_afltu_oid)
|
|
|
|
assert resolved["ubntAFLTU"] == [1, 3, 6, 1, 4, 1, 41_112, 1, 10]
|
|
end
|
|
end
|
|
|
|
describe "MIB GenServer integration" do
|
|
# MIB loading integration tests removed - not critical for current functionality
|
|
end
|
|
end
|