Closes netork#115. The suite had been red long enough that it stopped being read. Four of the fourteen failures were the tests being right. `interfaces_mixin.py` used `re.match` without importing `re`, so `get_mac_address_table` raised NameError against any node with a Linux bridge. The tests never reached that line: they mocked the API call underneath `_exec_ssh_command`, which takes two positional arguments where the doubles accepted one, and which base64-wraps the command — so a fixture keyed on "bridge fdb" appearing in the text matched nothing and the helper returned "". They mock `_exec_ssh_command` itself now, which is the driver's own seam. `is_alive` called `_resolve_node()`, which returns early without touching the API whenever a node was configured through optional_args. A dead connection reported itself alive. It probes `GET /version` now. The documented `realm` optional_arg was read into `self._realm` in `__init__` and then never used. Proxmox authenticates against "<user>@<realm>" and rejects a bare username, so the option had no effect and callers had to know to type the realm themselves. `get_vlans` filtered out entries with no member ports on one return path while the OVS path returned them, so a configured SDN VNet was visible or invisible depending on which branch ran. A VNet exists on the node whether or not anything is attached to it, and netOrk's VLAN discovery reads this. `get_ipv6_neighbors_table` was simply missing and fell through to NAPALM's stub; it is implemented against `ip -6 neigh show`, dropping FAILED entries. The rest were stale tests. The DNS fixture put an FQDN where a search domain belongs, which made `get_facts` build "pve1.pve1.example.com" and look like a driver bug. The LLDP fixture was a simplified shape that real `lldpcli show neighbors summary` does not produce — the parser matches on the ", via: LLDP" that follows the interface name. And `test_bridge_vlan_show_parsing` covered a fallback that was replaced by VM-config scanning, asserting an "interfaces" key this method has never returned; it is now a test of the fallback that exists.
104 lines
3.9 KiB
Python
104 lines
3.9 KiB
Python
"""Tests for SDN-related methods: get_vlans, get_network_instances."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from tests.conftest import _build_mock_api, SDN_ZONES, SDN_VNETS
|
|
|
|
|
|
class TestGetVlans:
|
|
def test_sdn_vnets_appear_as_vlans(self, driver):
|
|
result = driver.get_vlans()
|
|
# vnet0 tag=10, vnet1 tag=20
|
|
assert "10" in result
|
|
assert "20" in result
|
|
|
|
def test_vlan_name_is_vnet_id(self, driver):
|
|
result = driver.get_vlans()
|
|
assert result["10"]["name"] == "vnet0"
|
|
assert result["20"]["name"] == "vnet1"
|
|
|
|
def test_vlan_100000_for_vxlan(self, driver):
|
|
result = driver.get_vlans()
|
|
assert "100000" in result
|
|
|
|
def test_membership_derived_from_vm_configs(self, driver):
|
|
"""Without OVS ports, VLAN membership comes from each VM's netN config.
|
|
|
|
This replaces a test for a `bridge vlan show` fallback that no longer
|
|
exists — it also asserted an "interfaces" key this method has never
|
|
produced, so it could not have passed against any version of the code.
|
|
"""
|
|
node = driver._node_api()
|
|
node.qemu.get.return_value = [{"vmid": 100}]
|
|
node.lxc.get.return_value = []
|
|
node.qemu.return_value.config.get.return_value = {
|
|
"net0": "virtio=AA:BB:CC:DD:EE:FF,bridge=vmbr0,tag=10",
|
|
}
|
|
|
|
result = driver.get_vlans()
|
|
assert "vmbr0" in result["10"]["untagged"]
|
|
|
|
def test_configured_vnets_appear_even_without_members(self, driver):
|
|
"""An SDN VNet exists on the node whether or not anything is attached.
|
|
|
|
Entries with no member ports used to be filtered out of this one return
|
|
path while the OVS path returned them, so a configured VLAN was visible
|
|
or invisible depending on which branch ran.
|
|
"""
|
|
result = driver.get_vlans()
|
|
assert result["20"]["name"] == "vnet1"
|
|
assert result["20"]["untagged"] == []
|
|
|
|
def test_empty_sdn_returns_dict(self):
|
|
from unittest.mock import patch
|
|
from napalm_proxmox.driver import ProxmoxDriver
|
|
from tests.conftest import _build_mock_api
|
|
|
|
mock_api = _build_mock_api(sdn_vnets=[], sdn_zones=[])
|
|
drv = ProxmoxDriver("pve1", "root", "secret", optional_args={"verify_ssl": False})
|
|
with patch("napalm_proxmox.driver.ProxmoxAPI", return_value=mock_api):
|
|
drv.open()
|
|
result = drv.get_vlans()
|
|
assert isinstance(result, dict)
|
|
|
|
|
|
class TestGetNetworkInstances:
|
|
def test_default_instance_always_present(self, driver):
|
|
result = driver.get_network_instances()
|
|
assert "default" in result
|
|
assert result["default"]["type"] == "DEFAULT_INSTANCE"
|
|
|
|
def test_sdn_zones_as_instances(self, driver):
|
|
result = driver.get_network_instances()
|
|
assert "zone-vlan" in result
|
|
assert "zone-vxlan" in result
|
|
assert "zone-evpn" in result
|
|
|
|
def test_zone_type_mapping(self, driver):
|
|
result = driver.get_network_instances()
|
|
assert result["zone-vlan"]["type"] == "L2VPN"
|
|
assert result["zone-evpn"]["type"] == "L3VRF"
|
|
|
|
def test_vnet_appears_in_zone_interfaces(self, driver):
|
|
result = driver.get_network_instances()
|
|
zone_ifaces = result["zone-vlan"]["interfaces"]["interface"]
|
|
assert "vnet0" in zone_ifaces
|
|
assert "vnet1" in zone_ifaces
|
|
|
|
def test_filter_by_name(self, driver):
|
|
result = driver.get_network_instances(name="zone-vlan")
|
|
assert "zone-vlan" in result
|
|
assert "zone-vxlan" not in result
|
|
|
|
def test_evpn_route_distinguisher(self, driver):
|
|
result = driver.get_network_instances()
|
|
rd = result["zone-evpn"]["state"]["route_distinguisher"]
|
|
assert rd == 10001
|
|
|
|
def test_default_interfaces_include_node_ifaces(self, driver):
|
|
result = driver.get_network_instances()
|
|
default_ifaces = result["default"]["interfaces"]["interface"]
|
|
assert "eth0" in default_ifaces
|
|
assert "vmbr0" in default_ifaces
|