Skip to content

Commit

Permalink
Increased coverage, PEP8 fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisglass committed Aug 8, 2013
1 parent 323166c commit 1376242
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 49 deletions.
16 changes: 8 additions & 8 deletions rulez/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@
from collections import defaultdict

class Rule(object):
def __init__(self, codename, model, field_name='', view_param_pk='',
def __init__(self, codename, model, field_name='', view_param_pk='',
description=''):
self.field_name = field_name
self.field_name = field_name
self.description = description
self.codename = codename
self.model = model
self.view_param_pk = view_param_pk

registry = defaultdict(dict)

def register(codename, model, field_name='', view_param_pk='', description=''):
"""
This should be called from your models.py or wherever after your models are
declared (think admin registration)
"""

# Sanity check
if not field_name:
field_name = codename

if not hasattr(model,field_name):
raise NonexistentFieldName('Field %s does not exist on class %s' % (field_name,model.__name__))
registry[model].update({codename : Rule(codename, model, field_name,

registry[model].update({codename : Rule(codename, model, field_name,
view_param_pk, description)})

def get(codename, model):
return registry.get(model, {}).get(codename, None)
10 changes: 5 additions & 5 deletions rulez/rolez/cache_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ def counter_key(obj):
pk = obj.pk
obj_type = str(obj.__class__.__name__).lower()
return "%s-%s" % (obj_type, pk)

def increment_counter(obj):
"""
Invalidate the cache for the passed object.
"""
if obj: # If the object is None, do nothing (it's pointless)
if obj is not None: # If the object is None, do nothing (it's pointless)
cache.set(counter_key(obj), int(time.time()), 1*HOUR)

def get_counter(obj):
Expand All @@ -53,7 +53,7 @@ def roles_key(user, obj):
obj_counter = get_counter(obj)
user_id = get_user_pk(user)
user_counter = get_counter(user)
return "%s-%s-%s-%s-%s" % (user_id, user_counter, obj_type, obj_id,
return "%s-%s-%s-%s-%s" % (user_id, user_counter, obj_type, obj_id,
obj_counter)

def get_user_pk(user):
Expand All @@ -68,7 +68,7 @@ def get_user_pk(user):

def get_roles(user, obj):
"""
Get a list of roles assigned to a user for a specific instance from the
Get a list of roles assigned to a user for a specific instance from the
cache, or builds such a list if it is not found.
"""
# get roles for the user, if present:
Expand All @@ -81,7 +81,7 @@ def get_roles(user, obj):
user_roles = []
if not hasattr(obj, 'relevant_roles'):
raise RulesException('Cannot build roles cache for %s instance. Did you forget to define a "relevant_roles()" method on %s?' % (obj.__class__, obj.__class__))

relevant = obj.relevant_roles()
for role in relevant:
if role.is_member(user, obj):
Expand Down
47 changes: 36 additions & 11 deletions rulez/tests/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,37 @@
from django.test.testcases import TestCase
from rulez import registry
from rulez.backends import ObjectPermissionBackend
from rulez.exceptions import NonexistentFieldName
from rulez.exceptions import NonexistentFieldName, NotBooleanPermission
from rulez.registry import Rule


class MockModel():
pk = 999
not_callable = 'whatever'

def __init__(self):
self.attr_permission = True
self.attr_wrong_permission = "I'm not a boolean"

def mock_permission(self, user):
return True

def mock_simple_permission(self):
# just a callable, no "user" parameter
return True

def mock_non_boolean_permission(self, user):
return "Whatever"


class MockUser():
def __init__(self, is_active=True):
self.pk=666
self.is_active = is_active
def is_anonymous(self):
return False


class BackendTestCase(TestCase):

def create_fixtures(self):
Expand All @@ -39,7 +46,7 @@ def test_user_is_tested_for_rule(self):
back = ObjectPermissionBackend()
res = back.has_perm(self.user, 'mock_permission', self.model)
self.assertEqual(res, True)

def test_rules_returns_False_for_None_obj(self):
self.create_fixtures()
registry.register('mock_permission', MockModel)
Expand All @@ -53,33 +60,51 @@ def test_rules_returns_False_for_inexistant_rule(self):
back = ObjectPermissionBackend()
res = back.has_perm(self.user, 'whatever_permission', self.model)
self.assertEqual(res, False)

def test_user_is_tested_for_simple_rule(self):
self.create_fixtures()
registry.register('mock_simple_permission', MockModel)
back = ObjectPermissionBackend()
res = back.has_perm(self.user, 'mock_simple_permission', self.model)
self.assertEqual(res, True)

def test_user_is_tested_for_simple_rule_by_field_name(self):
self.create_fixtures()
registry.register('mock_permission', MockModel, field_name='mock_simple_permission')
registry.register(
'mock_permission', MockModel, field_name='mock_simple_permission')
back = ObjectPermissionBackend()
res = back.has_perm(self.user, 'mock_permission', self.model)
self.assertEqual(res, True)

def test_non_existant_filenames_are_caught(self):
self.create_fixtures()
codename = 'mock_permission'
rule = Rule(codename, MockModel, field_name='I_do_not_exist')
registry.registry[MockModel].update({codename : rule})
back = ObjectPermissionBackend()

self.assertRaises(NonexistentFieldName, back.has_perm, self.user, 'mock_permission', self.model)

self.assertRaises(
NonexistentFieldName, back.has_perm, self.user, 'mock_permission',
self.model)

def test_inactive_user_can_never_have_any_permissions(self):
self.create_fixtures()
registry.register('mock_permission', MockModel)
back = ObjectPermissionBackend()
res = back.has_perm(self.inactive_user, 'mock_permission', self.model)
self.assertEqual(res, False)
self.assertEqual(res, False)

def test_non_boolean_permissions_raises(self):
self.create_fixtures()
registry.register('mock_non_boolean_permission', MockModel)
back = ObjectPermissionBackend()
self.assertRaises(
NotBooleanPermission, back.has_perm, self.user,
'mock_non_boolean_permission', self.model)

def test_non_callable_permission_raises(self):
self.create_fixtures()
registry.register('not_callable', MockModel)
back = ObjectPermissionBackend()
self.assertRaises(
NotBooleanPermission, back.has_perm, self.user,
'not_callable', self.model)
62 changes: 37 additions & 25 deletions rulez/tests/roles_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,75 @@
get_user_pk, roles_key
from rulez.rolez.models import ModelRoleMixin


class Mock():
pk = 999


class MockUser():
def __init__(self):
self.pk=666
def is_anonymous(self):
return False


# Testing the model inheritence
class Tester(AbstractRole):
@classmethod
def is_member(cls, user, obj):
return getattr(user, 'member', False)



class TestModel(ModelRoleMixin):
pk = 1 # Just to emulate a Django model
roles = [Tester]


# The actual test case
class RolesCacheHelperTestCase(TestCase):

def setUp(self):
cache.cache.clear()

def test_incrementing_counter_works(self):
obj = Mock()
first = get_counter(obj)
self.assertEqual(first, 0)
increment_counter(obj)
second = get_counter(obj)
self.assertNotEqual(second, first)

def test_incrementing_counter_works_for_none(self):
increment_counter(None)

def test_get_roles_for_None_raises(self):
with self.assertRaises(AttributeError):
res = get_counter(None)
self.assertEqual(res, None)


def test_rulez_invalidate_works(self):
model = TestModel()
user = MockUser()
first = get_counter(model)
self.assertEqual(first, 0)
model.rulez_invalidate()
second = get_counter(model)
self.assertNotEqual(second, first)

def test_get_empty_roles_works(self):
model = TestModel()
user = MockUser()
res = get_roles(user, model)
self.assertEqual(res, [])

def test_user_with_role_works(self):
# Now let's make the user a member!
model = TestModel()
user = MockUser()
setattr(user, 'member', True)
res = get_roles(user, model)
self.assertEqual(len(res), 1)

def test_get_roles_cache_works(self):
# Now let's assert the cache works.
model = TestModel()
Expand All @@ -75,60 +88,59 @@ def test_get_roles_cache_works(self):
res2 = get_roles(user, model)
self.assertEqual(len(res2), 1)
self.assertEqual(res, res2)

def test_has_role_works(self):
model = TestModel()
user = MockUser()
setattr(user, 'member', True)
res = model.has_role(user, Tester)
self.assertEqual(res, True)

def test_doesnt_have_role_works(self):
model = TestModel()
user = MockUser()
res = model.has_role(user, Tester)
self.assertEqual(res, False)

def test_get_anonymous_user_works(self):
anon = AnonymousUser()
res = get_user_pk(anon)
self.assertEqual(res, 'anonymous')

def test_get_roles_works_for_anonymous(self):
model = TestModel()
user = AnonymousUser()
res = model.has_role(user, Tester)
self.assertEqual(res, False)

def test_get_counter_does_not_return_spaces(self):
obj = Mock()
user = MockUser()
roles_key(user, obj) # The first time, the counter == 0
increment_counter(obj) # Now there should be a timestamp
res = roles_key(user, obj)
self.assertTrue(' ' not in res)

def test_roles_for_users_on_users_raises_without_relevant_roles(self):
# If for some reasons you want to enforce rules on users...
django_user = User.objects.create(username="test",
email="[email protected]",
first_name="Test",
last_name = "Tester")
django_user = User.objects.create(username="test",
email="[email protected]",
first_name="Test",
last_name = "Tester")
user = MockUser() # That's faster
setattr(user, 'member', True)
with self.assertRaises(RulesException):
res = get_roles(user, django_user)
self.assertEqual(len(res), 1)

def test_roles_for_users_on_users_works_with_relevant_roles(self):
# If for some reasons you want to enforce rules on users...
django_user = User.objects.create(username="test",
email="[email protected]",
first_name="Test",
last_name = "Tester")
django_user = User.objects.create(username="test",
email="[email protected]",
first_name="Test",
last_name = "Tester")
setattr(django_user, 'relevant_roles', lambda : [Tester])
user = MockUser() # That's faster
setattr(user, 'member', True)
res = get_roles(user, django_user)
self.assertEqual(len(res), 1)

0 comments on commit 1376242

Please sign in to comment.