Inital commit
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
"""Unit tests for TPLinkJetstreamDriver — no real device required."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from napalm_tplink_jetstream.tplink_jetstream import TPLinkJetstreamDriver
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.fixture
|
||||
def driver():
|
||||
"""Return a driver instance with a mocked Netmiko connection."""
|
||||
with patch("napalm_tplink_jetstream.tplink_jetstream.ConnectHandler"):
|
||||
drv = TPLinkJetstreamDriver(
|
||||
hostname="192.168.0.1",
|
||||
username="admin",
|
||||
password="admin",
|
||||
)
|
||||
drv.device = MagicMock()
|
||||
yield drv
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SHOW_SYSTEM_INFO = """\
|
||||
System Name : T2600G-28TS
|
||||
Hardware Version : V2.0
|
||||
Firmware Version : 2.0.7 Build 20200929
|
||||
MAC Address : 00-0A-EB-13-07-82
|
||||
IP Address : 192.168.0.1
|
||||
Subnet Mask : 255.255.255.0
|
||||
Default Gateway : 192.168.0.254
|
||||
System Time : 2024-03-01 08:10:22
|
||||
Run Time : 5 day(s) 2 hour(s) 35 min(s) 16 sec(s)
|
||||
"""
|
||||
|
||||
SHOW_INTERFACE_STATUS = """\
|
||||
Port Status Speed Duplex FlowCtrl Active-Medium LAG Linkdown-Status Description
|
||||
Gi1/0/1 LinkUp 1000M Full Disable Copper N/A N/A uplink
|
||||
Gi1/0/2 LinkDown 100M Full Disable Copper N/A N/A
|
||||
"""
|
||||
|
||||
SHOW_INTERFACE_CONFIG = """\
|
||||
Port State Speed Duplex FlowCtrl Description
|
||||
Gi1/0/1 Enable Auto Auto Disable uplink
|
||||
Gi1/0/2 Enable Auto Auto Disable
|
||||
"""
|
||||
|
||||
SHOW_JUMBO = "Jumbo frames are disabled. Jumbo frame size is 1518 bytes."
|
||||
|
||||
SHOW_ARP = """\
|
||||
Interface Address Hardware Addr Type
|
||||
VLAN8 192.168.0.100 00:50:56:a1:b2:c3 DYNAMIC
|
||||
VLAN8 192.168.0.254 00:0c:29:d4:e5:f6 DYNAMIC
|
||||
"""
|
||||
|
||||
SHOW_MAC = """\
|
||||
MAC Address Table
|
||||
------------------------------------------------------------
|
||||
MAC VLAN Port Type Aging
|
||||
--- ---- ---- ---- -----
|
||||
00:50:56:a1:b2:c3 8 Gi1/0/2 dynamic aging
|
||||
ff:ff:ff:ff:ff:ff 1 CPU static noaging
|
||||
"""
|
||||
|
||||
SHOW_VLAN = """\
|
||||
UT: Untagged; TG: Tagged
|
||||
VLAN Name Status Ports
|
||||
---- --------------- -------- ----------------
|
||||
1 Default active UT: Gi1/0/1-2
|
||||
10 Management active UT: Gi1/0/3
|
||||
"""
|
||||
|
||||
SHOW_LLDP_NEIGHBOR_INFO = """\
|
||||
Port Device ID Port ID management address Port Description System Name
|
||||
---- ------------ -------- ------------------ ---------------- -----------
|
||||
Gi1/0/1 00-AA-BB-CC-DD-EE Gi0/1 10.0.0.1 uplink core-sw-01
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestGetFacts:
|
||||
def test_returns_required_keys(self, driver):
|
||||
driver.device.send_command.return_value = SHOW_SYSTEM_INFO
|
||||
driver._send_command = lambda cmd, **kw: SHOW_SYSTEM_INFO
|
||||
|
||||
# _get_interface_list needs show interface
|
||||
driver.device.send_command.side_effect = lambda cmd, **kw: (
|
||||
SHOW_SYSTEM_INFO if "system-info" in cmd else SHOW_INTERFACE
|
||||
)
|
||||
|
||||
facts = driver.get_facts()
|
||||
for key in ("vendor", "model", "hostname", "os_version", "serial_number",
|
||||
"uptime", "interface_list", "fqdn"):
|
||||
assert key in facts
|
||||
|
||||
def test_vendor(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_SYSTEM_INFO
|
||||
driver._get_interface_list = lambda: []
|
||||
facts = driver.get_facts()
|
||||
assert facts["vendor"] == "TP-Link"
|
||||
|
||||
def test_uptime_parsing(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_SYSTEM_INFO
|
||||
driver._get_interface_list = lambda: []
|
||||
facts = driver.get_facts()
|
||||
expected = 5 * 86400 + 2 * 3600 + 35 * 60 + 16
|
||||
assert facts["uptime"] == float(expected)
|
||||
|
||||
def test_os_version(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_SYSTEM_INFO
|
||||
driver._get_interface_list = lambda: []
|
||||
facts = driver.get_facts()
|
||||
assert "2.0.7" in facts["os_version"]
|
||||
|
||||
|
||||
class TestGetInterfaces:
|
||||
def _mock_send(self, cmd):
|
||||
if "jumbo" in cmd:
|
||||
return SHOW_JUMBO
|
||||
if "configuration" in cmd:
|
||||
return SHOW_INTERFACE_CONFIG
|
||||
return SHOW_INTERFACE_STATUS
|
||||
|
||||
def test_interface_count(self, driver):
|
||||
driver._send_command = self._mock_send
|
||||
ifaces = driver.get_interfaces()
|
||||
assert len(ifaces) == 2
|
||||
|
||||
def test_is_up_and_enabled(self, driver):
|
||||
driver._send_command = self._mock_send
|
||||
ifaces = driver.get_interfaces()
|
||||
gi1 = ifaces["Gi1/0/1"]
|
||||
assert gi1["is_up"] is True
|
||||
assert gi1["is_enabled"] is True
|
||||
gi2 = ifaces["Gi1/0/2"]
|
||||
assert gi2["is_up"] is False
|
||||
|
||||
def test_speed(self, driver):
|
||||
driver._send_command = self._mock_send
|
||||
ifaces = driver.get_interfaces()
|
||||
assert ifaces["Gi1/0/1"]["speed"] == 1000.0
|
||||
|
||||
def test_description(self, driver):
|
||||
driver._send_command = self._mock_send
|
||||
ifaces = driver.get_interfaces()
|
||||
assert ifaces["Gi1/0/1"]["description"] == "uplink"
|
||||
|
||||
|
||||
class TestGetArpTable:
|
||||
def test_entry_count(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_ARP
|
||||
table = driver.get_arp_table()
|
||||
assert len(table) == 2
|
||||
|
||||
def test_entry_structure(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_ARP
|
||||
entry = driver.get_arp_table()[0]
|
||||
for key in ("interface", "mac", "ip", "age"):
|
||||
assert key in entry
|
||||
|
||||
def test_ip_value(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_ARP
|
||||
ips = {e["ip"] for e in driver.get_arp_table()}
|
||||
assert "192.168.0.100" in ips
|
||||
assert "192.168.0.254" in ips
|
||||
|
||||
def test_interface_value(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_ARP
|
||||
interfaces = {e["interface"] for e in driver.get_arp_table()}
|
||||
assert "VLAN8" in interfaces
|
||||
|
||||
|
||||
class TestGetMacAddressTable:
|
||||
def test_entry_count(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_MAC
|
||||
table = driver.get_mac_address_table()
|
||||
assert len(table) == 2
|
||||
|
||||
def test_static_flag(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_MAC
|
||||
entries = {e["mac"]: e for e in driver.get_mac_address_table()}
|
||||
assert entries["FF:FF:FF:FF:FF:FF"]["static"] is True
|
||||
assert entries["00:50:56:A1:B2:C3"]["static"] is False
|
||||
|
||||
def test_vlan_value(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_MAC
|
||||
entries = {e["mac"]: e for e in driver.get_mac_address_table()}
|
||||
assert entries["00:50:56:A1:B2:C3"]["vlan"] == 8
|
||||
|
||||
|
||||
class TestGetVlans:
|
||||
def test_vlan_count(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_VLAN
|
||||
vlans = driver.get_vlans()
|
||||
assert len(vlans) == 2
|
||||
|
||||
def test_vlan_name(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_VLAN
|
||||
vlans = driver.get_vlans()
|
||||
assert vlans["1"]["name"] == "Default"
|
||||
assert vlans["10"]["name"] == "Management"
|
||||
|
||||
def test_port_expansion(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_VLAN
|
||||
vlans = driver.get_vlans()
|
||||
assert "Gi1/0/1" in vlans["1"]["interfaces"]
|
||||
assert "Gi1/0/2" in vlans["1"]["interfaces"]
|
||||
|
||||
|
||||
class TestGetLldpNeighbors:
|
||||
def test_returns_neighbor(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_LLDP_NEIGHBOR_INFO
|
||||
neighbors = driver.get_lldp_neighbors()
|
||||
assert "Gi1/0/1" in neighbors
|
||||
assert neighbors["Gi1/0/1"][0]["hostname"] == "core-sw-01"
|
||||
assert neighbors["Gi1/0/1"][0]["port"] == "Gi0/1"
|
||||
|
||||
|
||||
class TestGetLldpNeighborsDetail:
|
||||
def test_returns_detail_keys(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_LLDP_NEIGHBOR_INFO
|
||||
details = driver.get_lldp_neighbors_detail()
|
||||
entry = details["Gi1/0/1"][0]
|
||||
for key in ("remote_chassis_id", "remote_system_name", "remote_port"):
|
||||
assert key in entry
|
||||
|
||||
def test_system_name_parsed(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_LLDP_NEIGHBOR_INFO
|
||||
details = driver.get_lldp_neighbors_detail()
|
||||
assert details["Gi1/0/1"][0]["remote_system_name"] == "core-sw-01"
|
||||
|
||||
def test_chassis_id_parsed(self, driver):
|
||||
driver._send_command = lambda cmd: SHOW_LLDP_NEIGHBOR_INFO
|
||||
details = driver.get_lldp_neighbors_detail()
|
||||
assert details["Gi1/0/1"][0]["remote_chassis_id"] == "00-AA-BB-CC-DD-EE"
|
||||
|
||||
|
||||
class TestIsAlive:
|
||||
def test_returns_false_when_device_is_none(self, driver):
|
||||
driver.device = None
|
||||
assert driver.is_alive() == {"is_alive": False}
|
||||
|
||||
def test_returns_true_when_transport_active(self, driver):
|
||||
driver.device.remote_conn.transport.is_active.return_value = True
|
||||
assert driver.is_alive() == {"is_alive": True}
|
||||
|
||||
|
||||
class TestUptimeParser:
|
||||
@pytest.mark.parametrize("uptime_str,expected", [
|
||||
("0 day(s) 0 hour(s) 0 min(s) 0 sec(s)", 0),
|
||||
("1 day(s) 0 hour(s) 0 min(s) 0 sec(s)", 86400),
|
||||
("5 day(s) 2 hour(s) 35 min(s) 16 sec(s)", 5 * 86400 + 2 * 3600 + 35 * 60 + 16),
|
||||
])
|
||||
def test_parse_uptime_seconds(self, uptime_str, expected):
|
||||
result = TPLinkJetstreamDriver._parse_uptime_seconds(uptime_str)
|
||||
assert result == float(expected)
|
||||
|
||||
|
||||
class TestParseVlanPorts:
|
||||
def test_single_port(self):
|
||||
assert TPLinkJetstreamDriver._parse_vlan_ports("Gi1/0/1") == ["Gi1/0/1"]
|
||||
|
||||
def test_range(self):
|
||||
result = TPLinkJetstreamDriver._parse_vlan_ports("Gi1/0/1-4")
|
||||
assert result == ["Gi1/0/1", "Gi1/0/2", "Gi1/0/3", "Gi1/0/4"]
|
||||
|
||||
def test_comma_separated(self):
|
||||
result = TPLinkJetstreamDriver._parse_vlan_ports("Gi1/0/1, Gi1/0/5")
|
||||
assert result == ["Gi1/0/1", "Gi1/0/5"]
|
||||
|
||||
def test_tg_ut_prefixes(self):
|
||||
result = TPLinkJetstreamDriver._parse_vlan_ports("UT: Gi1/0/1-2 TG: Gi1/0/9")
|
||||
assert "Gi1/0/1" in result
|
||||
assert "Gi1/0/2" in result
|
||||
assert "Gi1/0/9" in result
|
||||
Reference in New Issue
Block a user