1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-02 01:21:21 +03:00

Merge pull request #2060 from wwitzel3/3.0

Test refactoring
This commit is contained in:
Akita Noek 2016-05-26 11:23:56 -04:00
commit 11443eb22d
10 changed files with 665 additions and 107 deletions

View File

@ -0,0 +1,65 @@
factories
=========
This is a module for defining stand-alone factories and fixtures. Ideally a fixture will implement a single item.
DO NOT decorate fixtures in this module with the @pytest.fixture. These fixtures are to be combined
with fixture factories and composition using the `conftest.py` convention. Those composed fixtures
will be decorated for usage and discovery.
Use the fixtures directly in factory methods to build up the desired set of components and relationships.
Each fixture should create exactly one object and should support the option for that object to be persisted
or not.
A factory should create at a minimum a single object for that factory type. The creation of any
associated objects should be explicit. For example, the `create_organization` factory when given only
a `name` parameter will create an Organization but it will not implicitly create any other objects.
teams
-----
There is some special handling for users when adding teams. There is a short hand that allows you to
assign a user to the member\_role of a team using the string notation of `team_name:user_name`. There is
no shortcut for adding a user to the admin\_role of a team. See the roles section for more information
about how to do that.
roles
-----
The roles helper allows you pass in roles to a factory. These roles assignments will happen after
the objects are created. Using the roles parameter required that persisted=True (default).
You can use a string notation of `object_name.role_name:user` OR `object_name.role_name:object_name.child_role`
obj.parent_role:user # This will make the user a member of parent_role
obj1.role:obj2.role # This will make obj2 a child role of obj1
team1.admin_role:joe
team1.admin_role:project1.admin_role
examples
--------
objects = create_organization('test-org')
assert objects.organization.name == 'test-org'
objects = create_organization('test-org', projects=['test-proj'])
assert objects.projects.test-proj.organization == objects.organization
objects = create_organization('test-org', persisted=False)
assert not objects.organization.pk
patterns
--------
`mk` functions are single object fixtures. They should create only a single object with the minimum deps.
They should also accept a `persited` flag, if they must be persisted to work, they raise an error if persisted=False
`generate` and `apply` functions are helpers that build up the various parts of a `create` functions objects. These
should be useful for more than one create function to use and should explicitly accept all of the values needed
to execute. These functions should also be robust and have very speciifc error reporting about constraints and/or
bad values.
`create` functions compose many of the `mk` and `generate` functions to make different object
factories. These functions when giving the minimum set of arguments should only produce a
single artifact (or the minimum needed for that object). These should be wrapped by discoverable
fixtures in various conftest.py files.

View File

@ -0,0 +1,16 @@
from .tower import (
create_organization,
create_job_template,
create_notification_template,
)
from .exc import (
NotUnique,
)
__all__ = [
'create_organization',
'create_job_template',
'create_notification_template',
'NotUnique',
]

View File

@ -0,0 +1,5 @@
class NotUnique(Exception):
def __init__(self, name, objects):
msg = '{} is not a unique key, found {}={}'.format(name, name, objects[name])
super(Exception, self).__init__(msg)

View File

