Blame cloudinit/distros/tests/test_networking.py

Packit Service 751c4a
from unittest import mock
Packit Service 751c4a
Packit Service 751c4a
import pytest
Packit Service 751c4a
Packit Service 751c4a
from cloudinit import net
Packit Service 751c4a
from cloudinit.distros.networking import (
Packit Service 751c4a
    BSDNetworking,
Packit Service 751c4a
    LinuxNetworking,
Packit Service 751c4a
    Networking,
Packit Service 751c4a
)
Packit Service 751c4a
Packit Service 751c4a
# See https://docs.pytest.org/en/stable/example
Packit Service 751c4a
# /parametrize.html#parametrizing-conditional-raising
Packit Service 751c4a
from contextlib import ExitStack as does_not_raise
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
@pytest.yield_fixture
Packit Service 751c4a
def generic_networking_cls():
Packit Service 751c4a
    """Returns a direct Networking subclass which errors on /sys usage.
Packit Service 751c4a
Packit Service 751c4a
    This enables the direct testing of functionality only present on the
Packit Service 751c4a
    ``Networking`` super-class, and provides a check on accidentally using /sys
Packit Service 751c4a
    in that context.
Packit Service 751c4a
    """
Packit Service 751c4a
Packit Service 751c4a
    class TestNetworking(Networking):
Packit Service 751c4a
        def is_physical(self, *args, **kwargs):
Packit Service 751c4a
            raise NotImplementedError
Packit Service 751c4a
Packit Service 751c4a
        def settle(self, *args, **kwargs):
Packit Service 751c4a
            raise NotImplementedError
Packit Service 751c4a
Packit Service 751c4a
    error = AssertionError("Unexpectedly used /sys in generic networking code")
Packit Service 751c4a
    with mock.patch(
Packit Service 751c4a
        "cloudinit.net.get_sys_class_path", side_effect=error,
Packit Service 751c4a
    ):
Packit Service 751c4a
        yield TestNetworking
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
@pytest.yield_fixture
Packit Service 751c4a
def sys_class_net(tmpdir):
Packit Service 751c4a
    sys_class_net_path = tmpdir.join("sys/class/net")
Packit Service 751c4a
    sys_class_net_path.ensure_dir()
Packit Service 751c4a
    with mock.patch(
Packit Service 751c4a
        "cloudinit.net.get_sys_class_path",
Packit Service 751c4a
        return_value=sys_class_net_path.strpath + "/",
Packit Service 751c4a
    ):
Packit Service 751c4a
        yield sys_class_net_path
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
class TestBSDNetworkingIsPhysical:
Packit Service 751c4a
    def test_raises_notimplementederror(self):
Packit Service 751c4a
        with pytest.raises(NotImplementedError):
Packit Service 751c4a
            BSDNetworking().is_physical("eth0")
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
class TestLinuxNetworkingIsPhysical:
Packit Service 751c4a
    def test_returns_false_by_default(self, sys_class_net):
Packit Service 751c4a
        assert not LinuxNetworking().is_physical("eth0")
Packit Service 751c4a
Packit Service 751c4a
    def test_returns_false_if_devname_exists_but_not_physical(
Packit Service 751c4a
        self, sys_class_net
Packit Service 751c4a
    ):
Packit Service 751c4a
        devname = "eth0"
Packit Service 751c4a
        sys_class_net.join(devname).mkdir()
Packit Service 751c4a
        assert not LinuxNetworking().is_physical(devname)
Packit Service 751c4a
Packit Service 751c4a
    def test_returns_true_if_device_is_physical(self, sys_class_net):
Packit Service 751c4a
        devname = "eth0"
Packit Service 751c4a
        device_dir = sys_class_net.join(devname)
Packit Service 751c4a
        device_dir.mkdir()
Packit Service 751c4a
        device_dir.join("device").write("")
Packit Service 751c4a
Packit Service 751c4a
        assert LinuxNetworking().is_physical(devname)
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
class TestBSDNetworkingSettle:
Packit Service 751c4a
    def test_settle_doesnt_error(self):
Packit Service 751c4a
        # This also implicitly tests that it doesn't use subp.subp
Packit Service 751c4a
        BSDNetworking().settle()
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
@pytest.mark.usefixtures("sys_class_net")
Packit Service 751c4a
@mock.patch("cloudinit.distros.networking.util.udevadm_settle", autospec=True)
Packit Service 751c4a
class TestLinuxNetworkingSettle:
Packit Service 751c4a
    def test_no_arguments(self, m_udevadm_settle):
Packit Service 751c4a
        LinuxNetworking().settle()
Packit Service 751c4a
Packit Service 751c4a
        assert [mock.call(exists=None)] == m_udevadm_settle.call_args_list
Packit Service 751c4a
Packit Service 751c4a
    def test_exists_argument(self, m_udevadm_settle):
Packit Service 751c4a
        LinuxNetworking().settle(exists="ens3")
Packit Service 751c4a
Packit Service 751c4a
        expected_path = net.sys_dev_path("ens3")
Packit Service 751c4a
        assert [
Packit Service 751c4a
            mock.call(exists=expected_path)
Packit Service 751c4a
        ] == m_udevadm_settle.call_args_list
Packit Service 751c4a
Packit Service 751c4a
Packit Service 751c4a
class TestNetworkingWaitForPhysDevs:
Packit Service 751c4a
    @pytest.fixture
Packit Service 751c4a
    def wait_for_physdevs_netcfg(self):
Packit Service 751c4a
        """This config is shared across all the tests in this class."""
