#!/usr/bin/python3

# This file is part of Cockpit.
#
# Copyright (C) 2021 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.

import os
import sys

# import Cockpit's machinery for test VMs and its browser test API
TEST_DIR = os.path.dirname(__file__)
sys.path.append(os.path.join(TEST_DIR, "common"))
sys.path.append(os.path.join(os.path.dirname(TEST_DIR), "bots/machine"))

from machineslib import VirtualMachinesCase  # noqa
from testlib import no_retry_when_changed, nondestructive, test_main, wait  # noqa
from machinesxmls import TEST_NETWORK_XML, TEST_NETWORK4_XML  # noqa


@nondestructive
class TestMachinesNICs(VirtualMachinesCase):
    def deleteIface(self, iface):
        b = self.browser

        b.click(f"#delete-vm-subVmTest1-iface-{iface}")
        b.wait_in_text(".pf-c-modal-box .pf-c-modal-box__header .pf-c-modal-box__title", "Delete network interface")
        b.click(".pf-c-modal-box__footer button:contains(Delete)")

    @no_retry_when_changed
    def testVmNICs(self):
        b = self.browser
        m = self.machine

        self.createVm("subVmTest1")

        self.login_and_go("/machines")
        b.wait_in_text("body", "Virtual machines")
        self.waitVmRow("subVmTest1")

        b.wait_in_text("#vm-subVmTest1-state", "Running")

        # Wait for the dynamic IP address to be assigned before logging in
        # If the IP will change or get assigned after fetching the domain data the user will not see any
        # changes until they refresh the page, since there is not any signal associated with this change
        wait(lambda: "1" in self.machine.execute("virsh domifaddr subVmTest1  | grep 192.168.122. | wc -l"), delay=3)
        self.goToVmPage("subVmTest1")

        b.wait_in_text("#vm-subVmTest1-network-1-type", "network")
        b.wait_in_text("#vm-subVmTest1-network-1-source", "default")
        b.wait_in_text("#vm-subVmTest1-network-1-ipv4-address", "192.168.122.")
        b.wait_in_text("#vm-subVmTest1-network-1-state", "up")

        b.assert_pixels("#vm-subVmTest1-networks", "vm-details-nics-card", ignore=["#vm-subVmTest1-network-1-mac", "#vm-subVmTest1-network-1-ipv4-address"])

        # Test add network
        m.execute("virsh attach-interface --domain subVmTest1 --type network --source default --model virtio --mac 52:54:00:4b:73:5f --config --live")

        b.wait_in_text("#vm-subVmTest1-network-2-type", "network")
        b.wait_in_text("#vm-subVmTest1-network-2-source", "default")
        b.wait_in_text("#vm-subVmTest1-network-2-model", "virtio")
        b.wait_in_text("#vm-subVmTest1-network-2-mac", "52:54:00:4b:73:5f")
        b.wait_in_text("#vm-subVmTest1-network-2-ipv4-address", "192.168.122.")
        b.wait_in_text("#vm-subVmTest1-network-2-state", "up")

        # Test bridge network
        m.execute("virsh attach-interface --domain subVmTest1 --type bridge --source virbr0 --model virtio --mac 52:54:00:4b:73:5e --config --live")

        b.wait_in_text("#vm-subVmTest1-network-3-type", "bridge")
        b.wait_in_text("#vm-subVmTest1-network-3-source", "virbr0")
        b.wait_in_text("#vm-subVmTest1-network-3-ipv4-address", "192.168.122.")

    def testNICPlugingAndUnpluging(self):
        b = self.browser
        m = self.machine

        self.createVm("subVmTest1")

        self.login_and_go("/machines")
        b.wait_in_text("body", "Virtual machines")

        self.waitVmRow("subVmTest1")
        b.wait_in_text("#vm-subVmTest1-state", "Running")
        self.goToVmPage("subVmTest1")

        # Plug and unplug NICs
        def plugAndUnplugNICs():
            mac_address = b.text("#vm-subVmTest1-network-1-mac")

            b.wait_in_text("#vm-subVmTest1-network-1-state", "up")
            b.wait_in_text("#vm-subVmTest1-iface-1-unplug", "Unplug")

            # Click "Unplug"
            b.click("#vm-subVmTest1-iface-1-unplug")

            b.wait_in_text("#vm-subVmTest1-network-1-state", "down")
            b.wait_in_text("#vm-subVmTest1-iface-1-plug", "Plug")
            wait(lambda: "down" in m.execute(f"virsh domif-getlink subVmTest1 {mac_address}"))

            # Click "plug"
            b.click("#vm-subVmTest1-iface-1-plug")

            b.wait_in_text("#vm-subVmTest1-network-1-state", "up")
            b.wait_in_text("#vm-subVmTest1-iface-1-unplug", "Unplug")
            wait(lambda: "up" in m.execute(f"virsh domif-getlink subVmTest1 {mac_address}"))

        plugAndUnplugNICs()

        self.performAction("subVmTest1", "forceOff")

        # Check again after VM is off
        plugAndUnplugNICs()

    def testNICDelete(self):
        b = self.browser
        m = self.machine

        args = self.createVm("subVmTest1")

        self.login_and_go("/machines")
        b.wait_in_text("body", "Virtual machines")
        self.waitVmRow("subVmTest1")
        b.wait_in_text("#vm-subVmTest1-state", "Running")
        wait(lambda: "login as 'cirros' user." in self.machine.execute(f"cat {args['logfile']}"), delay=3)
        self.goToVmPage("subVmTest1")

        self.deleteIface(1)
        b.wait_not_present(".pf-c-modal-box")
        b.wait_not_present("#vm-subVmTest1-network-1-mac")

        # Detach NIC when the VM is shutoff, Also check this issue: https://bugzilla.redhat.com/show_bug.cgi?id=1791543
        self.performAction("subVmTest1", "off")
        # Attach since no NIC now
        m.execute("virsh attach-interface --domain subVmTest1 --type network --source default --model virtio --mac 52:54:00:4b:73:5f --config")
        m.execute("virsh attach-interface --domain subVmTest1 --type bridge --source virbr0 --model virtio --mac 52:54:00:4b:73:6f --config")
        m.execute("virsh attach-interface --domain subVmTest1 --type network --source default --model virtio --mac 52:54:00:4b:73:4f --config")
        # Refresh for getting new added NIC
        b.reload()
        b.enter_page('/machines')
        b.wait_in_text("body", "Virtual machines")
        # Check NIC MAC addresses
        b.wait_text("#vm-subVmTest1-network-1-mac", "52:54:00:4b:73:5f")
        b.wait_text("#vm-subVmTest1-network-2-mac", "52:54:00:4b:73:6f")
        b.wait_text("#vm-subVmTest1-network-3-mac", "52:54:00:4b:73:4f")
        # Detach
        self.deleteIface(2)
        # Make sure popup dialog disappeared
        b.wait_not_present(".pf-c-modal-box")
        b.wait_text_not("#vm-subVmTest1-network-2-mac", "52:54:00:4b:73:6f")
        b.wait_text("#vm-subVmTest1-network-2-mac", "52:54:00:4b:73:4f")

    def testNICAdd(self):
        def get_next_mac(last_mac):
            parts = last_mac.split(':')
            suffix = parts[-1]
            new_suffix = format(int(suffix, 16) + 1, "x").zfill(2)
            parts[-1] = new_suffix
            new_mac = ':'.join(parts)
            return new_mac

        b = self.browser
        m = self.machine

        m.execute(f"echo \"{TEST_NETWORK_XML}\" > /tmp/xml && virsh net-define /tmp/xml && virsh net-start test_network")
        m.execute(f"echo \"{TEST_NETWORK4_XML}\" > /tmp/xml2 && virsh net-define /tmp/xml2")

        args = self.createVm("subVmTest1")

        self.login_and_go("/machines")
        b.wait_in_text("body", "Virtual machines")

        self.goToVmPage("subVmTest1")

        mac_address = "52:54:00:a5:f8:00"
        # Test a error message handling
        self.NICAddDialog(
            self,
            source_type="network",
            source="test_network4",
            mac=mac_address,
            xfail=True,
            xfail_error="Network interface settings could not be saved",  # fail because network 'test_network4' is not active
        ).execute()

        # Shut off domain
        b.click("#vm-subVmTest1-action-kebab button")
        b.click("#vm-subVmTest1-forceOff")
        b.wait_in_text("#vm-subVmTest1-state", "Shut off")

        # No NICs present
        b.wait_visible("#vm-subVmTest1-add-iface-button")  # open the Network Interfaces subtab

        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            source_type="network",
            source="test_network",
            mac=mac_address,
            pixel_test_tag="vm-add-nic-modal"
        ).execute()

        # Test direct
        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            source_type="direct",
        ).execute()

        # Test Bridge
        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            source_type="bridge",
            source="virbr0",
        ).execute()

        # Test model
        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            model="e1000e",
        ).execute()

        # Start vm and wait until kernel is booted
        m.execute(f"> {args['logfile']}")  # clear logfile
        b.click("#vm-subVmTest1-run")
        b.wait_in_text("#vm-subVmTest1-state", "Running")
        wait(lambda: "login as 'cirros' user." in self.machine.execute(f"cat {args['logfile']}"), delay=3)

        # Test permanent attachment to running VM
        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            source_type="network",
            source="test_network",
            permanent=True,
        ).execute()

        # Test NIC attaching to non-persistent VM
        m.execute("virsh dumpxml --inactive subVmTest1 > /tmp/subVmTest1.xml; virsh undefine subVmTest1")
        b.wait_visible("div[data-vm-transient=\"true\"]")
        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            source_type="network",
            source="test_network",
            mac=mac_address,
            nic_num=3,
            persistent_vm=False,
        ).execute()
        m.execute("virsh define /tmp/subVmTest1.xml")
        b.wait_visible("div[data-vm-transient=\"false\"]")
        b.click("#vm-subVmTest1-action-kebab button")
        b.click("#vm-subVmTest1-forceOff")
        b.wait_in_text("#vm-subVmTest1-state", "Shut off")

        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            remove=False,
        ).execute()

        mac_address = get_next_mac(mac_address)
        self.NICAddDialog(
            self,
            mac=mac_address,
            nic_num=3,
            remove=False,
        ).execute()

    class NICEditDialog:

        def __init__(
            self,
            test_obj,
            mac="52:54:00:f0:eb:63",
            model=None,
            nic_num=2,
            source=None,
            source_type=None,
        ):
            self.assertEqual = test_obj.assertEqual
            self.browser = test_obj.browser
            self.mac = mac
            self.machine = test_obj.machine
            self.model = model
            self.nic_num = nic_num
            self.source = source
            self.source_type = source_type
            self.vm_state = "running" if "running" in test_obj.machine.execute("virsh domstate subVmTest1") else "shut off"

        def execute(self):
            self.open()
            self.fill()
            self.save()
            self.verify()
            self.verify_overview()

        def open(self):
            b = self.browser

            b.click(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog")
            b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-modal-window")

            # select widget options are never visible for the headless chrome - call therefore directly the js function
            self.source_type_current = b.attr(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-type", "data-value")
            self.source_current = b.attr(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-source", "data-value")
            self.mac_current = b.val(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-mac")
            self.model_current = b.attr(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-model", "data-value")

        def fill(self):
            b = self.browser

            if self.source_type:
                b.select_from_dropdown(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-type", self.source_type)
            if self.source:
                b.select_from_dropdown(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-source", self.source)
            if self.model:
                b.select_from_dropdown(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-model", self.model)

            if self.vm_state == "running":
                b.wait_attr(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-mac", "readonly", "")
            else:
                b.set_input_text(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-mac", self.mac)

            if (self.vm_state == "running" and
                    (self.source_type is not None and self.source_type != self.source_type_current or
                        self.source is not None and self.source != self.source_current or
                        self.model is not None and self.model != self.model_current or
                        self.mac is not None and self.mac != self.mac_current)):
                b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-idle-message")
            else:
                b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-idle-message")

        def save(self):
            b = self.browser

            b.click(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-save")
            b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-modal-window")

        def cancel(self):
            b = self.browser

            b.click(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-cancel")
            b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-edit-dialog-modal-window")

        def verify(self):
            dom_xml = "virsh -c qemu:///system dumpxml --domain subVmTest1"
            mac_string = f'"{self.mac}"'
            xmllint_element = f"{dom_xml} | xmllint --xpath 'string(//domain/devices/interface[starts-with(mac/@address,{mac_string})]/{{prop}})' - 2>&1 || true"

            if self.source_type == "network":
                self.assertEqual(
                    "network" if self.vm_state == "shut off" else self.source_type_current,
                    self.machine.execute(xmllint_element.format(prop='@type')).strip()
                )
                if self.source:
                    self.assertEqual(
                        self.source if self.vm_state == "shut off" else self.source_current,
                        self.machine.execute(xmllint_element.format(prop='source/@network')).strip()
                    )
            elif self.source_type == "direct":
                self.assertEqual(
                    "direct" if self.vm_state == "shut off" else self.source_type_current,
                    self.machine.execute(xmllint_element.format(prop='@type')).strip()
                )
                if self.source:
                    self.assertEqual(
                        self.source if self.vm_state == "shut off" else self.source,
                        self.machine.execute(xmllint_element.format(prop='source/@dev')).strip()
                    )
            if self.model:
                self.assertEqual(
                    self.model if self.vm_state == "shut off" else self.model_current,
                    self.machine.execute(xmllint_element.format(prop='model/@type')).strip()
                )

        def verify_overview(self):
            b = self.browser

            b.wait_in_text(
                f"#vm-subVmTest1-network-{self.nic_num}-type",
                self.source_type if self.source_type and self.vm_state == "shut off" else self.source_type_current
            )
            b.wait_in_text(
                f"#vm-subVmTest1-network-{self.nic_num}-source",
                self.source if self.source and self.vm_state == "shut off" else self.source_current
            )
            b.wait_in_text(
                f"#vm-subVmTest1-network-{self.nic_num}-model",
                self.model if self.model and self.vm_state == "shut off" else self.model_current
            )
            b.wait_in_text(
                f"#vm-subVmTest1-network-{self.nic_num}-mac",
                self.mac if self.mac and self.vm_state == "shut off" else self.mac_current
            )
            if self.vm_state == "running":
                if self.source_type is not None and self.source_type != self.source_type_current:
                    b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-type-tooltip")
                else:
                    b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-type-tooltip")

                if self.source is not None and self.source != self.source_current:
                    b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-source-tooltip")
                # Changing source_type may in effect also change source, so tooltip being present is correct
                # Only changing source type beteen bridge and direct should not affect source
                elif self.source_type in ["direct", "bridge"] and self.source_type_current in ["direct", "bridge"]:
                    b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-source-tooltip")

                if self.mac is not None and self.mac != self.mac_current:
                    b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-mac-tooltip")
                else:
                    b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-mac-tooltip")

                if self.model is not None and self.model != self.model_current:
                    b.wait_visible(f"#vm-subVmTest1-network-{self.nic_num}-model-tooltip")
                else:
                    b.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-model-tooltip")

    def testNICEdit(self):
        b = self.browser

        self.add_veth("eth42")
        self.add_veth("eth43")

        self.createVm("subVmTest1", running=False)

        self.login_and_go("/machines")
        b.wait_in_text("body", "Virtual machines")

        self.goToVmPage("subVmTest1")

        self.NICAddDialog(
            self,
            source_type="bridge",
            source="eth42",
            mac="52:54:00:f0:eb:63",
            remove=False
        ).execute()

        # The dialog fields should reflect the permanent configuration
        dialog = self.NICEditDialog(self)
        dialog.open()
        b.wait_in_text("#vm-subVmTest1-network-2-edit-dialog-source", "eth42")
        b.wait_val("#vm-subVmTest1-network-2-edit-dialog-mac", "52:54:00:f0:eb:63")
        b.assert_pixels("#vm-subVmTest1-network-2-edit-dialog-modal-window", "vm-edit-nic-modal")
        dialog.cancel()

        # Changing the NIC configuration for a shut off VM should not display any warning
        self.NICEditDialog(
            self,
            source_type="direct",
            source="eth43",
        ).execute()

        b.click("#vm-subVmTest1-run")
        b.wait_in_text("#vm-subVmTest1-state", "Running")

        # Test a warning shows up when editing a vNIC for a running VM
        self.NICEditDialog(
            self,
            source="eth42",
        ).execute()

        # Change source type from direct to virtual network - https://bugzilla.redhat.com/show_bug.cgi?id=1977669
        self.NICEditDialog(
            self,
            source_type="network",
        ).execute()

        # Changing settings of a transient NIC is not implemented - https://bugzilla.redhat.com/show_bug.cgi?id=1977669
        self.NICAddDialog(
            self,
            source_type="direct",
            source="eth43",
            mac="52:54:00:f0:eb:64",
            nic_num=3,
            remove=False
        ).execute()
        b.wait_visible("#vm-subVmTest1-network-3-edit-dialog[aria-disabled=true]")

    class NICAddDialog:

        def __init__(
            # We have always have to specify mac and source_type to identify the device in xml and $virsh detach-interface
            self, test_obj, source_type="direct", source=None, model=None, nic_num=2,
            permanent=False, mac=None, remove=True, persistent_vm=True,
            xfail=False, xfail_error=None, pixel_test_tag=None
        ):
            self.source_type = source_type
            self.source = source
            self.model = model
            self.permanent = permanent
            self.mac = mac
            self.remove = remove
            self.persistent_vm = persistent_vm
            self.nic_num = nic_num

            self.browser = test_obj.browser
            self.machine = test_obj.machine
            self.assertEqual = test_obj.assertEqual
            self.deleteIface = test_obj.deleteIface

            self.xfail = xfail
            self.xfail_error = xfail_error
            self.pixel_test_tag = pixel_test_tag

        def execute(self):
            self.open()
            self.fill()
            self.assert_pixels()
            self.create()
            if not self.xfail:
                self.verify()
                self.verify_overview()
                if self.remove:
                    self.cleanup()

        def open(self):
            self.browser.click("#vm-subVmTest1-add-iface-button")  # open the Network Interfaces subtab
            self.browser.wait_in_text(".pf-c-modal-box .pf-c-modal-box__header .pf-c-modal-box__title", "Add virtual network interface")

        def fill(self):
            self.browser.select_from_dropdown("#vm-subVmTest1-add-iface-type", self.source_type)
            if self.source:
                self.browser.select_from_dropdown("#vm-subVmTest1-add-iface-source", self.source)
            if self.model:
                self.browser.select_from_dropdown("#vm-subVmTest1-add-iface-model", self.model)

            if self.mac:
                self.browser.click("#vm-subVmTest1-add-iface-set-mac")
                self.browser.set_input_text("#vm-subVmTest1-add-iface-mac", self.mac)

            if self.permanent:
                self.browser.click("#vm-subVmTest1-add-iface-permanent")

            if not self.persistent_vm:
                self.browser.wait_not_present("#vm-subVmTest1-add-iface-permanent")

        def assert_pixels(self):
            if self.pixel_test_tag:
                self.browser.assert_pixels("#vm-subVmTest1-add-iface-dialog", self.pixel_test_tag)

        def cancel(self):
            self.browser.click(".pf-c-modal-box__footer button:contains(Cancel)")
            self.browser.wait_not_present("#vm-subVmTest1-add-iface-dialog")

        def create(self):
            self.browser.click(".pf-c-modal-box__footer button:contains(Add)")

            if not self.xfail:
                self.browser.wait_not_present("#vm-subVmTest1-add-iface-dialog")
            else:
                self.browser.wait_in_text(".pf-c-modal-box__footer .pf-c-alert__title", self.xfail_error)
                self.browser.click(".pf-c-modal-box__footer button:contains(Cancel)")

        def verify(self):
            # Verify libvirt XML
            dom_xml = "virsh -c qemu:///system dumpxml --domain subVmTest1"
            mac_string = f'"{self.mac}"'
            xmllint_element = f"{dom_xml} | xmllint --xpath 'string(//domain/devices/interface[starts-with(mac/@address,{mac_string})]/{{prop}})' - 2>&1 || true"

            if (self.source_type == "network"):
                self.assertEqual("network", self.machine.execute(xmllint_element.format(prop='@type')).strip())
                if self.source:
                    self.assertEqual(self.source, self.machine.execute(xmllint_element.format(prop='source/@network')).strip())
            elif (self.source_type == "direct"):
                self.assertEqual("direct", self.machine.execute(xmllint_element.format(prop='@type')).strip())
                if self.source:
                    self.assertEqual(self.source, self.machine.execute(xmllint_element.format(prop='source/@dev')).strip())

            if (self.model):
                self.assertEqual(self.model, self.machine.execute(xmllint_element.format(prop='model/@type')).strip())

        def verify_overview(self):
            # The first NIC is default, our new NIC is second in row
            self.browser.wait_in_text(f"#vm-subVmTest1-network-{self.nic_num}-type", self.source_type)
            if self.model:
                self.browser.wait_in_text(f"#vm-subVmTest1-network-{self.nic_num}-model", self.model)
            if self.source:
                self.browser.wait_in_text(f"#vm-subVmTest1-network-{self.nic_num}-source", self.source)
            if self.mac:
                self.browser.wait_in_text(f"#vm-subVmTest1-network-{self.nic_num}-mac", self.mac)

        def cleanup(self):
            if self.permanent:
                self.machine.execute(f"virsh detach-interface --mac {self.mac} --domain subVmTest1 --type {self.source_type} --config")

                # we don't get any signal for interface detaching right now
                self.browser.reload()
                self.browser.enter_page('/machines')
                self.browser.wait_in_text("body", "Virtual machines")
            else:
                self.deleteIface(self.nic_num)
                vm_state = self.browser.text("#vm-subVmTest1-state")
                # On a running VM detaching NIC takes longer and we can see the spinner
                if vm_state == "Running":
                    self.browser.wait_visible(".pf-c-modal-box__footer button.pf-m-in-progress")

                # Check NIC is no longer in list
                self.browser.wait_not_present(f"#vm-subVmTest1-network-{self.nic_num}-mac")
                self.browser.wait_not_present(".pf-c-modal-box")


if __name__ == '__main__':
    test_main()