@ -0,0 +1,124 @@
from django.contrib.auth.models import User
from awx.main.models import (
Organization,
Project,
Team,
Instance,
JobTemplate,
NotificationTemplate,
Credential,
Inventory,
Label,
)
# mk methods should create only a single object of a single type.
# they should also have the option of being persisted or not.
# if the object must be persisted an error should be raised when
# persisted=False
#
def mk_instance(persisted=True):
if not persisted:
raise RuntimeError('creating an Instance requires persisted=True')
from django.conf import settings
return Instance.objects.get_or_create(uuid=settings.SYSTEM_UUID, primary=True, hostname="instance.example.org")
def mk_organization(name, description=None, persisted=True):
description = description or '{}-description'.format(name)
org = Organization(name=name, description=description)
if persisted:
mk_instance(persisted)
org.save()
return org
def mk_label(name, organization=None, description=None, persisted=True):
description = description or '{}-description'.format(name)
label = Label(name=name, description=description)
if organization is not None:
label.organization = organization
if persisted:
label.save()
return label
def mk_team(name, organization=None, persisted=True):
team = Team(name=name)
if organization is not None:
team.organization = organization
if persisted:
mk_instance(persisted)
team.save()
return team
def mk_user(name, is_superuser=False, organization=None, team=None, persisted=True):
user = User(username=name, is_superuser=is_superuser)
if persisted:
user.save()
if organization is not None:
organization.member_role.members.add(user)
if team is not None:
team.member_role.members.add(user)
return user
def mk_project(name, organization=None, description=None, persisted=True):
description = description or '{}-description'.format(name)
project = Project(name=name, description=description)
if organization is not None:
project.organization = organization
if persisted:
project.save()
return project
def mk_credential(name, cloud=False, kind='ssh', persisted=True):
cred = Credential(name=name, cloud=cloud, kind=kind)
if persisted:
cred.save()
return cred
def mk_notification_template(name, notification_type='webhook', configuration=None, organization=None, persisted=True):
nt = NotificationTemplate(name=name)
nt.notification_type = notification_type
nt.notification_configuration = configuration or dict(url="http://localhost", headers={"Test": "Header"})
if organization is not None:
nt.organization = organization
if persisted:
nt.save()
return nt
def mk_inventory(name, organization=None, persisted=True):
inv = Inventory(name=name)
if organization is not None:
inv.organization = organization
if persisted:
inv.save()
return inv
def mk_job_template(name, job_type='run',
organization=None, inventory=None,
credential=None, persisted=True,
project=None):
jt = JobTemplate(name=name, job_type=job_type)
jt.inventory = inventory
if jt.inventory is None:
jt.ask_inventory_on_launch = True
jt.credential = credential
if jt.credential is None:
jt.ask_credential_on_launch = True
jt.project = project
if persisted:
jt.save()
return jt

View File

