summaryrefslogtreecommitdiffstatshomepage
path: root/tests/test_canonical_bond.py
blob: d9f097cba400a6ee10333daf481e91eed752de0f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import shutil
import subprocess
import unittest
from unittest.mock import patch

from scripts import canonical_bond as bond


class BondTests(unittest.TestCase):
    @unittest.skipUnless(shutil.which("nmcli"), "nmcli is in the Nix development shell")
    def test_networkmanager_accepts_offline_profiles(self):
        config = bond.keyfile(bond.bond_profile())
        self.assertEqual(config["bond"]["fail_over_mac"], "active")
        for kind in ("ethernet", "wifi"):
            args = ["--offline", "con", "add", "type", kind, "ifname", "test0"]
            if kind == "wifi":
                args.extend(["ssid", "test"])
            profile = bond.port_profile(
                bond.nmcli(*args),
                kind,
                "74019c2b-26bb-42d9-a775-b715c70bbb58",
                100 if kind == "ethernet" else 0,
            )
            config = bond.keyfile(profile)
            self.assertNotIn("ipv4", config)
            self.assertNotIn("ipv6", config)
            self.assertEqual(config["connection"]["autoconnect"], "false")

    def test_activation_schedules_recovery_before_network_changes(self):
        script = bond.activation_commands(
            [{"original": "old", "uuid": "new"}], active={"old"}
        )
        self.assertLess(script.index("systemd-run"), script.index("install -m"))
        self.assertIn("--on-active=5m", script)
        self.assertIn("connection.autoconnect no", script)
        self.assertIn("con down uuid old", script)
        self.assertLess(script.index("con down uuid old"), script.index("con up uuid"))

    def test_recovery_restores_original_autoconnect_and_active_profiles(self):
        with patch.object(bond, "nmcli", return_value="old"):
            script = bond.recovery_commands(
                [{"original": "old", "uuid": "new", "autoconnect": "no"}]
            )
        self.assertIn("con mod uuid old connection.autoconnect no", script)
        self.assertIn("con up uuid old", script)
        self.assertNotIn("con delete uuid old", script)

    def test_bond_policy_and_identity(self):
        with patch.object(bond, "nmcli", return_value="profile") as command:
            self.assertEqual(bond.bond_profile(), "profile")
        args = command.call_args.args
        self.assertIn(
            "mode=active-backup,miimon=1000,fail_over_mac=active,primary_reselect=always",
            args,
        )
        self.assertEqual(args[args.index("ipv4.dhcp-client-id") + 1], "duid")
        self.assertEqual(args[args.index("ipv4.dhcp-iaid") + 1], "1")
        self.assertEqual(args[args.index("connection.autoconnect") + 1], "no")

    def test_ports_keep_authentication_but_remove_ip_settings(self):
        source = "[connection]\nid=wifi\nuuid=original\ntype=wifi\n[ipv4]\nmethod=auto\n[ipv6]\nmethod=auto\n[wifi-security]\nkey-mgmt=wpa-psk\npsk=example\n"
        with patch.object(bond, "nmcli", return_value="converted") as command:
            bond.port_profile(source, "wifi", "new", 0)
        args = command.call_args.args
        data = command.call_args.kwargs["input"]
        self.assertIn("psk=example", data)
        self.assertNotIn("[ipv4]", data)
        self.assertNotIn("[ipv6]", data)
        self.assertEqual(args[args.index("connection.controller") + 1], bond.BOND_UUID)
        self.assertEqual(
            args[args.index("802-11-wireless.cloned-mac-address") + 1], "permanent"
        )

    def test_ethernet_has_priority_over_wifi(self):
        with patch.object(bond, "nmcli", return_value="converted") as command:
            bond.port_profile("[connection]\ntype=ethernet\n", "ethernet", "new", 100)
        args = command.call_args.args
        self.assertEqual(args[args.index("bond-port.prio") + 1], "100")

    def test_rejects_other_profile_types(self):
        with self.assertRaises(ValueError):
            bond.port_profile("[connection]\ntype=bridge\n", "bridge", "new", 0)

    def test_does_not_drop_automatic_vpn_connections(self):
        with self.assertRaises(ValueError):
            bond.port_profile(
                "[connection]\ntype=ethernet\nsecondaries=vpn;\n",
                "ethernet",
                "new",
                100,
            )

    def test_generated_shell_scripts_parse(self):
        ports = [{"original": "old", "uuid": "new", "autoconnect": "yes"}]
        with patch.object(bond, "nmcli", return_value="old"):
            scripts = [bond.activation_commands(ports), bond.recovery_commands(ports)]
        for script in scripts:
            subprocess.run(["sh", "-n"], input=script, text=True, check=True)
            if shutil.which("shellcheck"):
                subprocess.run(
                    ["shellcheck", "-s", "sh", "-"], input=script, text=True, check=True
                )