#!/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 skipImage, nondestructive, test_main  # noqa


@nondestructive
class TestMachinesFilesystems(VirtualMachinesCase):

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

        m.execute("mkdir -p /tmp/dir1 /tmp/dir2")

        self.createVm("subVmTest1", running=False)
        self.login_and_go("/machines")
        self.goToVmPage("subVmTest1")

        if m.image in ["rhel-8-5", "centos-8-stream", "debian-stable", "ubuntu-2004", "fedora-33"]:
            b.wait_not_present("#vm-subVmTest1-filesystems-add")
            return

        # Form validation
        b.click("#vm-subVmTest1-filesystems-add")
        b.click("#vm-subVmTest1-filesystems-modal-add")
        b.wait_visible("#vm-subVmTest1-filesystems-modal-source-helper")
        b.wait_visible("#vm-subVmTest1-filesystems-modal-mountTag-helper")
        b.click("#vm-subVmTest1-filesystems-modal-cancel")

        # Add a new shared fileystem
        b.click("#vm-subVmTest1-filesystems-add")
        b.set_file_autocomplete_val("#vm-subVmTest1-filesystems-modal-source-group", "/tmp/dir1/")
        b.set_input_text("#vm-subVmTest1-filesystems-modal-mountTag", "dir1")
        b.click(".pf-c-expandable-section__toggle")
        b.wait_visible("#vm-subVmTest1-filesystems-modal-xattr:not(:checked)")
        b.set_checked("#vm-subVmTest1-filesystems-modal-xattr", True)
        b.wait_visible("#vm-subVmTest1-filesystems-modal-file-backed")

        b.click("#vm-subVmTest1-filesystems-modal-add")
        b.wait_visible("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1']")
        b.wait_in_text("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1'] td[data-label='Source path']", "/tmp/dir1/")
        b.wait_in_text("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1'] td[data-label='Mount tag']", "dir1")

        domain_xml = "virsh -c qemu:///system dumpxml {0}".format("subVmTest1")
        xmllint_element = "{0} | xmllint --xpath 'string(//domain/{{prop}})' - 2>&1 || true".format(domain_xml)

        self.assertEqual('/tmp/dir1/', self.machine.execute(xmllint_element.format(prop='devices/filesystem/source/@dir')).strip())
        self.assertEqual('dir1', self.machine.execute(xmllint_element.format(prop='devices/filesystem/target/@dir')).strip())
        self.assertEqual('on', self.machine.execute(xmllint_element.format(prop='devices/filesystem/binary/@xattr')).strip())
        self.assertEqual('shared', self.machine.execute(xmllint_element.format(prop='memoryBacking/access/@mode')).strip())

        # Add a new shared fileystem - now the memoryBacking is configured and hidden from the dialog
        b.click("#vm-subVmTest1-filesystems-add")
        b.set_file_autocomplete_val("#vm-subVmTest1-filesystems-modal-source-group", "/tmp/dir2/")
        b.set_input_text("#vm-subVmTest1-filesystems-modal-mountTag", "dir2")
        b.click(".pf-c-expandable-section__toggle")
        b.set_checked("#vm-subVmTest1-filesystems-modal-xattr", False)
        b.wait_not_present("#vm-subVmTest1-filesystems-modal-file-backed")

        b.click("#vm-subVmTest1-filesystems-modal-add")
        b.wait_visible("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir2/-dir2']")
        b.wait_in_text("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir2/-dir2'] td[data-label='Source path']", "/tmp/dir2/")
        b.wait_in_text("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir2/-dir2'] td[data-label='Mount tag']", "dir2")

        self.assertEqual('/tmp/dir2/', self.machine.execute(xmllint_element.format(prop='devices/filesystem[2]/source/@dir')).strip())
        self.assertEqual('dir2', self.machine.execute(xmllint_element.format(prop='devices/filesystem[2]/target/@dir')).strip())
        self.assertEqual('', self.machine.execute(xmllint_element.format(prop='devices/filesystem[2]/binary/@xattr')).strip())

        # Try to add a new shared filesystem with the same mount tag
        b.click("#vm-subVmTest1-filesystems-add")
        b.set_file_autocomplete_val("#vm-subVmTest1-filesystems-modal-source-group", "/tmp/dir1/")
        b.set_input_text("#vm-subVmTest1-filesystems-modal-mountTag", "dir1")
        b.click("#vm-subVmTest1-filesystems-modal-add")
        if m.execute("virsh --version") >= "7.5.0":
            b.wait_in_text(".pf-c-alert", "Failed to add shared directory")
            b.wait_in_text(".pf-c-alert", "filesystem target 'dir1' specified twice")
            b.click("#vm-subVmTest1-filesystems-modal-cancel")
        else:
            # Due to a libvirt < 7.5.0 bug this will be actually added without an error:
            # https://bugzilla.redhat.com/show_bug.cgi?id=1972218
            b.wait_visible("tr:nth-child(3)[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1']")

        # Try to add a new shared filesystem with non existing source directory
        b.click("#vm-subVmTest1-filesystems-add")
        b.set_input_text("#vm-subVmTest1-filesystems-modal-source-group input", "dir3")
        b.wait_in_text("#vm-subVmTest1-filesystems-modal-source", "No such file or directory")
        b.click("#vm-subVmTest1-filesystems-modal-cancel")

        # Start VM and ensure that adding filesystem is disabled
        b.click("#vm-subVmTest1-run")
        b.wait_visible("#vm-subVmTest1-filesystems-add[aria-disabled=true]")

    @skipImage("Older libvirt does not support virtiofs", "rhel-8-5", "centos-8-stream", "debian-stable", "ubuntu-2004", "fedora-33")
    def testDelete(self):
        b = self.browser
        m = self.machine

        m.execute("mkdir -p /tmp/dir1")

        self.createVm("subVmTest1", running=False)
        self.login_and_go("/machines")
        self.goToVmPage("subVmTest1")

        m.execute("virt-xml subVmTest1 --add-device --filesystem source=/tmp/dir1/,target=dir1")
        b.wait_visible("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1']")
        b.click("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1'] button:contains(Remove)")
        b.click("#delete-resource-modal button:contains(Remove)")
        b.wait_not_present("tr[data-row-id='vm-subVmTest1-filesystem-/tmp/dir1/-dir1']")


if __name__ == '__main__':
    test_main()