@ -0,0 +1,280 @@
from collections import namedtuple
from django.contrib.auth.models import User
from awx.main.models import (
Organization,
Project,
Team,
NotificationTemplate,
Credential,
Inventory,
Label,
)
from .fixtures import (
mk_organization,
mk_team,
mk_user,
mk_job_template,
mk_credential,
mk_inventory,
mk_project,
mk_label,
mk_notification_template,
)
from .exc import NotUnique
def generate_role_objects(objects):
'''generate_role_objects assembles a dictionary of all possible objects by name.
It will raise an exception if any of the objects share a name due to the fact that
it is to be used with apply_roles, which expects unique object names.
roles share a common name e.g. admin_role, member_role. This ensures that the
roles short hand used for mapping Roles and Users in apply_roles will function as desired.
'''
combined_objects = {}
for o in objects:
if type(o) is dict:
for k,v in o.iteritems():
if combined_objects.get(k) is not None:
raise NotUnique(k, combined_objects)
combined_objects[k] = v
elif hasattr(o, 'name'):
if combined_objects.get(o.name) is not None:
raise NotUnique(o.name, combined_objects)
combined_objects[o.name] = o
else:
if o is not None:
raise RuntimeError('expected a list of dict or list of list, got a type {}'.format(type(o)))
return combined_objects
def apply_roles(roles, objects, persisted):
'''apply_roles evaluates a list of Role relationships represented as strings.
The format of this string is 'role:[user|role]'. When a user is provided, they will be
made a member of the role on the LHS. When a role is provided that role will be added to
the children of the role on the LHS.
This function assumes that objects is a dictionary that contains a unique set of key to value
mappings for all possible "Role objects". See the example below:
Mapping Users
-------------
roles = ['org1.admin_role:user1', 'team1.admin_role:user1']
objects = {'org1': Organization, 'team1': Team, 'user1': User]
Mapping Roles
-------------
roles = ['org1.admin_role:team1.admin_role']
objects = {'org1': Organization, 'team1': Team}
Invalid Mapping
---------------
roles = ['org1.admin_role:team1.admin_role']
objects = {'org1': Organization', 'user1': User} # Exception, no team1 entry
'''
if roles is None:
return None
if not persisted:
raise RuntimeError('roles can not be used when persisted=False')
for role in roles:
obj_role, sep, member_role = role.partition(':')
if not member_role:
raise RuntimeError('you must provide an assignment role, got None')
obj_str, o_role_str = obj_role.split('.')
member_str, m_sep, m_role_str = member_role.partition('.')
obj = objects[obj_str]
obj_role = getattr(obj, o_role_str)
member = objects[member_str]
if m_role_str:
if hasattr(member, m_role_str):
member_role = getattr(member, m_role_str)
obj_role.children.add(member_role)
else:
raise RuntimeError('unable to find {} role for {}'.format(m_role_str, member_str))
else:
if type(member) is User:
obj_role.members.add(member)
else:
raise RuntimeError('unable to add non-user {} for members list of {}'.format(member_str, obj_str))
def generate_users(organization, teams, superuser, persisted, **kwargs):
'''generate_users evaluates a mixed list of User objects and strings.
If a string is encountered a user with that username is created and added to the lookup dict.
If a User object is encountered the User.username is used as a key for the lookup dict.
A short hand for assigning a user to a team is available in the following format: "team_name:username".
If a string in that format is encounted an attempt to lookup the team by the key team_name from the teams
argumnent is made, a KeyError will be thrown if the team does not exist in the dict. The teams argument should
be a dict of {Team.name:Team}
'''
users = {}
key = 'superusers' if superuser else 'users'
if key in kwargs and kwargs.get(key) is not None:
for u in kwargs[key]:
if type(u) is User:
users[u.username] = u
else:
p1, sep, p2 = u.partition(':')
if p2:
t = teams[p1]
users[p2] = mk_user(p2, organization=organization, team=t, is_superuser=superuser, persisted=persisted)
else:
users[p1] = mk_user(p1, organization=organization, team=None, is_superuser=superuser, persisted=persisted)
return users
def generate_teams(organization, persisted, **kwargs):
'''generate_teams evalutes a mixed list of Team objects and strings.
If a string is encountered a team with that string name is created and added to the lookup dict.
If a Team object is encounted the Team.name is used as a key for the lookup dict.
'''
teams = {}
if 'teams' in kwargs and kwargs.get('teams') is not None:
for t in kwargs['teams']:
if type(t) is Team:
teams[t.name] = t
else:
teams[t] = mk_team(t, organization=organization, persisted=persisted)
return teams
class _Mapped(object):
'''_Mapped is a helper class that replaces spaces and dashes
in the name of an object and assigns the object as an attribute
input: {'my org': Organization}
output: instance.my_org = Organization
'''
def __init__(self, d):
self.d = d
for k,v in d.items():
k = k.replace(' ', '_')
k = k.replace('-', '_')
setattr(self, k.replace(' ','_'), v)
def all(self):
return self.d.values()
# create methods are intended to be called directly as needed
# or encapsulated by specific factory fixtures in a conftest
#
def create_job_template(name, **kwargs):
Objects = namedtuple("Objects", "job_template, inventory, project, credential, job_type")
org = None
proj = None
inv = None
cred = None
job_type = kwargs.get('job_type', 'run')
persisted = kwargs.get('persisted', True)
if 'organization' in kwargs:
org = kwargs['organization']
if type(org) is not Organization:
org = mk_organization(org, '%s-desc'.format(org), persisted=persisted)
if 'credential' in kwargs:
cred = kwargs['credential']
if type(cred) is not Credential:
cred = mk_credential(cred, persisted=persisted)
if 'project' in kwargs:
proj = kwargs['project']
if type(proj) is not Project:
proj = mk_project(proj, organization=org, persisted=persisted)
if 'inventory' in kwargs:
inv = kwargs['inventory']
if type(inv) is not Inventory:
inv = mk_inventory(inv, organization=org, persisted=persisted)
jt = mk_job_template(name, project=proj,
inventory=inv, credential=cred,
job_type=job_type, persisted=persisted)
role_objects = generate_role_objects([org, proj, inv, cred])
apply_roles(kwargs.get('roles'), role_objects, persisted)
return Objects(job_template=jt,
project=proj,
inventory=inv,
credential=cred,
job_type=job_type)
def create_organization(name, **kwargs):
Objects = namedtuple("Objects", "organization,teams,users,superusers,projects,labels,notification_templates")
projects = {}
labels = {}
notification_templates = {}
persisted = kwargs.get('persisted', True)
org = mk_organization(name, '%s-desc'.format(name), persisted=persisted)
if 'projects' in kwargs:
for p in kwargs['projects']:
if type(p) is Project:
projects[p.name] = p
else:
projects[p] = mk_project(p, organization=org, persisted=persisted)
teams = generate_teams(org, persisted, teams=kwargs.get('teams'))
superusers = generate_users(org, teams, True, persisted, superusers=kwargs.get('superusers'))
users = generate_users(org, teams, False, persisted, users=kwargs.get('users'))
if 'labels' in kwargs:
for l in kwargs['labels']:
if type(l) is Label:
labels[l.name] = l
else:
labels[l] = mk_label(l, organization=org, persisted=persisted)
if 'notification_templates' in kwargs:
for nt in kwargs['notification_templates']:
if type(nt) is NotificationTemplate:
notification_templates[nt.name] = nt
else:
notification_templates[nt] = mk_notification_template(nt, organization=org, persisted=persisted)
role_objects = generate_role_objects([org, superusers, users, teams, projects, labels, notification_templates])
apply_roles(kwargs.get('roles'), role_objects, persisted)
return Objects(organization=org,
superusers=_Mapped(superusers),
users=_Mapped(users),
teams=_Mapped(teams),
projects=_Mapped(projects),
labels=_Mapped(labels),
notification_templates=_Mapped(notification_templates))
def create_notification_template(name, **kwargs):
Objects = namedtuple("Objects", "notification_template,organization,users,superusers,teams")
organization = None
persisted = kwargs.get('persisted', True)
if 'organization' in kwargs:
org = kwargs['organization']
organization = mk_organization(org, '{}-desc'.format(org), persisted=persisted)
notification_template = mk_notification_template(name, organization=organization, persisted=persisted)
teams = generate_teams(organization, persisted, teams=kwargs.get('teams'))
superusers = generate_users(organization, teams, True, persisted, superusers=kwargs.get('superusers'))
users = generate_users(organization, teams, False, persisted, users=kwargs.get('users'))
role_objects = generate_role_objects([organization, notification_template])
apply_roles(kwargs.get('roles'), role_objects, persisted)
return Objects(notification_template=notification_template,
organization=organization,
users=_Mapped(users),
superusers=_Mapped(superusers),
teams=teams)

