mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-31 15:06:32 +02:00
Add some unit tests
This commit is contained in:
parent
272d476592
commit
32edeb911b
2 changed files with 137 additions and 2 deletions
|
@ -162,13 +162,16 @@ class UserPortfolioPermission(TimeStampedModel):
|
||||||
# so called "forbidden" ones. But just member on their own cannot.
|
# so called "forbidden" ones. But just member on their own cannot.
|
||||||
# The solution to this is to only grab what is only COMMONLY "forbidden".
|
# The solution to this is to only grab what is only COMMONLY "forbidden".
|
||||||
# This will scale if we add more roles in the future.
|
# This will scale if we add more roles in the future.
|
||||||
|
# This is thes same as applying the `&` operator across all sets for each role.
|
||||||
common_forbidden_perms = set.intersection(
|
common_forbidden_perms = set.intersection(
|
||||||
*(set(cls.FORBIDDEN_PORTFOLIO_ROLE_PERMISSIONS.get(role, [])) for role in roles)
|
*[set(cls.FORBIDDEN_PORTFOLIO_ROLE_PERMISSIONS.get(role, [])) for role in roles]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the users current permissions overlap with any forbidden permissions
|
# Check if the users current permissions overlap with any forbidden permissions
|
||||||
|
# by getting the intersection between current user permissions, and forbidden ones.
|
||||||
|
# This is the same as portfolio_permissions & common_forbidden_perms.
|
||||||
portfolio_permissions = set(cls.get_portfolio_permissions(roles, additional_permissions))
|
portfolio_permissions = set(cls.get_portfolio_permissions(roles, additional_permissions))
|
||||||
return portfolio_permissions & common_forbidden_perms
|
return portfolio_permissions.intersection(common_forbidden_perms)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
"""Extends clean method to perform additional validation, which can raise errors in django admin."""
|
"""Extends clean method to perform additional validation, which can raise errors in django admin."""
|
||||||
|
|
|
@ -25,6 +25,7 @@ from registrar.admin import (
|
||||||
TransitionDomainAdmin,
|
TransitionDomainAdmin,
|
||||||
UserGroupAdmin,
|
UserGroupAdmin,
|
||||||
PortfolioAdmin,
|
PortfolioAdmin,
|
||||||
|
UserPortfolioPermissionAdmin,
|
||||||
)
|
)
|
||||||
from registrar.models import (
|
from registrar.models import (
|
||||||
Domain,
|
Domain,
|
||||||
|
@ -65,6 +66,8 @@ from django.contrib.sessions.backends.db import SessionStore
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from unittest.mock import ANY, patch, Mock
|
from unittest.mock import ANY, patch, Mock
|
||||||
|
from registrar.models.utility.portfolio_helper import validate_portfolio_invitation, validate_user_portfolio_permission
|
||||||
|
from django.forms import ValidationError
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -187,6 +190,93 @@ class TestDomainInvitationAdmin(TestCase):
|
||||||
self.assertContains(response, retrieved_html, count=1)
|
self.assertContains(response, retrieved_html, count=1)
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserPortfolioPermissionAdmin(TestCase):
|
||||||
|
"""Tests for the PortfolioInivtationAdmin class"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Create a client object"""
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.admin = ListHeaderAdmin(model=UserPortfolioPermissionAdmin, admin_site=AdminSite())
|
||||||
|
self.client = Client(HTTP_HOST="localhost:8080")
|
||||||
|
self.superuser = create_superuser()
|
||||||
|
self.portfolio = Portfolio.objects.create(organization_name="Test Portfolio", creator=self.superuser)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Delete all DomainInvitation objects"""
|
||||||
|
Portfolio.objects.all().delete()
|
||||||
|
PortfolioInvitation.objects.all().delete()
|
||||||
|
Contact.objects.all().delete()
|
||||||
|
User.objects.all().delete()
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_validate_user_portfolio_permission(self):
|
||||||
|
"""Tests validation of user portfolio permission"""
|
||||||
|
|
||||||
|
# Test validation fails when portfolio missing but permissions are present
|
||||||
|
permission = UserPortfolioPermission(user=self.superuser, roles=["organization_admin"], portfolio=None)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
validate_user_portfolio_permission(permission)
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"When portfolio roles or additional permissions are assigned, portfolio is required.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test validation fails when portfolio present but no permissions are present
|
||||||
|
permission = UserPortfolioPermission(user=self.superuser, roles=None, portfolio=self.portfolio)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
validate_user_portfolio_permission(permission)
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"When portfolio is assigned, portfolio roles or additional permissions are required.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test validation fails with forbidden permissions for single role
|
||||||
|
forbidden_member_roles = UserPortfolioPermission.FORBIDDEN_PORTFOLIO_ROLE_PERMISSIONS.get(
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_MEMBER
|
||||||
|
)
|
||||||
|
permission = UserPortfolioPermission(
|
||||||
|
user=self.superuser,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
|
||||||
|
additional_permissions=forbidden_member_roles,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
permission.clean()
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"These permissions cannot be assigned to Member: "
|
||||||
|
"<Create and edit members, View all domains and domain reports, View members>",
|
||||||
|
)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_get_forbidden_permissions_with_multiple_roles(self):
|
||||||
|
"""Tests that forbidden permissions are properly handled when a user has multiple roles"""
|
||||||
|
# Get forbidden permissions for member role
|
||||||
|
member_forbidden = UserPortfolioPermission.FORBIDDEN_PORTFOLIO_ROLE_PERMISSIONS.get(
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_MEMBER
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test with both admin and member roles
|
||||||
|
roles = [UserPortfolioRoleChoices.ORGANIZATION_ADMIN, UserPortfolioRoleChoices.ORGANIZATION_MEMBER]
|
||||||
|
|
||||||
|
# These permissions would be forbidden for member alone, but should be allowed
|
||||||
|
# when combined with admin role
|
||||||
|
permissions = UserPortfolioPermission.get_forbidden_permissions(
|
||||||
|
roles=roles, additional_permissions=member_forbidden
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should return empty set since no permissions are commonly forbidden between admin and member
|
||||||
|
self.assertEqual(permissions, set())
|
||||||
|
|
||||||
|
# Verify the same permissions are forbidden when only member role is present
|
||||||
|
member_only_permissions = UserPortfolioPermission.get_forbidden_permissions(
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER], additional_permissions=member_forbidden
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should return the forbidden permissions for member role
|
||||||
|
self.assertEqual(member_only_permissions, set(member_forbidden))
|
||||||
|
|
||||||
|
|
||||||
class TestPortfolioInvitationAdmin(TestCase):
|
class TestPortfolioInvitationAdmin(TestCase):
|
||||||
"""Tests for the PortfolioInvitationAdmin class as super user
|
"""Tests for the PortfolioInvitationAdmin class as super user
|
||||||
|
|
||||||
|
@ -204,9 +294,11 @@ class TestPortfolioInvitationAdmin(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Create a client object"""
|
"""Create a client object"""
|
||||||
self.client = Client(HTTP_HOST="localhost:8080")
|
self.client = Client(HTTP_HOST="localhost:8080")
|
||||||
|
self.portfolio = Portfolio.objects.create(organization_name="Test Portfolio", creator=self.superuser)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Delete all DomainInvitation objects"""
|
"""Delete all DomainInvitation objects"""
|
||||||
|
Portfolio.objects.all().delete()
|
||||||
PortfolioInvitation.objects.all().delete()
|
PortfolioInvitation.objects.all().delete()
|
||||||
Contact.objects.all().delete()
|
Contact.objects.all().delete()
|
||||||
|
|
||||||
|
@ -214,6 +306,46 @@ class TestPortfolioInvitationAdmin(TestCase):
|
||||||
def tearDownClass(self):
|
def tearDownClass(self):
|
||||||
User.objects.all().delete()
|
User.objects.all().delete()
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_portfolio_invitation_clean(self):
|
||||||
|
"""Tests validation of portfolio invitation permissions"""
|
||||||
|
|
||||||
|
# Test validation fails when portfolio missing but permissions present
|
||||||
|
invitation = PortfolioInvitation(email="test@example.com", roles=["organization_admin"], portfolio=None)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
invitation.clean()
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"When portfolio roles or additional permissions are assigned, portfolio is required.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test validation fails when portfolio present but no permissions
|
||||||
|
invitation = PortfolioInvitation(email="test@example.com", roles=None, portfolio=self.portfolio)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
invitation.clean()
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"When portfolio is assigned, portfolio roles or additional permissions are required.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test validation fails with forbidden permissions
|
||||||
|
forbidden_member_roles = UserPortfolioPermission.FORBIDDEN_PORTFOLIO_ROLE_PERMISSIONS.get(
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_MEMBER
|
||||||
|
)
|
||||||
|
invitation = PortfolioInvitation(
|
||||||
|
email="test@example.com",
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
|
||||||
|
additional_permissions=forbidden_member_roles,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
)
|
||||||
|
with self.assertRaises(ValidationError) as err:
|
||||||
|
invitation.clean()
|
||||||
|
self.assertEqual(
|
||||||
|
str(err.exception),
|
||||||
|
"These permissions cannot be assigned to Member: "
|
||||||
|
"<View all domains and domain reports, Create and edit members, View members>",
|
||||||
|
)
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_has_model_description(self):
|
def test_has_model_description(self):
|
||||||
"""Tests if this model has a model description on the table view"""
|
"""Tests if this model has a model description on the table view"""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue