test_manage_group.py 7.42 KB
Newer Older
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
"""
Unit tests for user_management management commands.
"""
import sys

import ddt
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management import call_command, CommandError
from django.test import TestCase

TEST_EMAIL = 'test@example.com'
TEST_GROUP = 'test-group'
TEST_USERNAME = 'test-user'
TEST_DATA = (
    {},
    {
        TEST_GROUP: ['add_group', 'change_group', 'change_group'],
    },
    {
        'other-group': ['add_group', 'change_group', 'change_group'],
    },
)


@ddt.ddt
class TestManageGroupCommand(TestCase):
    """
    Tests the `manage_group` command.
    """

    def set_group_permissions(self, group_permissions):
        """
        Sets up a before-state for groups and permissions in tests, which
        can be checked afterward to ensure that a failed atomic
        operation has not had any side effects.
        """
        content_type = ContentType.objects.get_for_model(Group)
        for group_name, permission_codenames in group_permissions.items():
            group = Group.objects.create(name=group_name)
            for codename in permission_codenames:
                group.permissions.add(
                    Permission.objects.get(content_type=content_type, codename=codename)  # pylint: disable=no-member
                )

    def check_group_permissions(self, group_permissions):
        """
        Checks that the current state of the database matches the specified groups and
        permissions.
        """
        self.check_groups(group_permissions.keys())
        for group_name, permission_codenames in group_permissions.items():
            self.check_permissions(group_name, permission_codenames)

    def check_groups(self, group_names):
        """
        DRY helper.
        """
        self.assertEqual(set(group_names), {g.name for g in Group.objects.all()})  # pylint: disable=no-member

    def check_permissions(self, group_name, permission_codenames):
        """
        DRY helper.
        """
        self.assertEqual(
            set(permission_codenames),
            {p.codename for p in Group.objects.get(name=group_name).permissions.all()}  # pylint: disable=no-member
        )

    @ddt.data(
        *(
            (data, args, exception)
            for data in TEST_DATA
            for args, exception in (
                ((), 'too few arguments' if sys.version_info.major == 2 else 'required: group_name'),  # no group name
                (('x' * 81,), 'invalid group name'),  # invalid group name
                ((TEST_GROUP, 'some-other-group'), 'unrecognized arguments'),  # multiple arguments
                ((TEST_GROUP, '--some-option', 'dummy'), 'unrecognized arguments')  # unexpected option name
            )
        )
    )
    @ddt.unpack
    def test_invalid_input(self, initial_group_permissions, command_args, exception_message):
        """
        Ensures that invalid inputs result in errors with relevant output,
        and that no persistent state is changed.
        """
        self.set_group_permissions(initial_group_permissions)

        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', *command_args)
        self.assertIn(exception_message, str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

    @ddt.data(*TEST_DATA)
    def test_invalid_permission(self, initial_group_permissions):
        """
        Ensures that a permission that cannot be parsed or resolved results in
        and error and that no persistent state is changed.
        """
        self.set_group_permissions(initial_group_permissions)

        # not parseable
        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', TEST_GROUP, '--permissions', 'fail')
        self.assertIn('invalid permission option', str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

        # not parseable
        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', TEST_GROUP, '--permissions', 'f:a:i:l')
        self.assertIn('invalid permission option', str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

        # invalid app label
        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', TEST_GROUP, '--permissions', 'nonexistent-label:dummy-model:dummy-perm')
        self.assertIn('no installed app', str(exc_context.exception).lower())
        self.assertIn('nonexistent-label', str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

        # invalid model name
        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', TEST_GROUP, '--permissions', 'auth:nonexistent-model:dummy-perm')
        self.assertIn('nonexistent-model', str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

        # invalid model name
        with self.assertRaises(CommandError) as exc_context:
            call_command('manage_group', TEST_GROUP, '--permissions', 'auth:Group:nonexistent-perm')
        self.assertIn('invalid permission codename', str(exc_context.exception).lower())
        self.assertIn('nonexistent-perm', str(exc_context.exception).lower())
        self.check_group_permissions(initial_group_permissions)

    def test_group(self):
        """
        Ensures that groups are created if they don't exist and reused if they do.
        """
        self.check_groups([])
        call_command('manage_group', TEST_GROUP)
        self.check_groups([TEST_GROUP])

        # check idempotency
        call_command('manage_group', TEST_GROUP)
        self.check_groups([TEST_GROUP])

    def test_group_remove(self):
        """
        Ensures that groups are removed if they exist and we exit cleanly otherwise.
        """
        self.set_group_permissions({TEST_GROUP: ['add_group']})
        self.check_groups([TEST_GROUP])
        call_command('manage_group', TEST_GROUP, '--remove')
        self.check_groups([])

        # check idempotency
        call_command('manage_group', TEST_GROUP, '--remove')
        self.check_groups([])

    def test_permissions(self):
        """
        Ensures that permissions are set on the group as specified.
        """
        self.check_groups([])
        call_command('manage_group', TEST_GROUP, '--permissions', 'auth:Group:add_group')
        self.check_groups([TEST_GROUP])
        self.check_permissions(TEST_GROUP, ['add_group'])

        # check idempotency
        call_command('manage_group', TEST_GROUP, '--permissions', 'auth:Group:add_group')
        self.check_groups([TEST_GROUP])
        self.check_permissions(TEST_GROUP, ['add_group'])

        # check adding a permission
        call_command('manage_group', TEST_GROUP, '--permissions', 'auth:Group:add_group', 'auth:Group:change_group')
        self.check_groups([TEST_GROUP])
        self.check_permissions(TEST_GROUP, ['add_group', 'change_group'])

        # check removing a permission
        call_command('manage_group', TEST_GROUP, '--permissions', 'auth:Group:change_group')
        self.check_groups([TEST_GROUP])
        self.check_permissions(TEST_GROUP, ['change_group'])

        # check removing all permissions
        call_command('manage_group', TEST_GROUP)
        self.check_groups([TEST_GROUP])
        self.check_permissions(TEST_GROUP, [])