View File

@ -38,6 +38,12 @@ from awx.main.models.organization import (
from awx.main.models.notifications import NotificationTemplate
from awx.main.tests.factories import (
create_organization,
create_job_template,
create_notification_template,
)
'''
Disable all django model signals.
'''
@ -147,18 +153,6 @@ def instance(settings):
def organization(instance):
return Organization.objects.create(name="test-org", description="test-org-desc")
@pytest.fixture
def organization_factory(instance):
def factory(name):
try:
org = Organization.objects.get(name=name)
except Organization.DoesNotExist:
org = Organization.objects.create(name=name,
description="description for " + name,
)
return org
return factory
@pytest.fixture
def credential():
return Credential.objects.create(kind='aws', name='test-cred')
@ -282,21 +276,6 @@ def permissions():
'update':False, 'delete':False, 'scm_update':False, 'execute':False, 'use':True,},
}
@pytest.fixture
def notification_template_factory(organization):
def n(name="test-notification_template"):
try:
notification_template = NotificationTemplate.objects.get(name=name)
except NotificationTemplate.DoesNotExist:
notification_template = NotificationTemplate(name=name,
organization=organization,
notification_type="webhook",
notification_configuration=dict(url="http://localhost",
headers={"Test": "Header"}))
notification_template.save()
return notification_template
return n
@pytest.fixture
def post():
def rf(url, data, user=None, middleware=None, **kwargs):
@ -474,3 +453,16 @@ def job_template_labels(organization, job_template):
job_template.labels.create(name="label-2", organization=organization)
return job_template
@pytest.fixture
def job_template_factory():
return create_job_template
@pytest.fixture
def organization_factory():
return create_organization
@pytest.fixture
def notification_template_factory():
return create_notification_template

View File

@ -0,0 +1,85 @@
import pytest
from awx.main.tests.factories import NotUnique
def test_roles_exc_not_persisted(organization_factory):
with pytest.raises(RuntimeError) as exc:
organization_factory('test-org', roles=['test-org.admin_role:user1'], persisted=False)
assert 'persisted=False' in str(exc.value)
@pytest.mark.django_db
def test_roles_exc_bad_object(organization_factory):
with pytest.raises(KeyError):
organization_factory('test-org', roles=['test-project.admin_role:user'])
@pytest.mark.django_db
def test_roles_exc_not_unique(organization_factory):
with pytest.raises(NotUnique) as exc:
organization_factory('test-org', projects=['foo'], teams=['foo'], roles=['foo.admin_role:user'])
assert 'not a unique key' in str(exc.value)
@pytest.mark.django_db
def test_roles_exc_not_assignment(organization_factory):
with pytest.raises(RuntimeError) as exc:
organization_factory('test-org', projects=['foo'], roles=['foo.admin_role'])
assert 'provide an assignment' in str(exc.value)
@pytest.mark.django_db
def test_roles_exc_not_found(organization_factory):
with pytest.raises(RuntimeError) as exc:
organization_factory('test-org', users=['user'], projects=['foo'], roles=['foo.admin_role:user.bad_role'])
assert 'unable to find' in str(exc.value)
@pytest.mark.django_db
def test_roles_exc_not_user(organization_factory):
with pytest.raises(RuntimeError) as exc:
organization_factory('test-org', projects=['foo'], roles=['foo.admin_role:foo'])
assert 'unable to add non-user' in str(exc.value)
@pytest.mark.django_db
def test_org_factory_roles(organization_factory):
objects = organization_factory('org_roles_test',
teams=['team1', 'team2'],
users=['team1:foo', 'bar'],
projects=['baz', 'bang'],
roles=['team2.member_role:foo',
'team1.admin_role:bar',
'team1.admin_role:team2.admin_role',
'baz.admin_role:foo'])
assert objects.users.bar in objects.teams.team2.admin_role
assert objects.users.foo in objects.projects.baz.admin_role
assert objects.users.foo in objects.teams.team1.member_role
assert objects.teams.team2.admin_role in objects.teams.team1.admin_role.children.all()
@pytest.mark.django_db
def test_org_factory(organization_factory):
objects = organization_factory('organization1',
teams=['team1'],
superusers=['superuser'],
users=['admin', 'alice', 'team1:bob'],
projects=['proj1'])
assert hasattr(objects.users, 'admin')
assert hasattr(objects.users, 'alice')
assert hasattr(objects.superusers, 'superuser')
assert objects.users.bob in objects.teams.team1.member_role.members.all()
assert objects.projects.proj1.organization == objects.organization
@pytest.mark.django_db
def test_job_template_factory(job_template_factory):
jt_objects = job_template_factory('testJT', organization='org1',
project='proj1', inventory='inventory1',
credential='cred1')
assert jt_objects.job_template.name == 'testJT'
assert jt_objects.project.name == 'proj1'
assert jt_objects.inventory.name == 'inventory1'
assert jt_objects.credential.name == 'cred1'
assert jt_objects.inventory.organization.name == 'org1'

View File

