Files
napalm-proxmox/tests/test_utils.py
T
2026-05-29 09:24:39 +02:00

225 lines
6.9 KiB
Python

"""Unit tests for napalm_proxmox.utils."""
from __future__ import annotations
import pytest
from napalm_proxmox import utils
class TestNormalizeMAC:
def test_colon_upper(self):
assert utils.normalize_mac("AA:BB:CC:DD:EE:FF") == "aa:bb:cc:dd:ee:ff"
def test_dash_separated(self):
assert utils.normalize_mac("AA-BB-CC-DD-EE-FF") == "aa:bb:cc:dd:ee:ff"
def test_lowercase_passthrough(self):
assert utils.normalize_mac("aa:bb:cc:dd:ee:ff") == "aa:bb:cc:dd:ee:ff"
def test_empty(self):
assert utils.normalize_mac("") == ""
class TestParseCIDR:
def test_ipv4(self):
ip, plen = utils.parse_cidr("192.168.1.1/24")
assert ip == "192.168.1.1"
assert plen == 24
def test_ipv6(self):
ip, plen = utils.parse_cidr("2001:db8::1/64")
assert ip == "2001:db8::1"
assert plen == 64
def test_no_prefix(self):
ip, plen = utils.parse_cidr("10.0.0.1")
assert ip == "10.0.0.1"
assert plen == 32
def test_host_route(self):
ip, plen = utils.parse_cidr("10.0.0.1/32")
assert plen == 32
class TestPrefixLength:
def test_slash24(self):
assert utils.prefix_length("10.0.0.0/24") == 24
def test_slash_16(self):
assert utils.prefix_length("192.168.0.0/16") == 16
def test_no_slash(self):
assert utils.prefix_length("10.0.0.1") == 32
class TestAddressesFromNodeNetwork:
def test_address_and_netmask(self):
data = {"address": "10.0.0.1", "netmask": "255.255.255.0"}
result = utils.addresses_from_node_network(data)
assert "ipv4" in result
assert "10.0.0.1" in result["ipv4"]
assert result["ipv4"]["10.0.0.1"]["prefix_length"] == 24
def test_cidr_ipv4(self):
data = {"cidr": "10.0.0.1/24"}
result = utils.addresses_from_node_network(data)
assert "ipv4" in result
assert "10.0.0.1" in result["ipv4"]
def test_cidr_ipv6(self):
data = {"cidr6": "2001:db8::1/64"}
result = utils.addresses_from_node_network(data)
assert "ipv6" in result
assert "2001:db8::1" in result["ipv6"]
assert result["ipv6"]["2001:db8::1"]["prefix_length"] == 64
def test_both_ipv4_and_ipv6(self):
data = {"cidr": "10.0.0.1/24", "cidr6": "2001:db8::1/64"}
result = utils.addresses_from_node_network(data)
assert "ipv4" in result
assert "ipv6" in result
def test_empty_input(self):
result = utils.addresses_from_node_network({})
assert result == {}
class TestIsOVSInterface:
def test_ovs_bridge(self):
assert utils.is_ovs_interface({"type": "OVSBridge"}) is True
def test_ovs_bond(self):
assert utils.is_ovs_interface({"type": "OVSBond"}) is True
def test_ovs_int_port(self):
assert utils.is_ovs_interface({"type": "OVSIntPort"}) is True
def test_linux_bridge(self):
assert utils.is_ovs_interface({"type": "bridge"}) is False
def test_eth(self):
assert utils.is_ovs_interface({"type": "eth"}) is False
def test_no_type_key(self):
assert utils.is_ovs_interface({}) is False
class TestIsSDNVNet:
def test_vnet_pattern(self):
assert utils.is_sdn_vnet("vnet0") is True
assert utils.is_sdn_vnet("vnet99") is True
def test_non_vnet(self):
assert utils.is_sdn_vnet("eth0") is False
assert utils.is_sdn_vnet("vmbr0") is False
def test_vnet_with_suffix(self):
assert utils.is_sdn_vnet("vnet0sub") is False
class TestSpeedMbps:
def test_speed_present(self):
assert utils.speed_mbps({"speed": "1000"}) == 1000.0
def test_speed_mbit_suffix(self):
# Some entries may have "Mbit" unit in the string — handled by parsing
assert utils.speed_mbps({"speed": "10000"}) == 10000.0
def test_no_speed(self):
assert utils.speed_mbps({}) == -1.0
def test_speed_non_numeric(self):
assert utils.speed_mbps({"speed": "unknown"}) == -1.0
class TestSDNZoneToNetworkInstance:
def test_vlan_zone(self):
zone = {"zone": "z1", "type": "vlan", "mtu": 1500}
result = utils.sdn_zone_to_network_instance(zone)
assert result["type"] == "L2VPN"
assert result["name"] == "z1"
def test_evpn_zone(self):
zone = {"zone": "z2", "type": "evpn", "peers": "10.0.0.1", "rt": 10001}
result = utils.sdn_zone_to_network_instance(zone)
assert result["type"] == "L3VRF"
def test_vxlan_zone(self):
zone = {"zone": "z3", "type": "vxlan", "mtu": 9000}
result = utils.sdn_zone_to_network_instance(zone)
assert result["type"] == "L2VPN"
def test_simple_zone(self):
zone = {"zone": "z4", "type": "simple"}
result = utils.sdn_zone_to_network_instance(zone)
assert result["type"] == "L3VRF"
def test_unknown_zone_type(self):
zone = {"zone": "z5", "type": "qinq"}
result = utils.sdn_zone_to_network_instance(zone)
assert result["type"] == "L2VPN"
def test_result_has_interfaces(self):
zone = {"zone": "z1", "type": "vlan"}
result = utils.sdn_zone_to_network_instance(zone)
assert "interfaces" in result
class TestParseARPOutput:
ARP_N = (
"Address HWtype HWaddress Flags Iface\n"
"10.0.0.254 ether aa:bb:cc:dd:ee:ff C eth0\n"
"10.0.0.10 ether 11:22:33:44:55:66 C vmbr0\n"
"? (10.0.0.20) at <incomplete> on eth0\n"
)
def test_parses_two_entries(self):
result = utils.parse_arp_output(self.ARP_N)
assert len(result) == 2
def test_entry_fields(self):
result = utils.parse_arp_output(self.ARP_N)
assert result[0]["ip"] == "10.0.0.254"
assert result[0]["mac"] == "aa:bb:cc:dd:ee:ff"
assert result[0]["interface"] == "eth0"
def test_skips_incomplete(self):
result = utils.parse_arp_output(self.ARP_N)
ips = {e["ip"] for e in result}
assert "10.0.0.20" not in ips
def test_empty_input(self):
result = utils.parse_arp_output("")
assert result == []
class TestParseOVSVsctlShow:
RAW = (
" Bridge vmbr1\n"
" Port eth1\n"
" Port vnet0\n"
" Port vmbr1\n"
" Bridge vmbr2\n"
" Port eth2\n"
" Port vmbr2\n"
)
def test_finds_both_bridges(self):
result = utils.parse_ovs_vsctl_show(self.RAW)
assert "vmbr1" in result
assert "vmbr2" in result
def test_ports_exclude_self(self):
result = utils.parse_ovs_vsctl_show(self.RAW)
assert "vmbr1" not in result["vmbr1"]["ports"]
assert "vmbr2" not in result["vmbr2"]["ports"]
def test_ports_included(self):
result = utils.parse_ovs_vsctl_show(self.RAW)
assert "eth1" in result["vmbr1"]["ports"]
assert "eth2" in result["vmbr2"]["ports"]
def test_empty_input(self):
result = utils.parse_ovs_vsctl_show("")
assert result == {}