Skip to content

Commit 07b2631

Browse files
committed
test: added tests to confirm solution
1 parent 941ea7e commit 07b2631

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# tests/unittests/net/test_net_freebsd.py
2+
#
3+
# FreeBSD-specific networking tests
4+
#
5+
# These tests validate Azure + FreeBSD edge cases involving
6+
# duplicate MAC addresses, Hyper-V synthetic NICs (hn*),
7+
# accelerated VFs (mce*), and deterministic primary NIC selection.
8+
9+
import logging
10+
from unittest import mock
11+
12+
from cloudinit import net
13+
14+
LOG = logging.getLogger(__name__)
15+
16+
17+
@mock.patch("cloudinit.net.util.is_FreeBSD", return_value=True)
18+
@mock.patch("cloudinit.net.subp.subp")
19+
def test_freebsd_duplicate_mac_preserves_first_interface(
20+
m_subp, _is_freebsd, caplog
21+
):
22+
"""Duplicate MACs on FreeBSD must not drop the synthetic hn* NIC.
23+
24+
Azure exposes hn* (synthetic) and mce* (accelerated VF) interfaces
25+
with the same MAC address. The first-discovered interface must be
26+
preserved and the duplicate logged.
27+
"""
28+
caplog.set_level(logging.DEBUG)
29+
30+
def subp_side_effect(cmd, *args, **kwargs):
31+
if cmd == ["ifconfig", "-a", "ether"]:
32+
return (
33+
"\n\n".join(
34+
[
35+
"\n".join(
36+
[
37+
"hn0: flags=8843"
38+
"<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST>",
39+
"\tether aa:bb:cc:dd:ee:ff",
40+
]
41+
),
42+
"\n".join(
43+
[
44+
"mce0: flags=8843"
45+
"<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST>",
46+
"\tether aa:bb:cc:dd:ee:ff",
47+
]
48+
),
49+
]
50+
),
51+
"",
52+
)
53+
raise AssertionError(f"Unexpected subp call: {cmd}")
54+
55+
m_subp.side_effect = subp_side_effect
56+
57+
interfaces = net.get_interfaces_by_mac_on_freebsd()
58+
59+
assert "hn0" in interfaces.values()
60+
assert "Duplicate MAC" in caplog.text
61+
62+
63+
@mock.patch("cloudinit.net.util.is_FreeBSD", return_value=True)
64+
@mock.patch("cloudinit.net.subp.subp")
65+
def test_freebsd_get_devicelist_returns_all_interfaces(m_subp, _is_freebsd):
66+
"""FreeBSD device discovery must not drop interfaces due to MAC collisions.
67+
68+
get_devicelist() should enumerate all interfaces directly rather than
69+
relying on MAC-keyed maps.
70+
"""
71+
m_subp.return_value = ("hn0 mce0 lo0", "")
72+
73+
devices = net.get_devicelist()
74+
75+
assert "hn0" in devices
76+
assert "mce0" in devices
77+
assert "lo0" in devices
78+
79+
80+
@mock.patch("cloudinit.net.util.is_FreeBSD", return_value=True)
81+
def test_freebsd_azure_filters_hyperv_vf_when_synthetic_present(
82+
_is_freebsd, caplog
83+
):
84+
"""On Azure FreeBSD, accelerated VFs (mce*) must be ignored when a
85+
synthetic hn* interface with the same MAC is present.
86+
"""
87+
caplog.set_level(logging.DEBUG)
88+
89+
interfaces = [
90+
("hn0", "aa:bb:cc:dd:ee:ff", "hn", ""),
91+
("mce0", "aa:bb:cc:dd:ee:ff", "mce", ""),
92+
]
93+
94+
filtered = list(interfaces)
95+
96+
net.filter_hyperv_vf_with_synthetic_interface(LOG.debug, filtered)
97+
98+
names = [iface[0] for iface in filtered]
99+
100+
assert "hn0" in names
101+
assert "mce0" not in names
102+
103+
assert (
104+
"Ignoring 'mce0' VF interface due to synthetic hn interface 'hn0'"
105+
in caplog.text
106+
)
107+
108+
109+
@mock.patch("cloudinit.net.util.is_FreeBSD", return_value=True)
110+
@mock.patch("cloudinit.net.subp.subp")
111+
@mock.patch("cloudinit.net.get_interfaces_by_mac")
112+
def test_freebsd_prefers_hn0_as_primary_interface(
113+
m_get_by_mac, m_subp, _is_freebsd
114+
):
115+
m_get_by_mac.return_value = {
116+
"aa:aa:aa:aa:aa:01": "mce0",
117+
"aa:aa:aa:aa:aa:02": "hn1",
118+
"aa:aa:aa:aa:aa:03": "hn0",
119+
}
120+
121+
# Order returned by ifconfig -l -u ether
122+
m_subp.return_value = ("mce0 hn1 hn0", "")
123+
124+
ordered = net.find_candidate_nics_on_freebsd()
125+
126+
assert ordered[0] == "hn0"

0 commit comments

Comments
 (0)