#!/usr/bin/python2
# -*- coding: utf-8 -*-

# This file is part of Cockpit.
#
# Copyright (C) 2015 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 parent
from testlib import *
from storagelib import *

storaged_debug_service = """
[Unit]
Description=Storaged
Documentation=man:storaged(8)

[Service]
Type=dbus
BusName=org.storaged.Storaged
ExecStart=/usr/lib/storaged/storaged
"""

class TestStorage(StorageCase):

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

        if not self.storaged_is_old_udisks:
            mount_point_foo = "/run/foo"
            mount_point_bar = "/run/bar"
        else:
            # We don't get to set the mountpoint with old UDisks so we
            # expect UDisks default.  (XXX - I think this is Ubuntu specific.)
            mount_point_foo = self.mount_root + "/admin/FILESYSTEM"
            mount_point_bar = self.mount_root + "/admin/FILESYSTEM"

        self.login_and_go("/storage")

        # Add a disk
        m.add_disk("50M", serial="MYDISK")
        b.wait_in_text("#drives", "MYDISK")
        b.click('#drives tr:contains("MYDISK")')
        b.wait_visible('#storage-detail')

        # Format it

        self.content_tab_action(1, 1, "Format")
        self.dialog({ "type": "ext4",
                      "name": "FILESYSTEM",
                      "mounting": "custom",
                      "mount_point": mount_point_foo })
        self.content_row_wait_in_col(1, 1, "ext4 File System")
        self.content_tab_wait_in_info(1, 1, "Name", "FILESYSTEM")
        if not self.storaged_is_old_udisks:
            self.wait_in_storaged_configuration(mount_point_foo)

        if not self.storaged_is_old_udisks:
            self.content_tab_wait_in_info(1, 1, "Mount Point", mount_point_foo)
        self.content_tab_action(1, 1, "Mount");
        self.content_tab_wait_in_info(1, 1, "Mounted At", mount_point_foo)

        self.content_tab_action(1, 1, "Unmount");
        if not self.storaged_is_old_udisks:
            b.wait_not_present(self.content_tab_info_row(1, 1, "Mounted At"))

        self.content_tab_info_action(1, 1, "Name");
        self.dialog({ "name": "filesystem" })
        self.content_tab_wait_in_info(1, 1, "Name", "filesystem")

        if not self.storaged_is_old_udisks:
            self.dialog_with_retry(trigger = lambda: self.content_tab_info_action(1, 1, "Mount Point"),
                                   expect = { "mounting": "custom",
                                              "mount_point": mount_point_foo },
                                   values = { "mount_point": mount_point_bar })
            self.wait_in_storaged_configuration(mount_point_bar)
        else:
            mount_point_bar = self.mount_root + "/admin/filesystem"

        self.content_tab_action(1, 1, "Mount");
        self.content_tab_wait_in_info(1, 1, "Mounted At", mount_point_bar)

        # Go to overview page and check that the filesystem usage is
        # displayed correctly.

        def wait_ratio_in_range(sel, low, high):
            b.wait_js_func("""(function (sel, low, high) {
              var text = ph_text(sel);
              var match = text.match('([0-9.]+) / ([0-9]+)');
              if (!match)
                return false;
              var ratio = parseFloat(match[1]) / parseFloat(match[2]);
              return low <= ratio && ratio <= high;
            })""", sel, low, high)

        b.go("#/")
        b.wait_in_text("#storage_mounts", mount_point_bar)
        bar_selector = '#storage_mounts tr:contains("%s") td:nth-child(4)' % mount_point_bar
        wait_ratio_in_range(bar_selector, 0.0, 0.1)
        m.execute("dd if=/dev/zero of=%s/zero bs=1M count=30 status=none" % mount_point_bar)
        wait_ratio_in_range(bar_selector, 0.5, 1.0)
        m.execute("rm %s/zero" % mount_point_bar)
        wait_ratio_in_range(bar_selector, 0.0, 0.1)
        m.execute("umount %s" % mount_point_bar)
        b.wait_not_in_text("#storage_mounts", mount_point_bar)
        b.click('#storage_mounts tr:contains("filesystem")')
        b.wait_visible("#storage-detail")

        def wait_info_field_value(name, value):
            return b.wait_text('#detail-header tr:contains("%s") td:nth-child(2)' % name, value)

        wait_info_field_value("Serial Number", "MYDISK")

        if not self.storaged_is_old_udisks:
            b.wait_not_present(self.content_tab_info_row(1, 1, "Mounted At"))
            self.content_tab_info_action(1, 1, "Mount Point");
            self.dialog(values = { "mounting": "default" })
            self.wait_not_in_storaged_configuration(mount_point_bar)

            self.content_tab_action(1, 1, "Mount");
            self.content_tab_wait_in_info(1, 1, "Mounted At", self.mount_root + "/admin/filesystem")

            self.content_tab_action(1, 1, "Unmount");
            b.wait_not_present(self.content_tab_info_row(1, 1, "Mounted At"))

        self.content_tab_action(1, 1, "Format")
        self.dialog({ "type": "empty" })
        self.content_row_wait_in_col(1, 1, "Unrecognized Data")

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

        if self.storaged_is_old_udisks:
            self.skipTest("No mount/crypto options with old UDisks")

        self.login_and_go("/storage")

        # Add a disk
        m.add_disk("50M", serial="MYDISK")
        b.wait_in_text("#drives", "MYDISK")
        b.click('#drives tr:contains("MYDISK")')
        b.wait_visible('#storage-detail')

        # Open format dialog and play with the checkboxes

        self.content_tab_action(1, 1, "Format")
        self.dialog_wait_open()
        self.dialog_set_val("type", "luks+ext4")
        self.dialog_set_val("mounting", "custom")

        def wait_checked(field):
            b.wait_present(self.dialog_field(field) + ":checked")

        def wait_not_checked(field):
            b.wait_present(self.dialog_field(field) + ":not(:checked)")

        wait_checked("crypto_options_auto")
        wait_checked("mount_auto")
        wait_not_checked("crypto_options_ro")
        wait_not_checked("mount_ro")

        # Uncheck crypto auto.  This gets propagated to mount auto.
        self.dialog_set_val("crypto_options_auto", False)
        wait_not_checked("mount_auto")

        # Check crypto ro.  This gets propagated to mount ro.
        self.dialog_set_val("crypto_options_ro", True)
        wait_checked("mount_ro")

        # Set extra options.
        self.dialog_set_val("crypto_extra_options", CheckBoxText("foo"))
        self.dialog_set_val("mount_extra_options", CheckBoxText("foo"))

        # Fill in the erst and do the format
        self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
        self.dialog_set_val("passphrase2", "vainu-reku-toma-rolle-kaja")
        self.dialog_set_val("mount_point", "/data")
        self.dialog_apply()
        self.dialog_wait_close()

        self.content_row_wait_in_col(1, 1, "Encrypted data")
        self.content_row_wait_in_col(2, 1, "ext4 File System")
        self.wait_in_storaged_configuration("/data")
        m.execute("grep 'noauto,readonly,foo' /etc/crypttab")
        m.execute("grep 'noauto,ro,foo' /etc/fstab")

if __name__ == '__main__':
    test_main()
