示例#1
0
 def setUp(self):
     super(TestSQLiteBackend, self).setUp()
     transaction.begin()
     request = MagicMock()
     request.tm = transaction.manager
     self.access = SQLAccessBackend(request, **self.kwargs)
     self.db = self.kwargs['dbmaker']()
     zope.sqlalchemy.register(self.db,
                              transaction_manager=transaction.manager)
示例#2
0
    def test_load(self):
        """ Access control can load universal format data """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)
        transaction.commit()

        data1 = self.access.dump()

        self.access.db.close()
        self.db.close()
        self._drop_and_recreate()
        kwargs = SQLAccessBackend.configure(self.settings)
        self.access = SQLAccessBackend(MagicMock(), **kwargs)
        self.access.load(data1)
        data2 = self.access.dump()

        def assert_nice_equals(obj1, obj2):
            """ Assertion that handles unordered lists inside dicts """
            if isinstance(obj1, dict):
                self.assertEqual(len(obj1), len(obj2))
                for key, val in six.iteritems(obj1):
                    assert_nice_equals(val, obj2[key])
            elif isinstance(obj1, list):
                self.assertItemsEqual(obj1, obj2)
            else:
                self.assertEqual(obj1, obj2)

        assert_nice_equals(data2, data1)

        # Load operation should be idempotent
        self.access.load(data2)
        data3 = self.access.dump()
        assert_nice_equals(data3, data2)
    def test_load(self):
        """ Access control can load universal format data """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)

        data1 = self.access.dump()

        SQLAccessBackend.configure(self.settings)
        kwargs = SQLAccessBackend.configure(self.settings)
        access2 = SQLAccessBackend(MagicMock(), **kwargs)
        access2.load(data1)
        data2 = access2.dump()

        def assert_nice_equals(obj1, obj2):
            """ Assertion that handles unordered lists inside dicts """
            if isinstance(obj1, dict):
                self.assertEqual(len(obj1), len(obj2))
                for key, val in obj1.iteritems():
                    assert_nice_equals(val, obj2[key])
            elif isinstance(obj1, list):
                self.assertItemsEqual(obj1, obj2)
            else:
                self.assertEqual(obj1, obj2)

        assert_nice_equals(data2, data1)

        # Load operation should be idempotent
        access2.load(data2)
        data3 = access2.dump()
        assert_nice_equals(data3, data2)
示例#4
0
 def setUpClass(cls):
     super(TestSQLiteBackend, cls).setUpClass()
     cls.settings = {
         'auth.db.url': cls.DB_URL,
     }
     try:
         cls.kwargs = SQLAccessBackend.configure(cls.settings)
     except OperationalError:
         raise unittest.SkipTest("Couldn't connect to database")
