Skip to content

Commit

Permalink
[tests] Update TestMultitenantAdminMixin to use default operator group
Browse files Browse the repository at this point in the history
…#106

Closes #106
  • Loading branch information
codesankalp authored Mar 8, 2022
1 parent b70b735 commit 9ac518d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 32 deletions.
21 changes: 17 additions & 4 deletions openwisp_users/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,8 +1666,15 @@ def _create_multitenancy_test_env(self):
organization_user3 = self._create_org_user(
organization=org3, user=operator, is_admin=True
)
administrator = self._create_administrator()
organization_user4 = self._create_org_user(
organization=org3, user=administrator, is_admin=True
)
organization_user31 = self._create_org_user(organization=org3, user=user3)
organization_user1o = self._create_org_user(organization=org1, user=operator)
organization_user1a = self._create_org_user(
organization=org1, user=administrator
)
data = dict(
org1=org1,
org2=org2,
Expand All @@ -1683,11 +1690,14 @@ def _create_multitenancy_test_env(self):
organization_user12=organization_user12,
organization_user22=organization_user22,
organization_user3=organization_user3,
organization_user4=organization_user4,
organization_user1o=organization_user1o,
organization_user1a=organization_user1a,
organization_user31=organization_user31,
organization_owner1=organization_owner1,
organization_owner2=organization_owner2,
operator=operator,
administrator=administrator,
)
return data

Expand All @@ -1698,7 +1708,7 @@ def _make_org_manager(self, user, org):

def test_multitenancy_organization_user_queryset(self):
data = self._create_multitenancy_test_env()
self._make_org_manager(data['operator'], data['org1'])
self._make_org_manager(data['administrator'], data['org1'])
self._test_multitenant_admin(
url=reverse(f'admin:{self.app_label}_organizationuser_changelist'),
hidden=[
Expand All @@ -1711,15 +1721,17 @@ def test_multitenancy_organization_user_queryset(self):
data['organization_user1o'].user.username,
data['organization_user3'].user.username,
],
administrator=True,
)

def test_multitenancy_organization_owner_queryset(self):
data = self._create_multitenancy_test_env()
self._make_org_manager(data['operator'], data['org1'])
self._make_org_manager(data['administrator'], data['org1'])
self._test_multitenant_admin(
url=reverse(f'admin:{self.app_label}_organizationowner_changelist'),
hidden=[data['organization_owner2'].organization_user.user.username],
visible=[data['organization_owner1'].organization_user.user.username],
administrator=True,
)

def test_useradmin_specific_multitenancy_costraints(self):
Expand All @@ -1728,6 +1740,7 @@ def test_useradmin_specific_multitenancy_costraints(self):
url=reverse(f'admin:{self.app_label}_user_changelist'),
visible=[data['user3'], data['operator']],
hidden=[data['user2'], data['user22'], data['user1'], data['user12']],
administrator=True,
)

def test_multitenant_admin_manager_only(self):
Expand Down Expand Up @@ -1765,7 +1778,7 @@ class TestAdmin(MultitenantAdminMixin):

def test_organization_user_filter(self):
data = self._create_multitenancy_test_env()
self._make_org_manager(data['operator'], data['org1'])
self._make_org_manager(data['administrator'], data['org1'])
url = reverse(f'admin:{self.app_label}_user_changelist')

with self.subTest('test superadmin'):
Expand All @@ -1776,7 +1789,7 @@ def test_organization_user_filter(self):
self.assertContains(response, f'href="?organization={org.pk}">')

with self.subTest('test non superadmin'):
user = User.objects.get(username='operator')
user = User.objects.get(username='administrator')
self.client.force_login(user)
response = self.client.get(url)
for pk in user.organizations_managed:
Expand Down
40 changes: 28 additions & 12 deletions openwisp_users/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from django.db.models import Q
from django.urls import reverse
from swapper import load_model

Organization = load_model('openwisp_users', 'Organization')
OrganizationOwner = load_model('openwisp_users', 'OrganizationOwner')
OrganizationUser = load_model('openwisp_users', 'OrganizationUser')
Group = load_model('openwisp_users', 'Group')
User = get_user_model()


Expand Down Expand Up @@ -42,14 +42,6 @@ def _login(self, username='admin', password='tester'):
def _logout(self):
self.client.logout()

operator_permission_filters = []

