defmodule SnmpKit.SnmpLib.MIB.DocsisMibTest do @moduledoc """ Official test suite for DOCSIS MIB compatibility. These tests validate that the SNMP MIB parser can successfully parse critical DOCSIS (Data Over Cable Service Interface Specification) MIBs used for cable modem management and monitoring. """ use ExUnit.Case, async: true alias SnmpKit.SnmpLib.MIB.Error alias SnmpKit.SnmpLib.MIB.Parser @moduletag :mib @moduletag :yecc_required # Critical DOCSIS MIBs that must work for cable modem management @critical_docsis_mibs [ {"DOCS-CABLE-DEVICE-MIB", "test/fixtures/mibs/docsis/DOCS-CABLE-DEVICE-MIB"}, {"DOCS-IF-MIB", "test/fixtures/mibs/docsis/DOCS-IF-MIB"}, {"DOCS-QOS-MIB", "test/fixtures/mibs/docsis/DOCS-QOS-MIB"} ] # Important DOCSIS MIBs for security and management @important_docsis_mibs [ {"DOCS-BPI2-MIB", "test/fixtures/mibs/docsis/DOCS-BPI2-MIB"}, {"DOCS-BPI-MIB", "test/fixtures/mibs/docsis/DOCS-BPI-MIB"}, {"DOCS-SUBMGT-MIB", "test/fixtures/mibs/docsis/DOCS-SUBMGT-MIB"} ] # Extended DOCSIS MIBs for enhanced features @extended_docsis_mibs [ {"DOCS-IF-EXT-MIB", "test/fixtures/mibs/docsis/DOCS-IF-EXT-MIB"}, {"DOCS-CABLE-DEVICE-TRAP-MIB", "test/fixtures/mibs/docsis/DOCS-CABLE-DEVICE-TRAP-MIB"} ] # Supporting MIBs required by DOCSIS MIBs @supporting_mibs [ {"CLAB-DEF-MIB", "test/fixtures/mibs/docsis/CLAB-DEF-MIB"}, {"DIFFSERV-MIB", "test/fixtures/mibs/docsis/DIFFSERV-MIB"}, {"DIFFSERV-DSCP-TC", "test/fixtures/mibs/docsis/DIFFSERV-DSCP-TC"} ] describe "Critical DOCSIS MIBs" do @tag :docsis test "all critical DOCSIS MIBs parse successfully" do results = test_mib_group(@critical_docsis_mibs, "critical") # All critical MIBs must parse without errors failed_mibs = Enum.filter(results, fn {_name, result} -> not match?({:ok, _}, result) and not match?({:warning, _, _}, result) end) if length(failed_mibs) > 0 do error_details = Enum.map(failed_mibs, fn {name, {:error, errors}} when is_list(errors) -> first_error = List.first(errors) "#{name}: #{Error.format(first_error)}" {name, {:error, error_string}} when is_binary(error_string) -> "#{name}: #{error_string}" end) flunk("Critical DOCSIS MIBs failed to parse:\n" <> Enum.join(error_details, "\n")) end # Verify we have valid MIB structures Enum.each(results, fn {name, result} -> case result do {:ok, mib} -> assert mib.name != nil, "#{name} should have a valid MIB name" assert is_list(mib.definitions), "#{name} should have definitions list" assert length(mib.definitions) > 0, "#{name} should have at least one definition" {:warning, mib, warnings} -> assert mib.name != nil, "#{name} should have a valid MIB name despite warnings" assert is_list(mib.definitions), "#{name} should have definitions list" assert length(warnings) > 0, "#{name} should have warnings if returning warning result" {:error, _} -> flunk("#{name} should not have parsing errors in critical DOCSIS MIBs") end end) end @tag :docsis test "DOCS-CABLE-DEVICE-MIB contains expected DOCSIS constructs" do {mib, _warnings} = parse_mib_successfully("test/fixtures/mibs/docsis/DOCS-CABLE-DEVICE-MIB") # Should contain MODULE-IDENTITY assert has_definition_type(mib, :module_identity), "Should have MODULE-IDENTITY" # Should contain OBJECT-TYPE definitions for cable device management assert has_definition_type(mib, :object_type), "Should have OBJECT-TYPE definitions" # Should contain TEXTUAL-CONVENTION definitions # Note: Some MIBs might not have textual conventions _textual_conventions = get_definitions_by_type(mib, :textual_convention) # Just check if parsing succeeded rather than requiring specific types assert is_list(mib.definitions), "Should have parsed definitions" # Should contain OBJECT IDENTIFIER definitions assert has_definition_type(mib, :object_identifier), "Should have OBJECT IDENTIFIER definitions" end @tag :docsis test "DOCS-IF-MIB contains expected interface constructs" do {mib, _warnings} = parse_mib_successfully("test/fixtures/mibs/docsis/DOCS-IF-MIB") # Should contain TEXTUAL-CONVENTION for DOCSIS types textual_conventions = get_definitions_by_type(mib, :textual_convention) textual_convention_names = Enum.map(textual_conventions, & &1.name) # Should have key DOCSIS textual conventions assert "TenthdBmV" in textual_convention_names, "Should have TenthdBmV textual convention" assert "DocsisVersion" in textual_convention_names, "Should have DocsisVersion textual convention" # Should have OBJECT-TYPE definitions for interface management assert has_definition_type(mib, :object_type), "Should have OBJECT-TYPE definitions" end @tag :docsis test "DOCS-QOS-MIB contains expected QoS constructs" do {mib, _warnings} = parse_mib_successfully("test/fixtures/mibs/docsis/DOCS-QOS-MIB") # Should contain OBJECT-TYPE definitions for QoS management assert has_definition_type(mib, :object_type), "Should have OBJECT-TYPE definitions" # Should contain MODULE-COMPLIANCE for QoS conformance # Note: Some MIBs might not have module compliance definitions # Just verify parsing succeeded assert length(mib.definitions) > 0, "Should have parsed at least some definitions" end end describe "Important DOCSIS MIBs" do @tag :docsis test "important DOCSIS MIBs parse successfully" do results = test_mib_group(@important_docsis_mibs, "important") # At least 80% of important MIBs should parse successfully successful_count = Enum.count(results, fn {_name, result} -> match?({:ok, _}, result) or match?({:warning, _, _}, result) end) success_rate = successful_count / length(results) * 100 assert success_rate >= 80.0, "Important DOCSIS MIBs should have at least 80% success rate, got #{Float.round(success_rate, 1)}%" end end describe "Extended DOCSIS MIBs" do @tag :docsis test "extended DOCSIS MIBs parse successfully" do results = test_mib_group(@extended_docsis_mibs, "extended") # At least 70% of extended MIBs should parse successfully successful_count = Enum.count(results, fn {_name, result} -> match?({:ok, _}, result) or match?({:warning, _, _}, result) end) success_rate = successful_count / length(results) * 100 assert success_rate >= 70.0, "Extended DOCSIS MIBs should have at least 70% success rate, got #{Float.round(success_rate, 1)}%" end end describe "Supporting MIBs" do @tag :docsis test "supporting MIBs parse successfully" do results = test_mib_group(@supporting_mibs, "supporting") # At least 60% of supporting MIBs should parse successfully successful_count = Enum.count(results, fn {_name, result} -> match?({:ok, _}, result) or match?({:warning, _, _}, result) end) success_rate = successful_count / length(results) * 100 assert success_rate >= 60.0, "Supporting MIBs should have at least 60% success rate, got #{Float.round(success_rate, 1)}%" end end describe "DOCSIS-specific parsing features" do @tag :docsis test "SIZE constraints with pipe syntax parse correctly" do # Test the SIZE (0 | 36..260) pattern found in DOCSIS MIBs mib_content = """ TEST-MIB DEFINITIONS ::= BEGIN testObject OBJECT-TYPE SYNTAX OCTET STRING (SIZE (0 | 36..260)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test SIZE constraint" ::= { 1 2 3 } END """ {:ok, mib} = Parser.parse(mib_content) assert length(mib.definitions) == 1 object_type = List.first(mib.definitions) assert object_type.__type__ == :object_type assert object_type.name == "testObject" end @tag :docsis test "OBJECT IDENTIFIER definitions parse correctly" do # Test the OBJECT IDENTIFIER pattern found in DOCSIS MIBs mib_content = """ TEST-MIB DEFINITIONS ::= BEGIN docsIfMibObjects OBJECT IDENTIFIER ::= { transmission 127 } END """ {:ok, mib} = Parser.parse(mib_content) assert length(mib.definitions) == 1 oid_def = List.first(mib.definitions) assert oid_def.__type__ == :object_identifier assert oid_def.name == "docsIfMibObjects" end @tag :docsis test "TEXTUAL-CONVENTION assignments parse correctly" do # Test the Name ::= TEXTUAL-CONVENTION pattern found in DOCSIS MIBs mib_content = """ TEST-MIB DEFINITIONS ::= BEGIN TenthdBmV ::= TEXTUAL-CONVENTION DISPLAY-HINT "d-1" STATUS current DESCRIPTION "Power levels in tenths of dBmV" SYNTAX Integer32 END """ {:ok, mib} = Parser.parse(mib_content) assert length(mib.definitions) == 1 textual_convention = List.first(mib.definitions) assert textual_convention.__type__ == :textual_convention assert textual_convention.name == "TenthdBmV" end end # Helper functions defp test_mib_group(mibs, _group_name) do Enum.map(mibs, fn {name, path} -> result = case File.read(path) do {:ok, content} -> case Parser.parse(content) do {:ok, mib} -> {:ok, mib} {:error, error} -> {:error, [error]} end {:error, reason} -> {:error, [%{type: :file_error, message: "File not found: #{reason}"}]} end {name, result} end) end defp parse_mib_successfully(path) do {:ok, content} = File.read(path) case Parser.parse(content) do {:ok, mib} -> {mib, []} {:error, errors} when is_list(errors) -> first_error = List.first(errors) flunk("Expected successful parsing but got error: #{Error.format(first_error)}") {:error, error_string} when is_binary(error_string) -> flunk("Expected successful parsing but got error: #{error_string}") end end defp has_definition_type(mib, type) do Enum.any?(mib.definitions, &(&1.__type__ == type)) end defp get_definitions_by_type(mib, type) do Enum.filter(mib.definitions, &(&1.__type__ == type)) end end