示例#5
0
class TestSQLiteBackend(unittest.TestCase):
    """ Tests for the SQL access backend """

    DB_URL = 'sqlite://'

    @classmethod
    def setUpClass(cls):
        super(TestSQLiteBackend, cls).setUpClass()
        cls.settings = {
            'auth.db.url': cls.DB_URL,
        }
        try:
            cls.kwargs = SQLAccessBackend.configure(cls.settings)
        except OperationalError:
            raise unittest.SkipTest("Couldn't connect to database")

    def setUp(self):
        super(TestSQLiteBackend, self).setUp()
        transaction.begin()
        request = MagicMock()
        request.tm = transaction.manager
        self.access = SQLAccessBackend(request, **self.kwargs)
        self.db = self.kwargs['dbmaker']()
        zope.sqlalchemy.register(self.db,
                                 transaction_manager=transaction.manager)

    def tearDown(self):
        super(TestSQLiteBackend, self).tearDown()
        transaction.abort()
        self.access.db.close()
        self.db.close()
        self._drop_and_recreate()

    def _drop_and_recreate(self):
        """ Drop all tables and recreate them """
        Base.metadata.drop_all(bind=self.db.get_bind())
        Base.metadata.create_all(bind=self.db.get_bind())

    def test_verify(self):
        """ Verify login credentials against database """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertTrue(valid)

        valid = self.access.verify_user('foo', 'barrrr')
        self.assertFalse(valid)

    def test_verify_pending(self):
        """ Pending users fail to verify """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertFalse(valid)

    def test_admin(self):
        """ Retrieve admin status from database """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertTrue(is_admin)

    def test_admin_default_false(self):
        """ The default admin status is False """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertFalse(is_admin)

    def test_user_groups(self):
        """ Retrieve a user's groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.update([g1, g2])
        self.db.add_all([user, g1, g2])
        transaction.commit()
        groups = self.access.groups('foo')
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_groups(self):
        """ Retrieve all groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.add(g1)
        user.groups.add(g2)
        self.db.add(user)
        transaction.commit()
        groups = self.access.groups()
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_group_members(self):
        """ Fetch all members of a group """
        u1 = make_user('u1', 'bar', False)
        u2 = make_user('u2', 'bar', False)
        u3 = make_user('u3', 'bar', False)
        g1 = Group('g1')
        g1.users.update([u1, u2])
        self.db.add_all([u1, u2, u3, g1])
        transaction.commit()
        users = self.access.group_members('g1')
        self.assertItemsEqual(users, ['u1', 'u2'])

    def test_all_user_permissions(self):
        """ Retrieve all user permissions on package from database """
        user = make_user('foo', 'bar', False)
        user2 = make_user('foo2', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg1', 'foo2', True, True)
        self.db.add_all([user, user2, p1, p2])
        transaction.commit()
        perms = self.access.user_permissions('pkg1')
        self.assertEqual(perms, {
            'foo': ['read'],
            'foo2': ['read', 'write'],
        })

    def test_all_group_permissions(self):
        """ Retrieve all group permissions from database """
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        p1 = GroupPermission('pkg1', 'brotatos', True, False)
        p2 = GroupPermission('pkg1', 'sharkfest', True, True)
        self.db.add_all([g1, g2, p1, p2])
        transaction.commit()
        perms = self.access.group_permissions('pkg1')
        self.assertEqual(perms, {
            'brotatos': ['read'],
            'sharkfest': ['read', 'write'],
        })

    def test_user_package_perms(self):
        """ Fetch all packages a user has permissions on """
        user = make_user('foo', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg2', 'foo', True, True)
        self.db.add_all([user, p1, p2])
        transaction.commit()
        perms = self.access.user_package_permissions('foo')
        self.assertEqual(perms, [
            {
                'package': 'pkg1',
                'permissions': ['read']
            },
            {
                'package': 'pkg2',
                'permissions': ['read', 'write']
            },
        ])

    def test_group_package_perms(self):
        """ Fetch all packages a group has permissions on """
        g1 = Group('foo')
        p1 = GroupPermission('pkg1', 'foo', True, False)
        p2 = GroupPermission('pkg2', 'foo', True, True)
        self.db.add_all([g1, p1, p2])
        transaction.commit()
        perms = self.access.group_package_permissions('foo')
        self.assertEqual(perms, [
            {
                'package': 'pkg1',
                'permissions': ['read']
            },
            {
                'package': 'pkg2',
                'permissions': ['read', 'write']
            },
        ])

    def test_user_data(self):
        """ Retrieve all users """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        u2 = make_user('bar', 'bar', False)
        g1 = Group('foobars')
        u2.groups.add(g1)
        self.db.add_all([u1, u2, g1])
        transaction.commit()
        users = self.access.user_data()
        self.assertItemsEqual(users, [
            {
                'username': '******',
                'admin': True
            },
            {
                'username': '******',
                'admin': False
            },
        ])

    def test_single_user_data(self):
        """ Retrieve a single user's data """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        g1 = Group('foobars')
        u1.groups.add(g1)
        self.db.add_all([u1, g1])
        transaction.commit()
        user = self.access.user_data('foo')
        self.assertEqual(user, {
            'username': '******',
            'admin': True,
            'groups': ['foobars'],
        })

    def test_no_need_admin(self):
        """ If admin exists, don't need an admin """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.assertFalse(self.access.need_admin())

    def test_need_admin(self):
        """ If admin doesn't exist, need an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.assertTrue(self.access.need_admin())

    # Tests for mutable backend methods

    def test_register(self):
        """ Register a new user """
        self.access.register('foo', 'bar')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertEqual(user.username, 'foo')
        self.assertTrue(pwd_context.verify('bar', user.password))

    def test_pending(self):
        """ Registering a user puts them in pending list """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.pending_users()
        self.assertEqual(users, ['foo'])

    def test_pending_not_in_users(self):
        """ Pending users are not listed in all_users """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.user_data()
        self.assertEqual(users, [])

    def test_approve(self):
        """ Approving user marks them as not pending """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        self.access.approve_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertFalse(user.pending)

    def test_edit_password(self):
        """ Users can edit their passwords """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_password('foo', 'baz')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertTrue(self.access.verify_user('foo', 'baz'))

    def test_delete_user(self):
        """ Can delete users """
        user = make_user('foo', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group, p1])
        transaction.commit()
        self.access.delete_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertIsNone(user)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_make_admin(self):
        """ Can make a user an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', True)
        transaction.commit()
        self.db.add(user)
        self.assertTrue(user.admin)

    def test_remove_admin(self):
        """ Can demote an admin to normal user """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', False)
        transaction.commit()
        self.db.add(user)
        self.assertFalse(user.admin)

    def test_add_user_to_group(self):
        """ Can add a user to a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual([g.name for g in user.groups], ['g1'])

    def test_remove_user_from_group(self):
        """ Can remove a user from a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.groups), 0)

    def test_create_group(self):
        """ Can create a group """
        self.access.create_group('g1')
        transaction.commit()
        group = self.db.query(Group).first()
        self.assertIsNotNone(group)
        self.assertEqual(group.name, 'g1')

    def test_delete_group(self):
        """ Can delete groups """
        user = make_user('foo', 'bar')
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foobar', 'read', True)
        transaction.commit()
        self.access.delete_group('foobar')
        transaction.commit()
        count = self.db.query(Group).count()
        self.assertEqual(count, 0)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_grant_user_read_permission(self):
        """ Can give users read permissions on a package """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 1)
        perm = user.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_grant_user_write_permission(self):
        """ Can give users write permissions on a package """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'write', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 1)
        perm = user.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertFalse(perm.read)
        self.assertTrue(perm.write)

    def test_grant_user_bad_permission(self):
        """ Attempting to grant a bad permission raises ValueError """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        with self.assertRaises(ValueError):
            self.access.edit_user_permission('pkg1', 'foo', 'wiggle', True)

    def test_revoke_user_permission(self):
        """ Can revoke user permissions on a package """
        user = make_user('foo', 'bar', False)
        perm = UserPermission('pkg1', 'foo', read=True)
        self.db.add_all([user, perm])
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 0)

    def test_grant_group_read_permission(self):
        """ Can give groups read permissions on a package """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 1)
        perm = g.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_grant_group_write_permission(self):
        """ Can give groups write permissions on a package """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'write', True)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 1)
        perm = g.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertFalse(perm.read)
        self.assertTrue(perm.write)

    def test_grant_group_bad_permission(self):
        """ Attempting to grant a bad permission raises ValueError """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        with self.assertRaises(ValueError):
            self.access.edit_group_permission('pkg1', 'foo', 'wiggle', True)

    def test_revoke_group_permission(self):
        """ Can revoke group permissions on a package """
        g = Group('foo')
        perm = GroupPermission('pkg1', 'foo', read=True)
        self.db.add_all([g, perm])
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 0)

    def test_enable_registration(self):
        """ Can set the 'enable registration' flag """
        self.access.set_allow_register(True)
        self.assertTrue(self.access.allow_register())
        self.access.set_allow_register(False)
        self.assertFalse(self.access.allow_register())

    def test_dump(self):
        """ Can dump all data to json format """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)

        data = self.access.dump()

        self.assertFalse(data['allow_register'])

        # users
        self.assertEqual(len(data['users']), 2)
        for user in data['users']:
            self.assertTrue(
                pwd_context.verify(user['username'], user['password']))
            self.assertFalse(user['admin'] ^ (user['username'] == 'user3'))

        # pending users
        self.assertEqual(len(data['pending_users']), 1)
        user = data['pending_users'][0]
        self.assertTrue(pwd_context.verify(user['username'], user['password']))

        # groups
        self.assertEqual(len(data['groups']), 2)
        self.assertItemsEqual(data['groups']['g1'], ['user2'])
        self.assertItemsEqual(data['groups']['g2'], ['user2', 'user3'])

        # user package perms
        self.assertEqual(
            data['packages']['users'], {
                'pkg1': {
                    'user2': ['read'],
                },
                'pkg2': {
                    'user3': ['read', 'write'],
                },
            })

        # group package perms
        self.assertEqual(data['packages']['groups'], {
            'pkg1': {
                'g1': ['read'],
            },
            'pkg2': {
                'g2': ['read', 'write'],
            },
        })

    def test_load(self):
        """ Access control can load universal format data """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)
        transaction.commit()

        data1 = self.access.dump()

        self.access.db.close()
        self.db.close()
        self._drop_and_recreate()
        kwargs = SQLAccessBackend.configure(self.settings)
        self.access = SQLAccessBackend(MagicMock(), **kwargs)
        self.access.load(data1)
        data2 = self.access.dump()

        def assert_nice_equals(obj1, obj2):
            """ Assertion that handles unordered lists inside dicts """
            if isinstance(obj1, dict):
                self.assertEqual(len(obj1), len(obj2))
                for key, val in six.iteritems(obj1):
                    assert_nice_equals(val, obj2[key])
            elif isinstance(obj1, list):
                self.assertItemsEqual(obj1, obj2)
            else:
                self.assertEqual(obj1, obj2)

        assert_nice_equals(data2, data1)

        # Load operation should be idempotent
        self.access.load(data2)
        data3 = self.access.dump()
        assert_nice_equals(data3, data2)

    def test_save_unicode(self):
        """ register() can accept a username with unicode """
        username, passw = 'foo™', 'bar™'
        self.access.register(username, passw)
        transaction.commit()
        user = self.db.query(User).first()
        self.assertEqual(user.username, username)
        self.assertTrue(pwd_context.verify(passw, user.password))
