Merge pull request #892 from nofusscomputing/2025-07-25

This commit is contained in:
Jon
2025-07-25 08:38:15 +09:30
committed by GitHub
18 changed files with 1101 additions and 577 deletions

View File

@ -0,0 +1,204 @@
import pytest
import random
from django.test import Client
class AdditionalTestCases:
def test_permission_add(self, model_instance, api_request_permissions,
model_kwargs, kwargs_api_create
):
""" Check correct permission for add
Attempt to add as user with permission
"""
client = Client()
client.force_login( api_request_permissions['user']['add'] )
the_model = model_instance( kwargs_create = self.kwargs_create_item )
url = the_model.get_url( many = True )
the_model.delete()
kwargs = kwargs_api_create.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
response = client.post(
path = url,
data = kwargs,
content_type = 'application/json'
)
assert response.status_code == 201, response.content
def test_returned_results_only_user_orgs(self, model_instance, model_kwargs, api_request_permissions):
"""Returned results check
Ensure that a query to the viewset endpoint does not return
items that are not part of the users organizations.
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
]
if getattr(self, 'global_organization', None):
# Cater for above test that also has global org
viewable_organizations += [ api_request_permissions['tenancy']['global'] ]
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
# if response.status_code == 405:
# pytest.xfail( reason = 'ViewSet does not have this request method.' )
# elif IsAuthenticatedOrReadOnly in response.renderer_context['view'].permission_classes:
# pytest.xfail( reason = 'ViewSet is public viewable, test is N/A' )
assert response.status_code == 200
contains_different_org: bool = False
for item in response.data['results']:
if 'organization' not in item:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if(
int(item['organization']['id']) not in viewable_organizations
and
int(item['organization']['id']) != api_request_permissions['tenancy']['global'].id
):
contains_different_org = True
print(f'Failed returned row was: {item}')
assert not contains_different_org
def test_returned_data_from_user_and_global_organizations_only(
self, model_instance, model_kwargs, api_request_permissions
):
"""Check items returned
Items returned from the query Must be from the users organization and
global ONLY!
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
only_from_user_org: bool = True
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
api_request_permissions['tenancy']['global'].id
]
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
assert len(response.data['results']) >= 2 # fail if only one item extist.
for row in response.data['results']:
if 'organization' not in row:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if row['organization']['id'] not in viewable_organizations:
only_from_user_org = False
print(f"Users org: {api_request_permissions['tenancy']['user'].id}")
print(f"global org: {api_request_permissions['tenancy']['global'].id}")
print(f'Failed returned row was: {row}')
assert only_from_user_org

View File

@ -0,0 +1,204 @@
import pytest
import random
from django.test import Client
class AdditionalTestCases:
def test_permission_add(self, model_instance, api_request_permissions,
model_kwargs, kwargs_api_create
):
""" Check correct permission for add
Attempt to add as user with permission
"""
client = Client()
client.force_login( api_request_permissions['user']['add'] )
the_model = model_instance( kwargs_create = self.kwargs_create_item )
url = the_model.get_url( many = True )
the_model.delete()
kwargs = kwargs_api_create.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
response = client.post(
path = url,
data = kwargs,
content_type = 'application/json'
)
assert response.status_code == 201, response.content
def test_returned_results_only_user_orgs(self, model_instance, model_kwargs, api_request_permissions):
"""Returned results check
Ensure that a query to the viewset endpoint does not return
items that are not part of the users organizations.
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
]
if getattr(self, 'global_organization', None):
# Cater for above test that also has global org
viewable_organizations += [ api_request_permissions['tenancy']['global'] ]
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
# if response.status_code == 405:
# pytest.xfail( reason = 'ViewSet does not have this request method.' )
# elif IsAuthenticatedOrReadOnly in response.renderer_context['view'].permission_classes:
# pytest.xfail( reason = 'ViewSet is public viewable, test is N/A' )
assert response.status_code == 200
contains_different_org: bool = False
for item in response.data['results']:
if 'organization' not in item:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if(
int(item['organization']['id']) not in viewable_organizations
and
int(item['organization']['id']) != api_request_permissions['tenancy']['global'].id
):
contains_different_org = True
print(f'Failed returned row was: {item}')
assert not contains_different_org
def test_returned_data_from_user_and_global_organizations_only(
self, model_instance, model_kwargs, api_request_permissions
):
"""Check items returned
Items returned from the query Must be from the users organization and
global ONLY!
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
only_from_user_org: bool = True
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
api_request_permissions['tenancy']['global'].id
]
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
assert len(response.data['results']) >= 2 # fail if only one item extist.
for row in response.data['results']:
if 'organization' not in row:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if row['organization']['id'] not in viewable_organizations:
only_from_user_org = False
print(f"Users org: {api_request_permissions['tenancy']['user'].id}")
print(f"global org: {api_request_permissions['tenancy']['global'].id}")
print(f'Failed returned row was: {row}')
assert only_from_user_org