Packit Service 751c4a
Packit Service 751c4a
        def ethernet(mac, name, driver=None, device_id=None):
Packit Service 751c4a
            v2_cfg = {"set-name": name, "match": {"macaddress": mac}}
Packit Service 751c4a
            if driver:
Packit Service 751c4a
                v2_cfg["match"].update({"driver": driver})
Packit Service 751c4a
            if device_id:
Packit Service 751c4a
                v2_cfg["match"].update({"device_id": device_id})
Packit Service 751c4a
Packit Service 751c4a
            return v2_cfg
Packit Service 751c4a
Packit Service 751c4a
        physdevs = [
Packit Service 751c4a
            ["aa:bb:cc:dd:ee:ff", "eth0", "virtio", "0x1000"],
Packit Service 751c4a
            ["00:11:22:33:44:55", "ens3", "e1000", "0x1643"],
Packit Service 751c4a
        ]
Packit Service 751c4a
        netcfg = {
Packit Service 751c4a
            "version": 2,
Packit Service 751c4a
            "ethernets": {args[1]: ethernet(*args) for args in physdevs},
Packit Service 751c4a
        }
Packit Service 751c4a
        return netcfg
Packit Service 751c4a
Packit Service 751c4a
    def test_skips_settle_if_all_present(
Packit Service 751c4a
        self, generic_networking_cls, wait_for_physdevs_netcfg,
Packit Service 751c4a
    ):
Packit Service 751c4a
        networking = generic_networking_cls()
Packit Service 751c4a
        with mock.patch.object(
Packit Service 751c4a
            networking, "get_interfaces_by_mac"
Packit Service 751c4a
        ) as m_get_interfaces_by_mac:
Packit Service 751c4a
            m_get_interfaces_by_mac.side_effect = iter(
Packit Service 751c4a
                [{"aa:bb:cc:dd:ee:ff": "eth0", "00:11:22:33:44:55": "ens3"}]
Packit Service 751c4a
            )
Packit Service 751c4a
            with mock.patch.object(
Packit Service 751c4a
                networking, "settle", autospec=True
Packit Service 751c4a
            ) as m_settle:
Packit Service 751c4a
                networking.wait_for_physdevs(wait_for_physdevs_netcfg)
Packit Service 751c4a
            assert 0 == m_settle.call_count
Packit Service 751c4a
Packit Service 751c4a
    def test_calls_udev_settle_on_missing(
Packit Service 751c4a
        self, generic_networking_cls, wait_for_physdevs_netcfg,
Packit Service 751c4a
    ):
Packit Service 751c4a
        networking = generic_networking_cls()
Packit Service 751c4a
        with mock.patch.object(
Packit Service 751c4a
            networking, "get_interfaces_by_mac"
Packit Service 751c4a
        ) as m_get_interfaces_by_mac:
Packit Service 751c4a
            m_get_interfaces_by_mac.side_effect = iter(
Packit Service 751c4a
                [
Packit Service 751c4a
                    {
Packit Service 751c4a
                        "aa:bb:cc:dd:ee:ff": "eth0"
Packit Service 751c4a
                    },  # first call ens3 is missing
Packit Service 751c4a
                    {
Packit Service 751c4a
                        "aa:bb:cc:dd:ee:ff": "eth0",
Packit Service 751c4a
                        "00:11:22:33:44:55": "ens3",
Packit Service 751c4a
                    },  # second call has both
Packit Service 751c4a
                ]
Packit Service 751c4a
            )
Packit Service 751c4a
            with mock.patch.object(
Packit Service 751c4a
                networking, "settle", autospec=True
Packit Service 751c4a
            ) as m_settle:
Packit Service 751c4a
                networking.wait_for_physdevs(wait_for_physdevs_netcfg)
Packit Service 751c4a
            m_settle.assert_called_with(exists="ens3")
Packit Service 751c4a
Packit Service 751c4a
    @pytest.mark.parametrize(
Packit Service 751c4a
        "strict,expectation",
Packit Service 751c4a
        [(True, pytest.raises(RuntimeError)), (False, does_not_raise())],
Packit Service 751c4a
    )
Packit Service 751c4a
    def test_retrying_and_strict_behaviour(
Packit Service 751c4a
        self,
Packit Service 751c4a
        strict,
Packit Service 751c4a
        expectation,
Packit Service 751c4a
        generic_networking_cls,
Packit Service 751c4a
        wait_for_physdevs_netcfg,
Packit Service 751c4a
    ):
Packit Service 751c4a
        networking = generic_networking_cls()
Packit Service 751c4a
        with mock.patch.object(
Packit Service 751c4a
            networking, "get_interfaces_by_mac"
Packit Service 751c4a
        ) as m_get_interfaces_by_mac:
Packit Service 751c4a
            m_get_interfaces_by_mac.return_value = {}
Packit Service 751c4a
Packit Service 751c4a
            with mock.patch.object(
Packit Service 751c4a
                networking, "settle", autospec=True
Packit Service 751c4a
            ) as m_settle:
Packit Service 751c4a
                with expectation:
Packit Service 751c4a
                    networking.wait_for_physdevs(
Packit Service 751c4a
                        wait_for_physdevs_netcfg, strict=strict
Packit Service 751c4a
                    )
Packit Service 751c4a
Packit Service 751c4a
        assert (
Packit Service 751c4a
            5 * len(wait_for_physdevs_netcfg["ethernets"])
Packit Service 751c4a
            == m_settle.call_count
Packit Service 751c4a
        )