示例#6
0
 def setUp(self):
     super(TestSQLBackend, self).setUp()
     self.db = self.kwargs['dbmaker']()
     self.access = SQLAccessBackend(MagicMock(), **self.kwargs)
示例#7
0
 def setUpClass(cls):
     super(TestSQLBackend, cls).setUpClass()
     cls.settings = {
         'auth.db.url': 'sqlite:///:memory:',
     }
     cls.kwargs = SQLAccessBackend.configure(cls.settings)
示例#8
0
 def setUp(self):
     super(TestSQLBackend, self).setUp()
     self.db = SQLAccessBackend.dbmaker()
     self.access = SQLAccessBackend(MagicMock())
示例#9
0
class TestSQLBackend(unittest.TestCase):

    """ Tests for the SQL access backend """
    @classmethod
    def setUpClass(cls):
        super(TestSQLBackend, cls).setUpClass()
        settings = {
            'auth.db.url': 'sqlite:///:memory:',
        }
        SQLAccessBackend.configure(settings)

    def setUp(self):
        super(TestSQLBackend, self).setUp()
        self.db = SQLAccessBackend.dbmaker()
        self.access = SQLAccessBackend(MagicMock())

    def tearDown(self):
        super(TestSQLBackend, self).tearDown()
        transaction.abort()
        self.db.query(User).delete()
        self.db.query(UserPermission).delete()
        self.db.query(GroupPermission).delete()
        self.db.query(Group).delete()
        self.db.execute(association_table.delete())  # pylint: disable=E1120
        transaction.commit()
        self.access.db.close()
        self.db.close()

    def test_verify(self):
        """ Verify login credentials against database """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertTrue(valid)

        valid = self.access.verify_user('foo', 'barrrr')
        self.assertFalse(valid)

    def test_verify_pending(self):
        """ Pending users fail to verify """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertFalse(valid)

    def test_admin(self):
        """ Retrieve admin status from database """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertTrue(is_admin)

    def test_admin_default_false(self):
        """ The default admin status is False """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertFalse(is_admin)

    def test_user_groups(self):
        """ Retrieve a user's groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.update([g1, g2])
        self.db.add_all([user, g1, g2])
        transaction.commit()
        groups = self.access.groups('foo')
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_groups(self):
        """ Retrieve all groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.add(g1)
        user.groups.add(g2)
        self.db.add(user)
        transaction.commit()
        groups = self.access.groups()
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_group_members(self):
        """ Fetch all members of a group """
        u1 = make_user('u1', 'bar', False)
        u2 = make_user('u2', 'bar', False)
        u3 = make_user('u3', 'bar', False)
        g1 = Group('g1')
        g1.users.update([u1, u2])
        self.db.add_all([u1, u2, u3, g1])
        transaction.commit()
        users = self.access.group_members('g1')
        self.assertItemsEqual(users, ['u1', 'u2'])

    def test_all_user_permissions(self):
        """ Retrieve all user permissions on package from database """
        user = make_user('foo', 'bar', False)
        user2 = make_user('foo2', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg1', 'foo2', True, True)
        self.db.add_all([user, user2, p1, p2])
        transaction.commit()
        perms = self.access.user_permissions('pkg1')
        self.assertEqual(perms, {
            'foo': ['read'],
            'foo2': ['read', 'write'],
        })

    def test_user_permissions(self):
        """ Retrieve a user's permissions on package from database """
        user = make_user('foo', 'bar', False)
        user2 = make_user('foo2', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg1', 'foo2', True, True)
        self.db.add_all([user, user2, p1, p2])
        transaction.commit()
        perms = self.access.user_permissions('pkg1', 'foo')
        self.assertEqual(perms, ['read'])

    def test_all_group_permissions(self):
        """ Retrieve all group permissions from database """
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        p1 = GroupPermission('pkg1', 'brotatos', True, False)
        p2 = GroupPermission('pkg1', 'sharkfest', True, True)
        self.db.add_all([g1, g2, p1, p2])
        transaction.commit()
        perms = self.access.group_permissions('pkg1')
        self.assertEqual(perms, {
            'brotatos': ['read'],
            'sharkfest': ['read', 'write'],
        })

    def test_group_permissions(self):
        """ Retrieve a group's permissions from database """
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        p1 = GroupPermission('pkg1', 'brotatos', True, False)
        p2 = GroupPermission('pkg1', 'sharkfest', True, True)
        self.db.add_all([g1, g2, p1, p2])
        transaction.commit()
        perms = self.access.group_permissions('pkg1', 'brotatos')
        self.assertEqual(perms, ['read'])

    def test_user_package_perms(self):
        """ Fetch all packages a user has permissions on """
        user = make_user('foo', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg2', 'foo', True, True)
        self.db.add_all([user, p1, p2])
        transaction.commit()
        perms = self.access.user_package_permissions('foo')
        self.assertEqual(perms, [
            {'package': 'pkg1', 'permissions': ['read']},
            {'package': 'pkg2', 'permissions': ['read', 'write']},
        ])

    def test_group_package_perms(self):
        """ Fetch all packages a group has permissions on """
        g1 = Group('foo')
        p1 = GroupPermission('pkg1', 'foo', True, False)
        p2 = GroupPermission('pkg2', 'foo', True, True)
        self.db.add_all([g1, p1, p2])
        transaction.commit()
        perms = self.access.group_package_permissions('foo')
        self.assertEqual(perms, [
            {'package': 'pkg1', 'permissions': ['read']},
            {'package': 'pkg2', 'permissions': ['read', 'write']},
        ])

    def test_user_data(self):
        """ Retrieve all users """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        u2 = make_user('bar', 'bar', False)
        g1 = Group('foobars')
        u2.groups.add(g1)
        self.db.add_all([u1, u2, g1])
        transaction.commit()
        users = self.access.user_data()
        self.assertItemsEqual(users, [
            {'username': '******', 'admin': True},
            {'username': '******', 'admin': False},
        ])

    def test_single_user_data(self):
        """ Retrieve a single user's data """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        g1 = Group('foobars')
        u1.groups.add(g1)
        self.db.add_all([u1, g1])
        transaction.commit()
        user = self.access.user_data('foo')
        self.assertEqual(user, {
            'username': '******',
            'admin': True,
            'groups': ['foobars'],
        })

    def test_no_need_admin(self):
        """ If admin exists, don't need an admin """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.assertFalse(self.access.need_admin())

    def test_need_admin(self):
        """ If admin doesn't exist, need an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.assertTrue(self.access.need_admin())

    # Tests for mutable backend methods

    def test_register(self):
        """ Register a new user """
        self.access.register('foo', 'bar')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertEqual(user.username, 'foo')

    def test_pending(self):
        """ Registering a user puts them in pending list """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.pending_users()
        self.assertEqual(users, ['foo'])

    def test_pending_not_in_users(self):
        """ Pending users are not listed in all_users """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.user_data()
        self.assertEqual(users, [])

    def test_approve(self):
        """ Approving user marks them as not pending """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        self.access.approve_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertFalse(user.pending)

    def test_edit_password(self):
        """ Users can edit their passwords """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_password('foo', 'baz')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertTrue(self.access.verify_user('foo', 'baz'))

    def test_delete_user(self):
        """ Can delete users """
        user = make_user('foo', 'bar', False)
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.delete_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertIsNone(user)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_make_admin(self):
        """ Can make a user an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', True)
        transaction.commit()
        self.db.add(user)
        self.assertTrue(user.admin)

    def test_remove_admin(self):
        """ Can demote an admin to normal user """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', False)
        transaction.commit()
        self.db.add(user)
        self.assertFalse(user.admin)

    def test_add_user_to_group(self):
        """ Can add a user to a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual([g.name for g in user.groups], ['g1'])

    def test_remove_user_from_group(self):
        """ Can remove a user from a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.groups), 0)

    def test_create_group(self):
        """ Can create a group """
        self.access.create_group('g1')
        transaction.commit()
        group = self.db.query(Group).first()
        self.assertIsNotNone(group)
        self.assertEqual(group.name, 'g1')

    def test_delete_group(self):
        """ Can delete groups """
        user = make_user('foo', 'bar')
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.delete_group('foobar')
        transaction.commit()
        count = self.db.query(Group).count()
        self.assertEqual(count, 0)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_grant_user_permission(self):
        """ Can give users permissions on a package """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 1)
        perm = user.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_revoke_user_permission(self):
        """ Can revoke user permissions on a package """
        user = make_user('foo', 'bar', False)
        perm = UserPermission('pkg1', 'foo', read=True)
        self.db.add_all([user, perm])
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 0)

    def test_grant_group_permission(self):
        """ Can give groups permissions on a package """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 1)
        perm = g.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_revoke_group_permission(self):
        """ Can revoke group permissions on a package """
        g = Group('foo')
        perm = GroupPermission('pkg1', 'foo', read=True)
        self.db.add_all([g, perm])
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 0)
 def setUp(self):
     super(TestSQLBackend, self).setUp()
     self.db = self.kwargs['dbmaker']()
     self.access = SQLAccessBackend(MagicMock(), **self.kwargs)
 def setUpClass(cls):
     super(TestSQLBackend, cls).setUpClass()
     cls.settings = {
         'auth.db.url': 'sqlite:///:memory:',
     }
     cls.kwargs = SQLAccessBackend.configure(cls.settings)