@ -1,7 +1,6 @@
import mock # noqa
import pytest
from django.db import transaction
from django.core.urlresolvers import reverse
from awx.main.models import Project
@ -9,62 +8,55 @@ from awx.main.models import Project
#
# Project listing and visibility tests
#
@pytest.fixture
def team_project_list(organization_factory):
objects = organization_factory('org-test',
superusers=['admin'],
users=['team1:alice', 'team2:bob'],
teams=['team1', 'team2'],
projects=['pteam1', 'pteam2', 'pshared'],
roles=['team1.member_role:pteam1.admin_role',
'team2.member_role:pteam2.admin_role',
'team1.member_role:pshared.admin_role',
'team2.member_role:pshared.admin_role'])
return objects
@pytest.mark.django_db
def test_user_project_list(get, project_factory, organization, admin, alice, bob):
def test_user_project_list(get, organization_factory):
'List of projects a user has access to, filtered by projects you can also see'
organization.member_role.members.add(alice, bob)
objects = organization_factory('org1',
projects=['alice project', 'bob project', 'shared project'],
superusers=['admin'],
users=['alice', 'bob'],
roles=['alice project.admin_role:alice',
'bob project.admin_role:bob',
'shared project.admin_role:bob',
'shared project.admin_role:alice'])
alice_project = project_factory('alice project')
alice_project.admin_role.members.add(alice)
bob_project = project_factory('bob project')
bob_project.admin_role.members.add(bob)
shared_project = project_factory('shared project')
shared_project.admin_role.members.add(alice)
shared_project.admin_role.members.add(bob)
# admins can see all projects
assert get(reverse('api:user_projects_list', args=(admin.pk,)), admin).data['count'] == 3
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.superusers.admin).data['count'] == 3
# admins can see everyones projects
assert get(reverse('api:user_projects_list', args=(alice.pk,)), admin).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(bob.pk,)), admin).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.superusers.admin).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.superusers.admin).data['count'] == 2
# users can see their own projects
assert get(reverse('api:user_projects_list', args=(alice.pk,)), alice).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.users.alice).data['count'] == 2
# alice should only be able to see the shared project when looking at bobs projects
assert get(reverse('api:user_projects_list', args=(bob.pk,)), alice).data['count'] == 1
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.users.alice).data['count'] == 1
# alice should see all projects they can see when viewing an admin
assert get(reverse('api:user_projects_list', args=(admin.pk,)), alice).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.users.alice).data['count'] == 2
def setup_test_team_project_list(project_factory, team_factory, admin, alice, bob):
team1 = team_factory('team1')
team2 = team_factory('team2')
team1_project = project_factory('team1 project')
team1_project.admin_role.parents.add(team1.member_role)
team2_project = project_factory('team2 project')
team2_project.admin_role.parents.add(team2.member_role)
shared_project = project_factory('shared project')
shared_project.admin_role.parents.add(team1.member_role)
shared_project.admin_role.parents.add(team2.member_role)
team1.member_role.members.add(alice)
team2.member_role.members.add(bob)
return team1, team2
@pytest.mark.django_db
def test_team_project_list(get, project_factory, team_factory, admin, alice, bob):
'List of projects a team has access to, filtered by projects you can also see'
team1, team2 = setup_test_team_project_list(project_factory, team_factory, admin, alice, bob)
def test_team_project_list(get, team_project_list):
objects = team_project_list
team1, team2 = objects.teams.team1, objects.teams.team2
alice, bob, admin = objects.users.alice, objects.users.bob, objects.superusers.admin
# admins can see all projects on a team
assert get(reverse('api:team_projects_list', args=(team1.pk,)), admin).data['count'] == 2
@ -78,12 +70,6 @@ def test_team_project_list(get, project_factory, team_factory, admin, alice, bob
assert get(reverse('api:team_projects_list', args=(team2.pk,)), alice).data['count'] == 1
team2.read_role.members.remove(alice)
# Test user endpoints first, very similar tests to test_user_project_list
# but permissions are being derived from team membership instead.
with transaction.atomic():
res = get(reverse('api:user_projects_list', args=(bob.pk,)), alice)
assert res.status_code == 403
# admins can see all projects
assert get(reverse('api:user_projects_list', args=(admin.pk,)), admin).data['count'] == 3
@ -98,17 +84,11 @@ def test_team_project_list(get, project_factory, team_factory, admin, alice, bob
assert get(reverse('api:user_projects_list', args=(admin.pk,)), alice).data['count'] == 2
@pytest.mark.django_db
def test_team_project_list_fail1(get, project_factory, team_factory, admin, alice, bob):
# alice should not be able to see team2 projects because she doesn't have access to team2
team1, team2 = setup_test_team_project_list(project_factory, team_factory, admin, alice, bob)
res = get(reverse('api:team_projects_list', args=(team2.pk,)), alice)
def test_team_project_list_fail1(get, team_project_list):
objects = team_project_list
res = get(reverse('api:team_projects_list', args=(objects.teams.team2.pk,)), objects.users.alice)
assert res.status_code == 403
@pytest.mark.django_db
def test_team_project_list_fail2(get, project_factory, team_factory, admin, alice, bob):
team1, team2 = setup_test_team_project_list(project_factory, team_factory, admin, alice, bob)
# alice should not be able to see bob
@pytest.mark.parametrize("u,expected_status_code", [
('rando', 403),
('org_member', 403),

View File

@ -31,20 +31,22 @@ def test_label_access_superuser(label, user):
assert access.can_delete(label)
@pytest.mark.django_db
def test_label_access_admin(label, user, organization_factory):
def test_label_access_admin(organization_factory):
'''can_change because I am an admin of that org'''
a = user('admin', False)
org_no_members = organization_factory("no_members")
org_members = organization_factory("has_members")
no_members = organization_factory("no_members")
members = organization_factory("has_members",
users=['admin'],
labels=['test'])
label.organization.admin_role.members.add(a)
org_members.admin_role.members.add(a)
label = members.labels.test
admin = members.users.admin
members.organization.admin_role.members.add(admin)
access = LabelAccess(user('admin', False))
assert not access.can_change(label, {'organization': org_no_members.id})
access = LabelAccess(admin)
assert not access.can_change(label, {'organization': no_members.organization.id})
assert access.can_read(label)
assert access.can_change(label, None)
assert access.can_change(label, {'organization': org_members.id})
assert access.can_change(label, {'organization': members.organization.id})
assert access.can_delete(label)
@pytest.mark.django_db

View File

@ -25,35 +25,44 @@ def test_notification_template_get_queryset_orgadmin(notification_template, user
assert access.get_queryset().count() == 1
@pytest.mark.django_db
def test_notification_template_access_superuser(notification_template, user, notification_template_factory):
access = NotificationTemplateAccess(user('admin', True))
assert access.can_read(notification_template)
assert access.can_change(notification_template, None)
assert access.can_delete(notification_template)
nf = notification_template_factory("test-orphaned")
def test_notification_template_access_superuser(notification_template_factory):
nf_objects = notification_template_factory('test-orphaned', organization='test', superusers=['admin'])
admin = nf_objects.superusers.admin
nf = nf_objects.notification_template
access = NotificationTemplateAccess(admin)
assert access.can_read(nf)
assert access.can_change(nf, None)
assert access.can_delete(nf)
nf.organization = None
nf.save()
assert access.can_read(nf)
assert access.can_change(nf, None)
assert access.can_delete(nf)
@pytest.mark.django_db
def test_notification_template_access_admin(notification_template, user, organization_factory, notification_template_factory):
adm = user('admin', False)
other_org = organization_factory('other')
present_org = organization_factory('present')
notification_template.organization.admin_role.members.add(adm)
present_org.admin_role.members.add(adm)
def test_notification_template_access_admin(organization_factory, notification_template_factory):
other_objects = organization_factory('other')
present_objects = organization_factory('present',
users=['admin'],
notification_templates=['test-notification'],
roles=['present.admin_role:admin'])
access = NotificationTemplateAccess(user('admin', False))
notification_template = present_objects.notification_templates.test_notification
other_org = other_objects.organization
present_org = present_objects.organization
admin = present_objects.users.admin
access = NotificationTemplateAccess(admin)
assert not access.can_change(notification_template, {'organization': other_org.id})
assert access.can_read(notification_template)
assert access.can_change(notification_template, None)
assert access.can_change(notification_template, {'organization': present_org.id})
assert access.can_delete(notification_template)
nf = notification_template_factory("test-orphaned")
nf.organization = None
nf.save()
assert not access.can_read(nf)
assert not access.can_change(nf, None)
assert not access.can_delete(nf)