# -*- coding: utf-8 -*-
"""
    :codeauthor: Nicole Thomas <nicole@saltstack.com>
"""

from __future__ import absolute_import, print_function, unicode_literals

from salt.exceptions import CommandExecutionError
from salt.ext import six
from tests.support.case import ModuleCase
from tests.support.helpers import (
    destructiveTest,
    random_string,
    runs_on,
    skip_if_not_root,
    slowTest,
)

# Create group name strings for tests
ADD_GROUP = random_string("RS-", lowercase=False)
DEL_GROUP = random_string("RS-", lowercase=False)
CHANGE_GROUP = random_string("RS-", lowercase=False)
ADD_USER = random_string("RS-", lowercase=False)
REP_USER_GROUP = random_string("RS-", lowercase=False)


@destructiveTest
@skip_if_not_root
@runs_on(kernel="Darwin")
class MacGroupModuleTest(ModuleCase):
    """
    Integration tests for the mac_group module
    """

    def setUp(self):
        """
        Sets up test requirements
        """
        os_grain = self.run_function("grains.item", ["kernel"])
        if os_grain["kernel"] not in "Darwin":
            self.skipTest("Test not applicable to '{kernel}' kernel".format(**os_grain))

    @slowTest
    def test_mac_group_add(self):
        """
        Tests the add group function
        """
        try:
            self.run_function("group.add", [ADD_GROUP, 3456])
            group_info = self.run_function("group.info", [ADD_GROUP])
            self.assertEqual(group_info["name"], ADD_GROUP)
        except CommandExecutionError:
            self.run_function("group.delete", [ADD_GROUP])
            raise

    @slowTest
    def test_mac_group_delete(self):
        """
        Tests the delete group function
        """
        # Create a group to delete - If unsuccessful, skip the test
        if self.run_function("group.add", [DEL_GROUP, 4567]) is not True:
            self.run_function("group.delete", [DEL_GROUP])
            self.skipTest("Failed to create a group to delete")

        # Now try to delete the added group
        ret = self.run_function("group.delete", [DEL_GROUP])
        self.assertTrue(ret)

    @slowTest
    def test_mac_group_chgid(self):
        """
        Tests changing the group id
        """
        # Create a group to delete - If unsuccessful, skip the test
        if self.run_function("group.add", [CHANGE_GROUP, 5678]) is not True:
            self.run_function("group.delete", [CHANGE_GROUP])
            self.skipTest("Failed to create a group to manipulate")

        try:
            self.run_function("group.chgid", [CHANGE_GROUP, 6789])
            group_info = self.run_function("group.info", [CHANGE_GROUP])
            self.assertEqual(group_info["gid"], 6789)
        except AssertionError:
            self.run_function("group.delete", [CHANGE_GROUP])
            raise

    @slowTest
    def test_mac_adduser(self):
        """
        Tests adding user to the group
        """
        # Create a group to use for test - If unsuccessful, skip the test
        if self.run_function("group.add", [ADD_GROUP, 5678]) is not True:
            self.run_function("group.delete", [ADD_GROUP])
            self.skipTest("Failed to create a group to manipulate")

        try:
            self.run_function("group.adduser", [ADD_GROUP, ADD_USER])
            group_info = self.run_function("group.info", [ADD_GROUP])
            self.assertEqual(ADD_USER, "".join(group_info["members"]))
        except AssertionError:
            self.run_function("group.delete", [ADD_GROUP])
            raise

    @slowTest
    def test_mac_deluser(self):
        """
        Test deleting user from a group
        """
        # Create a group to use for test - If unsuccessful, skip the test
        if (
            self.run_function("group.add", [ADD_GROUP, 5678])
            and self.run_function("group.adduser", [ADD_GROUP, ADD_USER]) is not True
        ):
            self.run_function("group.delete", [ADD_GROUP])
            self.skipTest("Failed to create a group to manipulate")

        delusr = self.run_function("group.deluser", [ADD_GROUP, ADD_USER])
        self.assertTrue(delusr)

        group_info = self.run_function("group.info", [ADD_GROUP])
        self.assertNotIn(ADD_USER, "".join(group_info["members"]))

    @slowTest
    def test_mac_members(self):
        """
        Test replacing members of a group
        """
        if (
            self.run_function("group.add", [ADD_GROUP, 5678])
            and self.run_function("group.adduser", [ADD_GROUP, ADD_USER]) is not True
        ):
            self.run_function("group.delete", [ADD_GROUP])
            self.skipTest(
                "Failed to create the {0} group or add user {1} to group "
                "to manipulate".format(ADD_GROUP, ADD_USER)
            )

        rep_group_mem = self.run_function("group.members", [ADD_GROUP, REP_USER_GROUP])
        self.assertTrue(rep_group_mem)

        # ensure new user is added to group and previous user is removed
        group_info = self.run_function("group.info", [ADD_GROUP])
        self.assertIn(REP_USER_GROUP, six.text_type(group_info["members"]))
        self.assertNotIn(ADD_USER, six.text_type(group_info["members"]))

    @slowTest
    def test_mac_getent(self):
        """
        Test returning info on all groups
        """
        if (
            self.run_function("group.add", [ADD_GROUP, 5678])
            and self.run_function("group.adduser", [ADD_GROUP, ADD_USER]) is not True
        ):
            self.run_function("group.delete", [ADD_GROUP])
            self.skipTest(
                "Failed to create the {0} group or add user {1} to group "
                "to manipulate".format(ADD_GROUP, ADD_USER)
            )

        getinfo = self.run_function("group.getent")
        self.assertTrue(getinfo)
        self.assertIn(ADD_GROUP, six.text_type(getinfo))
        self.assertIn(ADD_USER, six.text_type(getinfo))

    def tearDown(self):
        """
        Clean up after tests
        """
        # Delete ADD_GROUP
        add_info = self.run_function("group.info", [ADD_GROUP])
        if add_info:
            self.run_function("group.delete", [ADD_GROUP])

        # Delete DEL_GROUP if something failed
        del_info = self.run_function("group.info", [DEL_GROUP])
        if del_info:
            self.run_function("group.delete", [DEL_GROUP])

        # Delete CHANGE_GROUP
        change_info = self.run_function("group.info", [CHANGE_GROUP])
        if change_info:
            self.run_function("group.delete", [CHANGE_GROUP])