class TestSQLBackend(unittest.TestCase):

    """ Tests for the SQL access backend """
    @classmethod
    def setUpClass(cls):
        super(TestSQLBackend, cls).setUpClass()
        cls.settings = {
            'auth.db.url': 'sqlite:///:memory:',
        }
        cls.kwargs = SQLAccessBackend.configure(cls.settings)

    def setUp(self):
        super(TestSQLBackend, self).setUp()
        self.db = self.kwargs['dbmaker']()
        self.access = SQLAccessBackend(MagicMock(), **self.kwargs)

    def tearDown(self):
        super(TestSQLBackend, self).tearDown()
        transaction.abort()
        self.db.query(User).delete()
        self.db.query(UserPermission).delete()
        self.db.query(GroupPermission).delete()
        self.db.query(Group).delete()
        self.db.execute(association_table.delete())  # pylint: disable=E1120
        transaction.commit()
        self.access.db.close()
        self.db.close()

    def test_verify(self):
        """ Verify login credentials against database """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertTrue(valid)

        valid = self.access.verify_user('foo', 'barrrr')
        self.assertFalse(valid)

    def test_verify_pending(self):
        """ Pending users fail to verify """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        valid = self.access.verify_user('foo', 'bar')
        self.assertFalse(valid)

    def test_admin(self):
        """ Retrieve admin status from database """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertTrue(is_admin)

    def test_admin_default_false(self):
        """ The default admin status is False """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        is_admin = self.access.is_admin('foo')
        self.assertFalse(is_admin)

    def test_user_groups(self):
        """ Retrieve a user's groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.update([g1, g2])
        self.db.add_all([user, g1, g2])
        transaction.commit()
        groups = self.access.groups('foo')
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_groups(self):
        """ Retrieve all groups from database """
        user = make_user('foo', 'bar', False)
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        user.groups.add(g1)
        user.groups.add(g2)
        self.db.add(user)
        transaction.commit()
        groups = self.access.groups()
        self.assertItemsEqual(groups, ['brotatos', 'sharkfest'])

    def test_group_members(self):
        """ Fetch all members of a group """
        u1 = make_user('u1', 'bar', False)
        u2 = make_user('u2', 'bar', False)
        u3 = make_user('u3', 'bar', False)
        g1 = Group('g1')
        g1.users.update([u1, u2])
        self.db.add_all([u1, u2, u3, g1])
        transaction.commit()
        users = self.access.group_members('g1')
        self.assertItemsEqual(users, ['u1', 'u2'])

    def test_all_user_permissions(self):
        """ Retrieve all user permissions on package from database """
        user = make_user('foo', 'bar', False)
        user2 = make_user('foo2', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg1', 'foo2', True, True)
        self.db.add_all([user, user2, p1, p2])
        transaction.commit()
        perms = self.access.user_permissions('pkg1')
        self.assertEqual(perms, {
            'foo': ['read'],
            'foo2': ['read', 'write'],
        })

    def test_user_permissions(self):
        """ Retrieve a user's permissions on package from database """
        user = make_user('foo', 'bar', False)
        user2 = make_user('foo2', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg1', 'foo2', True, True)
        self.db.add_all([user, user2, p1, p2])
        transaction.commit()
        perms = self.access.user_permissions('pkg1', 'foo')
        self.assertEqual(perms, ['read'])

    def test_all_group_permissions(self):
        """ Retrieve all group permissions from database """
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        p1 = GroupPermission('pkg1', 'brotatos', True, False)
        p2 = GroupPermission('pkg1', 'sharkfest', True, True)
        self.db.add_all([g1, g2, p1, p2])
        transaction.commit()
        perms = self.access.group_permissions('pkg1')
        self.assertEqual(perms, {
            'brotatos': ['read'],
            'sharkfest': ['read', 'write'],
        })

    def test_group_permissions(self):
        """ Retrieve a group's permissions from database """
        g1 = Group('brotatos')
        g2 = Group('sharkfest')
        p1 = GroupPermission('pkg1', 'brotatos', True, False)
        p2 = GroupPermission('pkg1', 'sharkfest', True, True)
        self.db.add_all([g1, g2, p1, p2])
        transaction.commit()
        perms = self.access.group_permissions('pkg1', 'brotatos')
        self.assertEqual(perms, ['read'])

    def test_user_package_perms(self):
        """ Fetch all packages a user has permissions on """
        user = make_user('foo', 'bar', False)
        p1 = UserPermission('pkg1', 'foo', True, False)
        p2 = UserPermission('pkg2', 'foo', True, True)
        self.db.add_all([user, p1, p2])
        transaction.commit()
        perms = self.access.user_package_permissions('foo')
        self.assertEqual(perms, [
            {'package': 'pkg1', 'permissions': ['read']},
            {'package': 'pkg2', 'permissions': ['read', 'write']},
        ])

    def test_group_package_perms(self):
        """ Fetch all packages a group has permissions on """
        g1 = Group('foo')
        p1 = GroupPermission('pkg1', 'foo', True, False)
        p2 = GroupPermission('pkg2', 'foo', True, True)
        self.db.add_all([g1, p1, p2])
        transaction.commit()
        perms = self.access.group_package_permissions('foo')
        self.assertEqual(perms, [
            {'package': 'pkg1', 'permissions': ['read']},
            {'package': 'pkg2', 'permissions': ['read', 'write']},
        ])

    def test_user_data(self):
        """ Retrieve all users """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        u2 = make_user('bar', 'bar', False)
        g1 = Group('foobars')
        u2.groups.add(g1)
        self.db.add_all([u1, u2, g1])
        transaction.commit()
        users = self.access.user_data()
        self.assertItemsEqual(users, [
            {'username': '******', 'admin': True},
            {'username': '******', 'admin': False},
        ])

    def test_single_user_data(self):
        """ Retrieve a single user's data """
        u1 = make_user('foo', 'bar', False)
        u1.admin = True
        g1 = Group('foobars')
        u1.groups.add(g1)
        self.db.add_all([u1, g1])
        transaction.commit()
        user = self.access.user_data('foo')
        self.assertEqual(user, {
            'username': '******',
            'admin': True,
            'groups': ['foobars'],
        })

    def test_no_need_admin(self):
        """ If admin exists, don't need an admin """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.assertFalse(self.access.need_admin())

    def test_need_admin(self):
        """ If admin doesn't exist, need an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.assertTrue(self.access.need_admin())

    # Tests for mutable backend methods

    def test_register(self):
        """ Register a new user """
        self.access.register('foo', 'bar')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertEqual(user.username, 'foo')
        self.assertTrue(pwd_context.verify('bar', user.password))

    def test_pending(self):
        """ Registering a user puts them in pending list """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.pending_users()
        self.assertEqual(users, ['foo'])

    def test_pending_not_in_users(self):
        """ Pending users are not listed in all_users """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        users = self.access.user_data()
        self.assertEqual(users, [])

    def test_approve(self):
        """ Approving user marks them as not pending """
        user = make_user('foo', 'bar')
        self.db.add(user)
        transaction.commit()
        self.access.approve_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertFalse(user.pending)

    def test_edit_password(self):
        """ Users can edit their passwords """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_password('foo', 'baz')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertTrue(self.access.verify_user('foo', 'baz'))

    def test_delete_user(self):
        """ Can delete users """
        user = make_user('foo', 'bar', False)
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.delete_user('foo')
        transaction.commit()
        user = self.db.query(User).first()
        self.assertIsNone(user)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_make_admin(self):
        """ Can make a user an admin """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', True)
        transaction.commit()
        self.db.add(user)
        self.assertTrue(user.admin)

    def test_remove_admin(self):
        """ Can demote an admin to normal user """
        user = make_user('foo', 'bar', False)
        user.admin = True
        self.db.add(user)
        transaction.commit()
        self.access.set_user_admin('foo', False)
        transaction.commit()
        self.db.add(user)
        self.assertFalse(user.admin)

    def test_add_user_to_group(self):
        """ Can add a user to a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual([g.name for g in user.groups], ['g1'])

    def test_remove_user_from_group(self):
        """ Can remove a user from a group """
        user = make_user('foo', 'bar', False)
        group = Group('g1')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.edit_user_group('foo', 'g1', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.groups), 0)

    def test_create_group(self):
        """ Can create a group """
        self.access.create_group('g1')
        transaction.commit()
        group = self.db.query(Group).first()
        self.assertIsNotNone(group)
        self.assertEqual(group.name, 'g1')

    def test_delete_group(self):
        """ Can delete groups """
        user = make_user('foo', 'bar')
        group = Group('foobar')
        user.groups.add(group)
        self.db.add_all([user, group])
        transaction.commit()
        self.access.delete_group('foobar')
        transaction.commit()
        count = self.db.query(Group).count()
        self.assertEqual(count, 0)
        count = self.db.query(association_table).count()
        self.assertEqual(count, 0)

    def test_grant_user_read_permission(self):
        """ Can give users read permissions on a package """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 1)
        perm = user.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_grant_user_write_permission(self):
        """ Can give users write permissions on a package """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'write', True)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 1)
        perm = user.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertFalse(perm.read)
        self.assertTrue(perm.write)

    def test_grant_user_bad_permission(self):
        """ Attempting to grant a bad permission raises ValueError """
        user = make_user('foo', 'bar', False)
        self.db.add(user)
        transaction.commit()
        with self.assertRaises(ValueError):
            self.access.edit_user_permission('pkg1', 'foo', 'wiggle', True)

    def test_revoke_user_permission(self):
        """ Can revoke user permissions on a package """
        user = make_user('foo', 'bar', False)
        perm = UserPermission('pkg1', 'foo', read=True)
        self.db.add_all([user, perm])
        transaction.commit()
        self.access.edit_user_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(user)
        self.assertEqual(len(user.permissions), 0)

    def test_grant_group_read_permission(self):
        """ Can give groups read permissions on a package """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', True)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 1)
        perm = g.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertTrue(perm.read)
        self.assertFalse(perm.write)

    def test_grant_group_write_permission(self):
        """ Can give groups write permissions on a package """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'write', True)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 1)
        perm = g.permissions[0]
        self.assertEqual(perm.package, 'pkg1')
        self.assertFalse(perm.read)
        self.assertTrue(perm.write)

    def test_grant_group_bad_permission(self):
        """ Attempting to grant a bad permission raises ValueError """
        g = Group('foo')
        self.db.add(g)
        transaction.commit()
        with self.assertRaises(ValueError):
            self.access.edit_group_permission('pkg1', 'foo', 'wiggle', True)

    def test_revoke_group_permission(self):
        """ Can revoke group permissions on a package """
        g = Group('foo')
        perm = GroupPermission('pkg1', 'foo', read=True)
        self.db.add_all([g, perm])
        transaction.commit()
        self.access.edit_group_permission('pkg1', 'foo', 'read', False)
        transaction.commit()
        self.db.add(g)
        self.assertEqual(len(g.permissions), 0)

    def test_enable_registration(self):
        """ Can set the 'enable registration' flag """
        self.access.set_allow_register(True)
        self.assertTrue(self.access.allow_register())
        self.access.set_allow_register(False)
        self.assertFalse(self.access.allow_register())

    def test_dump(self):
        """ Can dump all data to json format """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)

        data = self.access.dump()

        self.assertFalse(data['allow_register'])

        # users
        self.assertEqual(len(data['users']), 2)
        for user in data['users']:
            self.assertTrue(pwd_context.verify(user['username'],
                                               user['password']))
            self.assertFalse(user['admin'] ^ (user['username'] == 'user3'))

        # pending users
        self.assertEqual(len(data['pending_users']), 1)
        user = data['pending_users'][0]
        self.assertTrue(pwd_context.verify(user['username'], user['password']))

        # groups
        self.assertEqual(len(data['groups']), 2)
        self.assertItemsEqual(data['groups']['g1'], ['user2'])
        self.assertItemsEqual(data['groups']['g2'], ['user2', 'user3'])

        # user package perms
        self.assertEqual(data['packages']['users'], {
            'pkg1': {
                'user2': ['read'],
            },
            'pkg2': {
                'user3': ['read', 'write'],
            },
        })

        # group package perms
        self.assertEqual(data['packages']['groups'], {
            'pkg1': {
                'g1': ['read'],
            },
            'pkg2': {
                'g2': ['read', 'write'],
            },
        })

    def test_load(self):
        """ Access control can load universal format data """
        user1 = make_user('user1', 'user1', True)
        user2 = make_user('user2', 'user2', False)
        user3 = make_user('user3', 'user3', False)
        user3.admin = True
        self.db.add_all([user1, user2, user3])
        transaction.commit()
        self.access.set_allow_register(False)
        self.access.create_group('g1')
        self.access.create_group('g2')
        self.access.edit_user_group('user2', 'g1', True)
        self.access.edit_user_group('user2', 'g2', True)
        self.access.edit_user_group('user3', 'g2', True)
        self.access.edit_user_permission('pkg1', 'user2', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'read', True)
        self.access.edit_user_permission('pkg2', 'user3', 'write', True)
        self.access.edit_group_permission('pkg1', 'g1', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'read', True)
        self.access.edit_group_permission('pkg2', 'g2', 'write', True)

        data1 = self.access.dump()

        SQLAccessBackend.configure(self.settings)
        kwargs = SQLAccessBackend.configure(self.settings)
        access2 = SQLAccessBackend(MagicMock(), **kwargs)
        access2.load(data1)
        data2 = access2.dump()

        def assert_nice_equals(obj1, obj2):
            """ Assertion that handles unordered lists inside dicts """
            if isinstance(obj1, dict):
                self.assertEqual(len(obj1), len(obj2))
                for key, val in obj1.iteritems():
                    assert_nice_equals(val, obj2[key])
            elif isinstance(obj1, list):
                self.assertItemsEqual(obj1, obj2)
            else:
                self.assertEqual(obj1, obj2)

        assert_nice_equals(data2, data1)

        # Load operation should be idempotent
        access2.load(data2)
        data3 = access2.dump()
        assert_nice_equals(data3, data2)