137 lines
4.4 KiB
Elixir
137 lines
4.4 KiB
Elixir
defmodule SnmpKit.SnmpMgr.MIB.ExtractionTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias SnmpKit.SnmpLib.MIB.Parser
|
|
|
|
# Test the actual extract_mib_mappings private function behavior
|
|
@tag :yecc_required
|
|
test "extract_mib_mappings resolves UBNT-MIB OIDs" do
|
|
mib_path = Path.join(:code.priv_dir(:towerops), "mibs/ubnt/UBNT-MIB")
|
|
{:ok, mib_content} = File.read(mib_path)
|
|
{:ok, parsed} = Parser.parse(mib_content)
|
|
|
|
# Simulate state with standard MIBs
|
|
mock_state = %{
|
|
name_to_oid: %{
|
|
"enterprises" => [1, 3, 6, 1, 4, 1],
|
|
"mib-2" => [1, 3, 6, 1, 2, 1],
|
|
"system" => [1, 3, 6, 1, 2, 1, 1]
|
|
}
|
|
}
|
|
|
|
# Call the extraction logic manually
|
|
result = extract_mib_mappings_manually(parsed, mock_state, mib_content)
|
|
|
|
# Check that new OIDs were resolved
|
|
assert map_size(result.name_to_oid) > map_size(mock_state.name_to_oid),
|
|
"Should have more OIDs after extraction"
|
|
|
|
# Check specific UBNT OIDs
|
|
assert Map.has_key?(result.name_to_oid, "ubnt")
|
|
assert Map.has_key?(result.name_to_oid, "ubntMIB")
|
|
assert Map.has_key?(result.name_to_oid, "ubntAFLTU")
|
|
|
|
# Verify the resolved values
|
|
assert result.name_to_oid["ubnt"] == [1, 3, 6, 1, 4, 1, 41_112]
|
|
assert result.name_to_oid["ubntMIB"] == [1, 3, 6, 1, 4, 1, 41_112, 1]
|
|
assert result.name_to_oid["ubntAFLTU"] == [1, 3, 6, 1, 4, 1, 41_112, 1, 10]
|
|
end
|
|
|
|
# Manually implement the extraction logic for testing
|
|
defp extract_mib_mappings_manually(parsed, state, mib_content) do
|
|
definitions = Map.get(parsed, :definitions, [])
|
|
|
|
# Build OID definitions
|
|
oid_defs =
|
|
definitions
|
|
|> Enum.filter(&(Map.get(&1, :__type__) in [:object_type, :object_identifier, :module_identity]))
|
|
|> 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)
|
|
|
|
# Fix missing indices
|
|
oid_defs = fix_missing_indices(oid_defs, mib_content)
|
|
|
|
# Resolve OIDs
|
|
name_to_oid = resolve_all_oids(oid_defs, state.name_to_oid)
|
|
|
|
%{name_to_oid: name_to_oid, name_to_meta: %{}}
|
|
end
|
|
|
|
defp fix_missing_indices(oid_defs, mib_content) do
|
|
missing =
|
|
Enum.filter(oid_defs, fn
|
|
{_, {_, nil}} -> true
|
|
_ -> false
|
|
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)
|
|
Map.put(acc, name, {String.to_atom(parent), <<index>>})
|
|
|
|
_ ->
|
|
acc
|
|
end
|
|
end)
|
|
end
|
|
|
|
defp resolve_all_oids(oid_defs, existing_oids) do
|
|
resolve_iteratively(oid_defs, existing_oids, 10)
|
|
end
|
|
|
|
defp resolve_iteratively(_oid_defs, resolved, 0), do: resolved
|
|
|
|
defp resolve_iteratively(oid_defs, resolved, iterations_left) do
|
|
{new_resolved, remaining} =
|
|
Enum.reduce(oid_defs, {resolved, %{}}, fn {name, oid_def}, {res_acc, rem_acc} ->
|
|
case resolve_single(oid_def, res_acc) do
|
|
{:ok, oid_list} -> {Map.put(res_acc, name, oid_list), rem_acc}
|
|
{:error, _} -> {res_acc, Map.put(rem_acc, name, oid_def)}
|
|
end
|
|
end)
|
|
|
|
if map_size(remaining) == map_size(oid_defs) do
|
|
new_resolved
|
|
else
|
|
resolve_iteratively(remaining, new_resolved, iterations_left - 1)
|
|
end
|
|
end
|
|
|
|
defp resolve_single(oid_list, _) when is_list(oid_list) do
|
|
if Enum.all?(oid_list, &is_integer/1), do: {:ok, oid_list}, else: {:error, :not_resolved}
|
|
end
|
|
|
|
defp resolve_single({parent_name, index_binary}, resolved) when is_atom(parent_name) and is_binary(index_binary) do
|
|
parent_str = Atom.to_string(parent_name)
|
|
|
|
case Map.get(resolved, parent_str) do
|
|
parent_oid when is_list(parent_oid) ->
|
|
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_single(_, _), do: {:error, :invalid_format}
|
|
end
|