netx/tests/test_fsm_parser_pipeline.py
oliver 0f235133ed Wire ZTE show arp through TextFSM dual-input pipeline.
Add zte_zxros_show_arp rule + prefer_fsm mapping using the lab one-line sample.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 22:30:23 +08:00

103 lines
3.9 KiB
Python

"""Tests for TextFSM rule table + parser dual-input pipeline."""
from __future__ import annotations
import unittest
from netx_api.biz_state.parsers import get_parser_meta, run_parser
from netx_api.ntc_parse import apply_rule, apply_rules, rules_for_command
ZTE_BRIEF = """\
Interface Attribute Mode BW Admin Phy Prot Description
xgei-1/1/0/1 optical Duplex/full 1G up up up C2930L100-EQ2
xgei-1/1/0/2 optical Duplex/full 1G up down down
"""
ZTE_ARP = """\
IP Hardware Exter Inter Sub
Address Age Address Interface VlanID VlanID Interface
--------------------------------------------------------------------------------
192.168.1.1 03:22:07 0011.2233.4455 gei-0/1/0/1 N/A N/A gei-0/1/0/1
192.168.1.2 H 00aa.bbcc.ddee gei-0/1/0/1 N/A N/A N/A
"""
class ApplyRulesTests(unittest.TestCase):
def test_apply_rules_interface_brief(self) -> None:
stems = rules_for_command("zte_zxros", "show interface brief")
self.assertIn("zte_zxros_show_interface_brief", stems)
tables = apply_rules(
platform="zte_zxros",
text=ZTE_BRIEF,
rule_keys=("zte_zxros_show_interface_brief",),
command="show interface brief",
)
rows = tables.get("zte_zxros_show_interface_brief") or []
self.assertGreaterEqual(len(rows), 2)
self.assertEqual(rows[0].get("INTERFACE") or rows[0].get("interface"), "xgei-1/1/0/1")
def test_apply_rule_missing_stem(self) -> None:
rows = apply_rule(
platform="zte_zxros",
rule_key="zte_zxros_show_arp_does_not_exist",
text=ZTE_ARP,
)
self.assertEqual(rows, [])
def test_apply_rules_empty_key_on_miss(self) -> None:
tables = apply_rules(
platform="zte_zxros",
text=ZTE_ARP,
rule_keys=("no_such_template_xyz",),
)
self.assertEqual(tables.get("no_such_template_xyz"), [])
class ParserMetaTests(unittest.TestCase):
def test_interface_brief_meta(self) -> None:
meta = get_parser_meta("interface_brief")
self.assertIsNotNone(meta)
assert meta is not None
self.assertIn("zte_zxros_show_interface_brief", meta["rule_keys"])
def test_arp_rule_keys(self) -> None:
meta = get_parser_meta("arp")
self.assertIsNotNone(meta)
assert meta is not None
self.assertEqual(meta["rule_keys"], ("zte_zxros_show_arp",))
self.assertTrue(meta["rule_keys_declared"])
def test_run_parser_interface_brief(self) -> None:
records, tables, keys = run_parser(
"interface_brief",
raw_text=ZTE_BRIEF,
vendor="zte",
device_type="zte_zxros",
command="show interface brief",
)
self.assertIn("zte_zxros_show_interface_brief", keys)
self.assertGreaterEqual(len(tables.get("zte_zxros_show_interface_brief") or []), 2)
self.assertGreaterEqual(len(records), 2)
self.assertEqual(records[0]["interface"], "xgei-1/1/0/1")
def test_run_parser_arp_via_fsm(self) -> None:
records, tables, keys = run_parser(
"arp",
raw_text=ZTE_ARP,
vendor="zte",
device_type="zte_zxros",
command="show arp | one-line",
textfsm_command="show arp",
)
self.assertEqual(keys, ["zte_zxros_show_arp"])
self.assertEqual(len(tables.get("zte_zxros_show_arp") or []), 2)
self.assertEqual(len(records), 2)
by_ip = {r["ip"]: r for r in records}
self.assertEqual(by_ip["192.168.1.1"]["entry_type"], "dynamic")
self.assertEqual(by_ip["192.168.1.2"]["entry_type"], "static")
self.assertEqual(by_ip["192.168.1.1"]["mac"], "0011.2233.4455")
if __name__ == "__main__":
unittest.main()