def get_operator_permissions(self):
filters = Q()
for filter in self.operator_permission_filters:
filters = filters | Q(**filter)
return Permission.objects.filter(filters)

def _create_operator(self, organizations=[], **kwargs):
opts = dict(
username='operator',
Expand All @@ -59,23 +51,47 @@ def _create_operator(self, organizations=[], **kwargs):
)
opts.update(kwargs)
operator = User.objects.create_user(**opts)
operator.user_permissions.add(*self.get_operator_permissions())
groups = Group.objects.filter(name='Operator')
operator.groups.set(groups)
for organization in organizations:
OrganizationUser.objects.create(
user=operator, organization=organization, is_admin=True
)
operator.organizations_dict # force caching
return operator

def _test_multitenant_admin(self, url, visible, hidden, select_widget=False):
def _create_administrator(self, organizations=[], **kwargs):
opts = dict(
username='administrator',
password='tester',
email='administrator@test.com',
is_staff=True,
)
opts.update(kwargs)
administrator = User.objects.create_user(**opts)
groups = Group.objects.filter(name='Administrator')
administrator.groups.set(groups)
for organization in organizations:
OrganizationUser.objects.create(
user=administrator, organization=organization, is_admin=True
)
administrator.organizations_dict # force caching
return administrator

def _test_multitenant_admin(
self, url, visible, hidden, select_widget=False, administrator=False
):
"""
reusable test function that ensures different users
can see the right objects.
an operator with limited permissions will not be able
to see the elements contained in ``hidden``, while
a superuser can see everything.
"""
self._login(username='operator', password='tester')
if administrator:
self._login(username='administrator', password='tester')
else:
self._login(username='operator', password='tester')
response = self.client.get(url)

# utility format function
Expand Down
16 changes: 16 additions & 0 deletions tests/testapp/migrations/0005_default_groups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Manually Created

from django.db import migrations
from testapp.migrations import update_administrator_permissions


class Migration(migrations.Migration):
dependencies = [
('testapp', '0004_library'),
]

operations = [
migrations.RunPython(
update_administrator_permissions, reverse_code=migrations.RunPython.noop
),
]
27 changes: 27 additions & 0 deletions tests/testapp/migrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import swapper
from django.contrib.auth.management import create_permissions
from django.contrib.auth.models import Permission
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q


def update_administrator_permissions(apps, schema_editor):
model_name = swapper.get_model_name('openwisp_users', 'Group')
model_label = swapper.split(model_name)[0]
Group = apps.get_model(model_label, 'Group')

for app_config in apps.get_app_configs():
app_config.models_module = True
create_permissions(app_config, apps=apps, verbosity=0)
app_config.models_module = None

try:
operator = Group.objects.get(name='Administrator')
permissions = Permission.objects.filter(
Q(codename__endswith='template')
| Q(codename__endswith='shelf')
| Q(codename__endswith='book')
).values_list('pk', flat=True)
operator.permissions.add(*permissions)
except ObjectDoesNotExist:
pass
18 changes: 9 additions & 9 deletions tests/testapp/tests/test_filter_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,11 @@ def test_unauthorized_user(self):
self.assertEqual(r.status_code, 401)