View File

@ -1,20 +1,14 @@
import django
import pytest
import unittest
import requests
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser, Permission
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import reverse
from django.test import Client, TestCase
from django.test import TestCase
from access.models.tenant import Tenant as Organization
from access.models.team import Team
from access.models.team_user import TeamUsers
from api.tests.abstract.api_permissions_viewset import APIPermissions
from api.tests.abstract.api_serializer_viewset import SerializersTestCases
from api.tests.abstract.test_metadata_functional import MetadataAttributesFunctional, MetaDataNavigationEntriesFunctional
@ -197,108 +191,6 @@ class ViewSetBase:
class OrganizationPermissionsAPI(
ViewSetBase,
APIPermissions,
TestCase
):
def test_returned_data_from_user_and_global_organizations_only(self):
"""Check items returned
This test case is a over-ride of a test case with the same name.
This model is not a tenancy model making this test not-applicable.
Items returned from the query Must be from the users organization and
global ONLY!
"""
pass
def test_add_has_permission(self):
""" Check correct permission for add
Attempt to add as user with permission
"""
client = Client()
if self.url_kwargs:
url = reverse( self.app_namespace + ':' + self.url_name + '-list', kwargs = self.url_kwargs )
else:
url = reverse( self.app_namespace + ':' + self.url_name + '-list' )
client.force_login( self.add_user )
response = client.post( url, data = self.add_data )
assert response.status_code == 201
def test_returned_results_only_user_orgs(self):
"""Returned results check
This test case is an override of a test of the same name.
organizations are not tenancy objects and therefor are supposed to
return all items when a user queries them.
Ensure that a query to the viewset endpoint does not return
items that are not part of the users organizations.
"""
# Ensure the other org item exists, without test not able to function
print('Check that the different organization item has been defined')
assert hasattr(self, 'other_org_item')
# ensure that the variables for the two orgs are different orgs
print('checking that the different and user oganizations are different')
assert self.different_organization.id != self.organization.id
client = Client()
if self.url_kwargs:
url = reverse(self.app_namespace + ':' + self.url_name + '-list', kwargs = self.url_kwargs)
else:
url = reverse(self.app_namespace + ':' + self.url_name + '-list')
client.force_login(self.view_user)
response = client.get(url)
contains_different_org: bool = False
# for item in response.data['results']:
# if int(item['id']) != self.organization.id:
# contains_different_org = True
assert len(response.data['results']) == 2
def test_add_different_organization_denied(self):
""" Check correct permission for add
This test is a duplicate of a test case with the same name.
Organizations are not tenancy models so this test does nothing of value
attempt to add as user from different organization
"""
pass
class OrganizationViewSet(
ViewSetBase,
SerializersTestCases,

View File

@ -79,9 +79,11 @@ class MetadataTestCases(
self.view_user = User.objects.create_user(username="test_user_view", password="password")
kwargs = self.kwargs_create_item
kwargs['organization'] = organization
self.item = self.model.objects.create(
organization = organization,
**self.kwargs_create_item
**kwargs
)
self.other_org_item = self.model.objects.create(

View File

@ -77,9 +77,10 @@ class ViewSetBase:
self.view_user = User.objects.create_user(username="test_user_view", password="password")
kwargs = self.kwargs_create_item
kwargs['organization'] = organization
self.item = self.model.objects.create(
organization = organization,
**self.kwargs_create_item
**kwargs
)
self.other_org_item = self.model.objects.create(

View File

@ -22,3 +22,11 @@ def create_serializer():
yield ModelSerializer
@pytest.fixture( scope = 'class', autouse = True)
def model_kwargs(request, kwargs_ticketbase):
request.cls.kwargs_create_item = kwargs_ticketbase.copy()
yield kwargs_ticketbase.copy()

View File

@ -0,0 +1,361 @@
import django
import pytest
import random
from django.db import models
from rest_framework.relations import Hyperlink
from api.tests.functional.test_functional_api_fields import (
APIFieldsInheritedCases,
)
@pytest.mark.model_ticketbase
class APITestCases(
APIFieldsInheritedCases,
):
@pytest.fixture( scope = 'class')
def create_model(self, request, django_db_blocker,
model, model_kwargs, model_entity
):
item = None
with django_db_blocker.unblock():
entity_user = model_entity.objects.create(
organization = model_kwargs['organization'],
model_notes = 'asdas'
)
parent_ticket = model.objects.create(
organization = model_kwargs['organization'],
title = 'parent ticket' + str(random.randint(9999,999999)),
description = 'bla bla',
opened_by = model_kwargs['opened_by'],
)
kwargs = model_kwargs.copy()
kwargs['parent_ticket'] = parent_ticket
kwargs['is_solved'] = True
kwargs['date_solved'] = '2025-05-12T02:30:01Z'
kwargs['is_closed'] = True
kwargs['date_closed'] = '2025-05-12T02:30:02Z'
kwargs['status'] = model.TicketStatus.CLOSED
item = model.objects.create(
**kwargs
)
item.assigned_to.add(entity_user)
item.subscribed_to.add(entity_user)
request.cls.item = item
yield item
with django_db_blocker.unblock():
item.delete()
parent_ticket.delete()
entity_user.delete()
@property
def parameterized_api_fields(self):
return {
'model_notes': {
'expected': models.NOT_PROVIDED
},
'_urls.notes': {
'expected': models.NOT_PROVIDED
},
'external_system': {
'expected': int
},
'external_ref': {
'expected': int
},
'parent_ticket': {
'expected': dict
},
'parent_ticket.id': {
'expected': int
},
'parent_ticket.display_name': {
'expected': str
},
'parent_ticket.url': {
'expected': str
},
'ticket_type': {
'expected': str
},
'status': {
'expected': int
},
'status_badge': {
'expected': dict
},
'status_badge.icon': {
'expected': dict
},
'status_badge.icon.name': {
'expected': str
},
'status_badge.icon.style': {
'expected': str
},
'status_badge.text': {
'expected': str
},
'status_badge.text_style': {
'expected': str
},
'status_badge.url': {
'expected': type(None)
},
'category': {
'expected': dict
},
'category.id': {
'expected': int
},
'category.display_name': {
'expected': str
},
'category.url': {
'expected': Hyperlink
},
'title': {
'expected': str
},
'description': {
'expected': str
},
'ticket_duration': {
'expected': int
},
'ticket_estimation': {
'expected': int
},
'project': {
'expected': dict
},
'project.id': {
'expected': int
},
'project.display_name': {
'expected': str
},
'project.url': {
'expected': Hyperlink
},
'milestone': {
'expected': dict
},
'milestone.id': {
'expected': int
},
'milestone.display_name': {
'expected': str
},
'milestone.url': {
'expected': str
},
'urgency': {
'expected': int
},
'urgency_badge': {
'expected': dict
},
'urgency_badge.icon': {
'expected': dict
},
'urgency_badge.icon.name': {
'expected': str
},
'urgency_badge.icon.style': {
'expected': str
},
'urgency_badge.text': {
'expected': str
},
'urgency_badge.text_style': {
'expected': str
},
'urgency_badge.url': {
'expected': type(None)
},
'impact': {
'expected': int
},
'impact_badge': {
'expected': dict
},
'impact_badge.icon': {
'expected': dict
},
'impact_badge.icon.name': {
'expected': str
},
'impact_badge.icon.style': {
'expected': str
},
'impact_badge.text': {
'expected': str
},
'impact_badge.text_style': {
'expected': str
},
'impact_badge.url': {
'expected': type(None)
},
'priority': {
'expected': int
},
'priority_badge': {
'expected': dict
},
'priority_badge.icon': {
'expected': dict
},
'priority_badge.icon.name': {
'expected': str
},
'priority_badge.icon.style': {
'expected': str
},
'priority_badge.text': {
'expected': str
},
'priority_badge.text_style': {
'expected': str
},
'priority_badge.url': {
'expected': type(None)
},
'opened_by': {
'expected': dict
},
'opened_by.id': {
'expected': int
},
'opened_by.display_name': {
'expected': str
},
'opened_by.first_name': {
'expected': str
},
'opened_by.last_name': {
'expected': str
},
'opened_by.username': {
'expected': str
},
'opened_by.username': {
'expected': str
},
'opened_by.is_active': {
'expected': bool
},
'opened_by.url': {
'expected': Hyperlink
},
'subscribed_to': {
'expected': list
},
'subscribed_to.0.id': {
'expected': int
},
'subscribed_to.0.display_name': {
'expected': str
},
'subscribed_to.0.url': {
'expected': str
},
'assigned_to': {
'expected': list
},
'assigned_to.0.id': {
'expected': int
},
'assigned_to.0.display_name': {
'expected': str
},
'assigned_to.0.url': {
'expected': str
},
'planned_start_date': {
'expected': str
},
'planned_finish_date': {
'expected': str
},
'real_start_date': {
'expected': str
},
'real_finish_date': {
'expected': str
},
'is_deleted': {
'expected': bool
},
'is_solved': {
'expected': bool
},
'date_solved': {
'expected': str
},
'is_closed': {
'expected': bool
},
'date_closed': {
'expected': str
},
}
# def test_api_field_value_ticket_type(self):
# """ Test for value of an API Field
# **note:** you must override this test with the correct value for
# your ticket type
# ticket_type field must be 'ticket'
# """
# assert self.api_data['ticket_type'] == 'ticket'
class TicketBaseAPIInheritedCases(
APITestCases,
):
pass
@pytest.mark.module_core
class TicketBaseAPIPyTest(
APITestCases,
):
pass

View File

@ -80,9 +80,12 @@ class MetadataTestCases(
'opened_by': self.view_user
})
kwargs = self.kwargs_create_item.copy()
kwargs['organization'] = organization
self.item = self.model.objects.create(
organization = organization,
**self.kwargs_create_item
**kwargs
)
self.kwargs_create_item_diff_org.update({

View File

@ -78,9 +78,11 @@ class ViewSetBase:
'opened_by': self.view_user
})
kwargs = self.kwargs_create_item.copy()
kwargs['organization'] = organization
self.item = self.model.objects.create(
organization = organization,
**self.kwargs_create_item
**kwargs
)
self.kwargs_create_item_diff_org.update({

View File

@ -1,433 +0,0 @@
import django
import pytest
from django.db import models
from rest_framework.relations import Hyperlink
from access.models.entity import Entity
from api.tests.functional.test_functional_api_fields import (
APIFieldsInheritedCases,
)
from core.models.ticket.ticket_category import TicketCategory
from project_management.models.project_milestone import Project, ProjectMilestone
@pytest.mark.model_ticketbase
class APITestCases(
APIFieldsInheritedCases,
):
@pytest.fixture( scope = 'class')
def setup_model(self, request, django_db_blocker,
model,
):
with django_db_blocker.unblock():
request.cls.entity_user = Entity.objects.create(
organization = request.cls.organization,
model_notes = 'asdas'
)
project = Project.objects.create(
organization = request.cls.organization,
name = 'project'
)
parent_ticket = request.cls.model.objects.create(
organization = request.cls.organization,
title = 'parent ticket',
description = 'bla bla',
opened_by = request.cls.view_user,
)
project_milestone = ProjectMilestone.objects.create(
organization = request.cls.organization,
name = 'project milestone one',
project = project
)
request.cls.kwargs_create_item.update({
'category': TicketCategory.objects.create(
organization = request.cls.organization,
name = 'a category'
),
'opened_by': request.cls.view_user,
'project': project,
'milestone': project_milestone,
'parent_ticket': parent_ticket,
'external_system': int(request.cls.model.Ticket_ExternalSystem.CUSTOM_1),
'impact': int(request.cls.model.TicketImpact.MEDIUM),
'priority': int(request.cls.model.TicketPriority.HIGH),
'status': request.cls.model.TicketStatus.CLOSED,
})
if request.cls.model._meta.sub_model_type != 'ticket':
request.cls.url_view_kwargs.update({
'ticket_type': str(request.cls.model._meta.sub_model_type),
})
yield
with django_db_blocker.unblock():
request.cls.entity_user.delete()
parent_ticket.delete()
try:
project_milestone.delete()
except django.db.models.deletion.ProtectedError:
pass
try:
project.delete()
except django.db.models.deletion.ProtectedError:
pass
try:
request.cls.kwargs_create_item['category'].delete()
except django.db.models.deletion.ProtectedError:
pass
if 'ticket_type' in request.cls.url_view_kwargs:
del request.cls.url_view_kwargs['ticket_type']
@pytest.fixture( scope = 'class')
def post_model_create(self, request, django_db_blocker):
with django_db_blocker.unblock():
request.cls.item.assigned_to.add(request.cls.entity_user.id)
request.cls.item.subscribed_to.add(request.cls.entity_user.id)
@pytest.fixture( scope = 'class', autouse = True)
def class_setup(self,
setup_pre,
setup_model,
create_model,
post_model_create,
setup_post,
):
pass
parameterized_test_data = {
'model_notes': {
'expected': models.NOT_PROVIDED
},
'_urls.notes': {
'expected': models.NOT_PROVIDED
},
'external_system': {
'expected': int
},
'external_ref': {
'expected': int
},
'parent_ticket': {
'expected': dict
},
'parent_ticket.id': {
'expected': int
},
'parent_ticket.display_name': {
'expected': str
},
'parent_ticket.url': {
'expected': str
},
'ticket_type': {
'expected': str
},
'status': {
'expected': int
},
'status_badge': {
'expected': dict
},
'status_badge.icon': {
'expected': dict
},
'status_badge.icon.name': {
'expected': str
},
'status_badge.icon.style': {
'expected': str
},
'status_badge.text': {
'expected': str
},
'status_badge.text_style': {
'expected': str
},
'status_badge.url': {
'expected': type(None)
},
'category': {
'expected': dict
},
'category.id': {
'expected': int
},
'category.display_name': {
'expected': str
},
'category.url': {
'expected': Hyperlink
},
'title': {
'expected': str
},
'description': {
'expected': str
},
'ticket_duration': {
'expected': int
},
'ticket_estimation': {
'expected': int
},
'project': {
'expected': dict
},
'project.id': {
'expected': int
},
'project.display_name': {
'expected': str
},
'project.url': {
'expected': Hyperlink
},
'milestone': {
'expected': dict
},
'milestone.id': {
'expected': int
},
'milestone.display_name': {
'expected': str
},
'milestone.url': {
'expected': str
},
'urgency': {
'expected': int
},
'urgency_badge': {
'expected': dict
},
'urgency_badge.icon': {
'expected': dict
},
'urgency_badge.icon.name': {
'expected': str
},
'urgency_badge.icon.style': {
'expected': str
},
'urgency_badge.text': {
'expected': str
},
'urgency_badge.text_style': {
'expected': str
},
'urgency_badge.url': {
'expected': type(None)
},
'impact': {
'expected': int
},
'impact_badge': {
'expected': dict
},
'impact_badge.icon': {
'expected': dict
},
'impact_badge.icon.name': {
'expected': str
},
'impact_badge.icon.style': {
'expected': str
},
'impact_badge.text': {
'expected': str
},
'impact_badge.text_style': {
'expected': str
},
'impact_badge.url': {
'expected': type(None)
},
'priority': {
'expected': int
},
'priority_badge': {
'expected': dict
},
'priority_badge.icon': {
'expected': dict
},
'priority_badge.icon.name': {
'expected': str
},
'priority_badge.icon.style': {
'expected': str
},
'priority_badge.text': {
'expected': str
},
'priority_badge.text_style': {
'expected': str
},
'priority_badge.url': {
'expected': type(None)
},
'opened_by': {
'expected': dict
},
'opened_by.id': {
'expected': int
},
'opened_by.display_name': {
'expected': str
},
'opened_by.first_name': {
'expected': str
},
'opened_by.last_name': {
'expected': str
},
'opened_by.username': {
'expected': str
},
'opened_by.username': {
'expected': str
},
'opened_by.is_active': {
'expected': bool
},
'opened_by.url': {
'expected': Hyperlink
},
'subscribed_to': {
'expected': list
},
'subscribed_to.0.id': {
'expected': int
},
'subscribed_to.0.display_name': {
'expected': str
},
'subscribed_to.0.url': {
'expected': str
},
'assigned_to': {
'expected': list
},
'assigned_to.0.id': {
'expected': int
},
'assigned_to.0.display_name': {
'expected': str
},
'assigned_to.0.url': {
'expected': str
},
'planned_start_date': {
'expected': str
},
'planned_finish_date': {
'expected': str
},
'real_start_date': {
'expected': str
},
'real_finish_date': {
'expected': str
},
'is_deleted': {
'expected': bool
},
'is_solved': {
'expected': bool
},
'date_solved': {
'expected': str
},
'is_closed': {
'expected': bool
},
'date_closed': {
'expected': str
},
}
kwargs_create_item: dict = {
'external_ref': 1,
'title': 'ticket title',
'description': 'the ticket description',
'planned_start_date': '2025-04-16T00:00:01',
'planned_finish_date': '2025-04-16T00:00:02',
'real_start_date': '2025-04-16T00:00:03',
'real_finish_date': '2025-04-16T00:00:04',
'is_solved': True,
'date_solved': '2025-05-12T02:30:01',
'is_closed': True,
'date_closed': '2025-05-12T02:30:02',
}
url_ns_name = '_api_ticketbase'
"""Url namespace (optional, if not required) and url name"""
# def test_api_field_value_ticket_type(self):
# """ Test for value of an API Field
# **note:** you must override this test with the correct value for
# your ticket type
# ticket_type field must be 'ticket'
# """
# assert self.api_data['ticket_type'] == 'ticket'
class TicketBaseAPIInheritedCases(
APITestCases,
):
kwargs_create_item: dict = None
model = None
url_ns_name = '_api_ticketbase_sub'
@pytest.mark.module_core
class TicketBaseAPIPyTest(
APITestCases,
):
pass

View File

@ -464,11 +464,11 @@ class TicketBaseModelTestCases(
' ', '').replace(':', '').replace('+', '').replace('.', '')
kwargs['external_ref'] = int(random_str[len(random_str)-9:])
kwargs['status'] = model._meta.get_field('status').default
ticket = model.objects.create(
**kwargs,
status = model._meta.get_field('status').default,
)
yield ticket

View File

@ -0,0 +1,204 @@
import pytest
import random
from django.test import Client
class AdditionalTestCases:
def test_permission_add(self, model_instance, api_request_permissions,
model_kwargs, kwargs_api_create
):
""" Check correct permission for add
Attempt to add as user with permission
"""
client = Client()
client.force_login( api_request_permissions['user']['add'] )
the_model = model_instance( kwargs_create = self.kwargs_create_item )
url = the_model.get_url( many = True )
the_model.delete()
kwargs = kwargs_api_create.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
response = client.post(
path = url,
data = kwargs,
content_type = 'application/json'
)
assert response.status_code == 201, response.content
def test_returned_results_only_user_orgs(self, model_instance, model_kwargs, api_request_permissions):
"""Returned results check
Ensure that a query to the viewset endpoint does not return
items that are not part of the users organizations.
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
]
if getattr(self, 'global_organization', None):
# Cater for above test that also has global org
viewable_organizations += [ api_request_permissions['tenancy']['global'] ]
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
# if response.status_code == 405:
# pytest.xfail( reason = 'ViewSet does not have this request method.' )
# elif IsAuthenticatedOrReadOnly in response.renderer_context['view'].permission_classes:
# pytest.xfail( reason = 'ViewSet is public viewable, test is N/A' )
assert response.status_code == 200
contains_different_org: bool = False
for item in response.data['results']:
if 'organization' not in item:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if(
int(item['organization']['id']) not in viewable_organizations
and
int(item['organization']['id']) != api_request_permissions['tenancy']['global'].id
):
contains_different_org = True
print(f'Failed returned row was: {item}')
assert not contains_different_org
def test_returned_data_from_user_and_global_organizations_only(
self, model_instance, model_kwargs, api_request_permissions
):
"""Check items returned
Items returned from the query Must be from the users organization and
global ONLY!
"""
if model_kwargs.get('organization', None) is None:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
client = Client()
only_from_user_org: bool = True
viewable_organizations = [
api_request_permissions['tenancy']['user'].id,
api_request_permissions['tenancy']['global'].id
]
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['different']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance(
kwargs_create = kwargs
)
kwargs = self.kwargs_create_item.copy()
kwargs.update({
'organization': api_request_permissions['tenancy']['global']
})
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
model_instance(
kwargs_create = kwargs
)
client.force_login( api_request_permissions['user']['view'] )
kwargs = self.kwargs_create_item.copy()
kwargs['dob'] = str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
the_model = model_instance( kwargs_create = kwargs )
response = client.get(
path = the_model.get_url( many = True )
)
assert len(response.data['results']) >= 2 # fail if only one item extist.
for row in response.data['results']:
if 'organization' not in row:
pytest.xfail( reason = 'Model lacks organization field. test is n/a' )
if row['organization']['id'] not in viewable_organizations:
only_from_user_org = False
print(f"Users org: {api_request_permissions['tenancy']['user'].id}")
print(f"global org: {api_request_permissions['tenancy']['global'].id}")
print(f'Failed returned row was: {row}')
assert only_from_user_org

View File

@ -24,3 +24,11 @@ def create_serializer():
yield serializer
del serializer
@pytest.fixture( scope = 'class', autouse = True)
def model_kwargs(request, kwargs_requestticket):
request.cls.kwargs_create_item = kwargs_requestticket.copy()
yield kwargs_requestticket.copy()

View File

@ -1,4 +1,4 @@
from itim.tests.unit.ticket_slm.test_unit_ticket_slm_api_fields import TicketSLMAPIInheritedCases
from itim.tests.functional.ticket_slm.test_functional_ticket_slm_api_fields import TicketSLMAPIInheritedCases
@ -6,7 +6,7 @@ class TicketRequestAPITestCases(
TicketSLMAPIInheritedCases,
):
model = None
pass
@ -14,9 +14,7 @@ class TicketRequestAPIInheritedCases(
TicketRequestAPITestCases,
):
kwargs_create_item: dict = None
model = None
pass

View File

@ -22,3 +22,14 @@ def create_serializer():
yield serializer
del serializer
@pytest.fixture( scope = 'class', autouse = True)
def model_kwargs(request, kwargs_slmticket):
request.cls.kwargs_create_item = kwargs_slmticket.copy()
yield kwargs_slmticket.copy()
if hasattr(request.cls, 'kwargs_create_item'):
del request.cls.kwargs_create_item

View File

@ -1,6 +1,6 @@
import pytest
from core.tests.unit.ticket_base.test_unit_ticket_base_api_fields import (
from core.tests.functional.ticket_base.test_functional_ticket_base_api_fields import (
TicketBaseAPIInheritedCases,
)
@ -11,19 +11,18 @@ class TicketSLMAPITestCases(
TicketBaseAPIInheritedCases,
):
parameterized_test_data = {
'tto': {
'expected': int
},
'ttr': {
'expected': int
}
}
@property
def parameterized_api_fields(self):
return {
'tto': {
'expected': int
},
'ttr': {
'expected': int
}
}
kwargs_create_item: dict = {
'tto': 11,
'ttr': 22,
}
@ -32,9 +31,7 @@ class TicketSLMAPIInheritedCases(
TicketSLMAPITestCases,
):
kwargs_create_item: dict = None
model = None
pass
#

View File

@ -1,5 +1,6 @@
import datetime
import pytest
import random
from access.models.person import Person
@ -24,7 +25,8 @@ def kwargs_person( kwargs_entity ):
'f_name': 'p' + random_str,
'm_name': 'p' + random_str,
'l_name': 'p' + random_str,
'dob': '2025-04-08'
'dob': str(random.randint(1972, 2037)) + '-' + str(
random.randint(1, 12)) + '-' + str(random.randint(1, 28))
}
yield kwargs.copy()

View File

@ -1,5 +1,8 @@
import datetime
import pytest
import random
from django.db import models
from core.models.ticket_base import TicketBase
@ -13,7 +16,9 @@ def model_ticketbase(request):
@pytest.fixture( scope = 'class')
def kwargs_ticketbase(django_db_blocker, kwargs_centurionmodel,
model_user, kwargs_user, model_ticketbase
model_user, kwargs_user, model_ticketbase,
model_project, model_projectmilestone,
model_ticketcategory,
):
random_str = str(datetime.datetime.now(tz=datetime.timezone.utc))
@ -24,16 +29,56 @@ def kwargs_ticketbase(django_db_blocker, kwargs_centurionmodel,
user = model_user.objects.create( **kwargs_user.copy() )
project = model_project.objects.create(
organization = kwargs_centurionmodel['organization'],
name = 'project' + str( random.randint(1, 99999))
)
project_milestone = model_projectmilestone.objects.create(
organization = kwargs_centurionmodel['organization'],
name = 'project milestone one' + str( random.randint(1, 99999)),
project = project
)
category = model_ticketcategory.objects.create(
organization = kwargs_centurionmodel['organization'],
name = 'tb cat ' + str( random.randint(1, 99999)),
)
kwargs = kwargs_centurionmodel.copy()
del kwargs['model_notes']
kwargs = {
**kwargs,
'category': category,
'opened_by': user,
'project': project,
'milestone': project_milestone,
# 'parent_ticket': None,
'external_system': model_ticketbase.Ticket_ExternalSystem.GITHUB,
'external_ref': int(random_str[len(random_str)-9:]),
'impact': int(model_ticketbase.TicketImpact.MEDIUM),
'priority': int(model_ticketbase.TicketPriority.HIGH),
'status': model_ticketbase.TicketStatus.NEW,
'title': 'tb_' + random_str,
'description': 'the body',
'opened_by': user,
'planned_start_date': '2025-04-16T00:00:01Z',
'planned_finish_date': '2025-04-16T00:00:02Z',
'real_start_date': '2025-04-16T00:00:03Z',
'real_finish_date': '2025-04-16T00:00:04Z',
# 'is_solved': True,
# 'date_solved': '2025-05-12T02:30:01',
# 'is_closed': True,
# 'date_closed': '2025-05-12T02:30:02',
}
yield kwargs.copy()
@ -43,4 +88,19 @@ def kwargs_ticketbase(django_db_blocker, kwargs_centurionmodel,
try:
user.delete()
except:
pass
pass
try:
project_milestone.delete()
except models.deletion.ProtectedError:
pass
try:
project.delete()
except models.deletion.ProtectedError:
pass
try:
category.delete()
except models.deletion.ProtectedError:
pass