def test_presence_of_null_org_field(self):
operator = self._get_operator()
administrator = self._create_administrator()
self._create_org_user(
user=operator, is_admin=True, organization=self._get_org('org_a')
user=administrator, is_admin=True, organization=self._get_org('org_a')
)
token = self._obtain_auth_token(operator)
token = self._obtain_auth_token(administrator)
url = reverse('test_template_list')
response = self.client.get(
url, {'format': 'api'}, HTTP_AUTHORIZATION=f'Bearer {token}'
Expand Down Expand Up @@ -235,23 +235,23 @@ def test_filter_by_org_managed_with_org_field(self):
self.assertEqual(response.status_code, 404)

def test_get_book_nested_shelf(self):
operator = self._get_operator()
administrator = self._create_administrator()
self._create_org_user(
user=operator, is_admin=True, organization=self._get_org('org_a')
user=administrator, is_admin=True, organization=self._get_org('org_a')
)
token = self._obtain_auth_token(operator)
token = self._obtain_auth_token(administrator)
url = reverse('test_book_nested_shelf')
with self.assertNumQueries(6):
response = self.client.get(url, HTTP_AUTHORIZATION=f'Bearer {token}')
self.assertEqual(response.status_code, 200)

def test_post_book_nested_shelf(self):
org1 = self._get_org('org_a')
operator = self._get_operator()
administrator = self._create_administrator()
self._create_org_user(
user=operator, is_admin=True, organization=self._get_org('org_a')
user=administrator, is_admin=True, organization=self._get_org('org_a')
)
token = self._obtain_auth_token(operator)
token = self._obtain_auth_token(administrator)
url = reverse('test_book_nested_shelf')
data = {
'shelf': {'name': 'test-shelf', 'organization': org1.pk},
Expand Down
18 changes: 13 additions & 5 deletions tests/testapp/tests/test_multitenancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
class TestMultitenancy(TestMultitenancyMixin, TestCase):
book_model = Book
shelf_model = Shelf
operator_permission_filter = [
{'codename__endswith': 'book'},
{'codename__endswith': 'shelf'},
]

def _create_multitenancy_test_env(self):
org1 = self._create_org(name='org1')
org2 = self._create_org(name='org2')
inactive = self._create_org(name='inactive-org', is_active=False)
operator = self._create_operator(organizations=[org1, inactive])
operator = self._create_operator(
organizations=[org1, inactive],
)
administrator = self._create_administrator(
organizations=[org1, inactive],
)
s1 = self._create_shelf(name='shell1', organization=org1)
s2 = self._create_shelf(name='shell2', organization=org2)
s3 = self._create_shelf(name='shell3', organization=inactive)
Expand All @@ -35,6 +36,7 @@ def _create_multitenancy_test_env(self):
org2=org2,
inactive=inactive,
operator=operator,
administrator=administrator,
)
return data

Expand All @@ -44,6 +46,7 @@ def test_shelf_queryset(self):
url=reverse('admin:testapp_shelf_changelist'),
visible=[data['s1'].name, data['org1'].name],
hidden=[data['s2'].name, data['org2'].name, data['s3_inactive'].name],
administrator=True,
)

def test_shelf_organization_fk_queryset(self):
Expand All @@ -53,6 +56,7 @@ def test_shelf_organization_fk_queryset(self):
visible=[data['org1'].name],
hidden=[data['org2'].name, data['inactive']],
select_widget=True,
administrator=True,
)

def test_book_queryset(self):
Expand All @@ -61,6 +65,7 @@ def test_book_queryset(self):
url=reverse('admin:testapp_book_changelist'),
visible=[data['b1'].name, data['org1'].name],
hidden=[data['b2'].name, data['org2'].name, data['b3_inactive'].name],
administrator=True,
)

def test_book_organization_fk_queryset(self):
Expand All @@ -70,6 +75,7 @@ def test_book_organization_fk_queryset(self):
visible=[data['org1'].name],
hidden=[data['org2'].name, data['inactive']],
select_widget=True,
administrator=True,
)

def test_book_shelf_filter(self):
Expand All @@ -79,6 +85,7 @@ def test_book_shelf_filter(self):
url=reverse('admin:testapp_book_changelist'),
visible=[data['s1'].name, s_special.name],
hidden=[data['s2'].name, data['s3_inactive'].name],
administrator=True,
)

def test_book_shelf_fk_queryset(self):
Expand All @@ -88,4 +95,5 @@ def test_book_shelf_fk_queryset(self):
visible=[data['s1'].name],
hidden=[data['s2'].name, data['s3_inactive'].name],
select_widget=True,
administrator=True,
)
5 changes: 3 additions & 2 deletions tests/testapp/tests/test_permission_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def test_view_permission_with_administrator(self):
user = self._get_user()
administrator_group = Group.objects.get(name='Administrator')
change_perm = Permission.objects.get(codename='change_template')
administrator_group.permissions.set([])
administrator_group.permissions.add(change_perm)
user.groups.add(administrator_group)
org1 = self._get_org()
Expand All @@ -173,8 +174,8 @@ def test_view_permission_with_administrator(self):
def test_view_permission_with_operator_having_view_perm(self):
user = self._get_user()
operator_group = Group.objects.get(name='Operator')
view_perm = Permission.objects.get(codename='view_template')
operator_group.permissions.add(view_perm)
view_perm = Permission.objects.filter(codename='view_template')
operator_group.permissions.set(view_perm)
user.groups.add(operator_group)
org1 = self._get_org()
auth, t1 = self._get_auth_template(user, org1)
Expand Down

0 comments on commit 9ac518d

Please sign in to comment.