* adds tests for compensations (WIP)
* refactors some dummy data generating into base test class
* fixes bugs detected by testing
* adds important requirements.txt change for itsdangerous package (<1.0.0 for compatibility to django-simple-sso)
pull/40/head
mpeltriaux 3 years ago
parent 5213c717d9
commit b5fc96c1cf

@ -229,6 +229,19 @@ class Compensation(AbstractCompensation):
self.identifier = self.generate_new_identifier() self.identifier = self.generate_new_identifier()
super().save(*args, **kwargs) super().save(*args, **kwargs)
def is_shared_with(self, user: User):
""" Access check
Checks whether a given user has access to this object
Args:
user ():
Returns:
"""
return self.intervention.users.filter(id=user.id)
def get_LANIS_link(self) -> str: def get_LANIS_link(self) -> str:
""" Generates a link for LANIS depending on the geometry """ Generates a link for LANIS depending on the geometry

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,202 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 27.10.21
"""
from django.urls import reverse
from django.test import Client
from compensation.models import CompensationState, CompensationAction
from konova.settings import DEFAULT_GROUP
from konova.tests.test_views import BaseViewTestCase
class ViewTestCase(BaseViewTestCase):
comp_state = None
comp_action = None
def setUp(self) -> None:
super().setUp()
self.create_dummy_states()
self.create_dummy_action()
# Prepare urls
self.index_url = reverse("compensation:index", args=())
self.new_url = reverse("compensation:new", args=(self.intervention.id,))
self.new_id_url = reverse("compensation:new-id", args=())
self.detail_url = reverse("compensation:detail", args=(self.compensation.id,))
self.log_url = reverse("compensation:log", args=(self.compensation.id,))
self.edit_url = reverse("compensation:edit", args=(self.compensation.id,))
self.remove_url = reverse("compensation:remove", args=(self.compensation.id,))
self.report_url = reverse("compensation:report", args=(self.compensation.id,))
self.state_new_url = reverse("compensation:new-state", args=(self.compensation.id,))
self.action_new_url = reverse("compensation:new-action", args=(self.compensation.id,))
self.deadline_new_url = reverse("compensation:new-deadline", args=(self.compensation.id,))
self.new_doc_url = reverse("compensation:new-doc", args=(self.compensation.id,))
self.state_remove_url = reverse("compensation:state-remove", args=(self.comp_state.id,))
self.action_remove_url = reverse("compensation:action-remove", args=(self.comp_action.id,))
def create_dummy_states(self):
""" Creates an intervention which can be used for tests
Returns:
"""
self.comp_state = CompensationState.objects.create(
surface=10.00,
biotope_type=None,
)
self.compensation.before_states.set([self.comp_state])
self.compensation.after_states.set([self.comp_state])
def create_dummy_action(self):
""" Creates an intervention which can be used for tests
Returns:
"""
self.comp_action = CompensationAction.objects.create(
amount=10
)
self.compensation.actions.set([self.comp_action])
def test_logged_in_no_groups_shared(self):
""" Check correct status code for all requests
Assumption: User logged in and has no groups and data is shared
Returns:
"""
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([])
self.intervention.users.set([self.superuser])
# Since the user has no groups, it does not matter that data has been shared. There SHOULD not be any difference
# to a user without access, since the important permissions are missing
success_urls = [
self.index_url,
self.detail_url,
self.report_url,
]
fail_urls = [
self.new_url,
self.new_id_url,
self.log_url,
self.edit_url,
self.remove_url,
self.state_new_url,
self.action_new_url,
self.deadline_new_url,
self.state_remove_url,
self.action_remove_url,
self.new_doc_url,
]
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)
def test_logged_in_no_groups_unshared(self):
""" Check correct status code for all requests
Assumption: User logged in and has no groups and data is shared
Returns:
"""
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([])
self.intervention.users.set([])
# Since the user has no groups, it does not matter that data is unshared. There SHOULD not be any difference
# to a user having shared access, since all important permissions are missing
success_urls = [
self.index_url,
self.detail_url,
self.report_url,
]
fail_urls = [
self.new_url,
self.new_id_url,
self.log_url,
self.edit_url,
self.remove_url,
self.state_new_url,
self.action_new_url,
self.deadline_new_url,
self.state_remove_url,
self.action_remove_url,
self.new_doc_url,
]
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)
def test_logged_in_default_group_shared(self):
""" Check correct status code for all requests
Assumption: User logged in and has no groups and data is shared
Returns:
"""
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
group = self.groups.get(name=DEFAULT_GROUP)
self.superuser.groups.set([group])
self.intervention.users.set([self.superuser])
success_urls = [
self.index_url,
self.detail_url,
self.report_url,
self.new_url,
self.new_id_url,
self.edit_url,
self.state_new_url,
self.action_new_url,
self.deadline_new_url,
self.state_remove_url,
self.action_remove_url,
self.new_doc_url,
self.log_url,
self.remove_url,
]
self.assert_url_success(client, success_urls)
def test_anonymous_user(self):
""" Check correct status code for all requests
Assumption: User not logged in
Returns:
"""
client = Client()
success_urls = [
self.report_url,
]
fail_urls = [
self.index_url,
self.detail_url,
self.new_url,
self.new_id_url,
self.log_url,
self.edit_url,
self.remove_url,
self.state_new_url,
self.action_new_url,
self.deadline_new_url,
self.state_remove_url,
self.action_remove_url,
self.new_doc_url,
]
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)

@ -90,6 +90,7 @@ def new_view(request: HttpRequest, intervention_id: str = None):
@login_required @login_required
@default_group_required
def new_id_view(request: HttpRequest): def new_id_view(request: HttpRequest):
""" JSON endpoint """ JSON endpoint
@ -196,6 +197,8 @@ def detail_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def log_view(request: HttpRequest, id: str): def log_view(request: HttpRequest, id: str):
""" Renders a log view using modal """ Renders a log view using modal
@ -220,6 +223,8 @@ def log_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def remove_view(request: HttpRequest, id: str): def remove_view(request: HttpRequest, id: str):
""" Renders a modal view for removing the compensation """ Renders a modal view for removing the compensation
@ -240,6 +245,8 @@ def remove_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def new_document_view(request: HttpRequest, id: str): def new_document_view(request: HttpRequest, id: str):
""" Renders a form for uploading new documents """ Renders a form for uploading new documents
@ -258,6 +265,7 @@ def new_document_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
def get_document_view(request: HttpRequest, doc_id: str): def get_document_view(request: HttpRequest, doc_id: str):
""" Returns the document as downloadable file """ Returns the document as downloadable file
@ -284,6 +292,7 @@ def get_document_view(request: HttpRequest, doc_id: str):
@login_required @login_required
@default_group_required
def remove_document_view(request: HttpRequest, doc_id: str): def remove_document_view(request: HttpRequest, doc_id: str):
""" Removes the document from the database and file system """ Removes the document from the database and file system
@ -304,6 +313,8 @@ def remove_document_view(request: HttpRequest, doc_id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def state_new_view(request: HttpRequest, id: str): def state_new_view(request: HttpRequest, id: str):
""" Renders a form for adding new states for a compensation """ Renders a form for adding new states for a compensation
@ -323,6 +334,8 @@ def state_new_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def action_new_view(request: HttpRequest, id: str): def action_new_view(request: HttpRequest, id: str):
""" Renders a form for adding new actions for a compensation """ Renders a form for adding new actions for a compensation
@ -342,6 +355,8 @@ def action_new_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
@shared_access_required(Compensation, "id")
def deadline_new_view(request: HttpRequest, id: str): def deadline_new_view(request: HttpRequest, id: str):
""" Renders a form for adding new states for a compensation """ Renders a form for adding new states for a compensation
@ -361,6 +376,7 @@ def deadline_new_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
def state_remove_view(request: HttpRequest, id: str): def state_remove_view(request: HttpRequest, id: str):
""" Renders a form for removing a compensation state """ Renders a form for removing a compensation state
@ -380,6 +396,7 @@ def state_remove_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required
def action_remove_view(request: HttpRequest, id: str): def action_remove_view(request: HttpRequest, id: str):
""" Renders a form for removing a compensation action """ Renders a form for removing a compensation action

@ -18,11 +18,8 @@ from user.models import UserActionLogEntry, UserAction
class ViewTestCase(BaseViewTestCase): class ViewTestCase(BaseViewTestCase):
intervention = None
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
self.create_dummy_data()
# Prepare urls # Prepare urls
self.index_url = reverse("intervention:index", args=()) self.index_url = reverse("intervention:index", args=())
@ -38,35 +35,6 @@ class ViewTestCase(BaseViewTestCase):
self.record_url = reverse("intervention:record", args=(self.intervention.id,)) self.record_url = reverse("intervention:record", args=(self.intervention.id,))
self.report_url = reverse("intervention:report", args=(self.intervention.id,)) self.report_url = reverse("intervention:report", args=(self.intervention.id,))
def create_dummy_data(self):
""" Creates an intervention which can be used for tests
Returns:
"""
# Create dummy data
# Create log entry
action = UserActionLogEntry.objects.create(
user=self.superuser,
action=UserAction.CREATED,
)
# Create legal data object (without M2M laws first)
legal_data = LegalData.objects.create()
# Create responsible data object
responsibility_data = ResponsibilityData.objects.create()
geometry = Geometry.objects.create()
# Finally create main object, holding the other objects
self.intervention = Intervention.objects.create(
identifier="TEST",
title="Test_title",
responsible=responsibility_data,
legal=legal_data,
created=action,
geometry=geometry,
comment="Test",
)
self.intervention.generate_access_token(make_unique=True)
def test_views_logged_in_no_groups(self): def test_views_logged_in_no_groups(self):
""" Check correct status code for all requests """ Check correct status code for all requests
@ -78,7 +46,7 @@ class ViewTestCase(BaseViewTestCase):
# Login client # Login client
client = Client() client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw) client.login(username=self.superuser.username, password=self.superuser_pw)
self.superuser.groups.set([])
success_urls = [ success_urls = [
self.index_url, self.index_url,
self.report_url, self.report_url,
@ -134,7 +102,7 @@ class ViewTestCase(BaseViewTestCase):
response = client.get(url, follow=True) response = client.get(url, follow=True)
self.assertEqual(response.redirect_chain[0], (f"{self.login_url}?next={url}", 302), msg=f"Failed for {url}. Redirect chain is {response.redirect_chain}") self.assertEqual(response.redirect_chain[0], (f"{self.login_url}?next={url}", 302), msg=f"Failed for {url}. Redirect chain is {response.redirect_chain}")
def test_views_logged_in_default_group(self): def test_views_logged_in_default_group_shared(self):
""" Check correct status code for all requests """ Check correct status code for all requests
Assumption: User logged in and is default group member Assumption: User logged in and is default group member
@ -149,6 +117,7 @@ class ViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
default_group = Group.objects.get(name=DEFAULT_GROUP) default_group = Group.objects.get(name=DEFAULT_GROUP)
self.superuser.groups.set([default_group]) self.superuser.groups.set([default_group])
self.intervention.users.set([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -173,10 +142,50 @@ class ViewTestCase(BaseViewTestCase):
self.assert_url_fail(client, fail_urls) self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect) self.assert_url_success_redirect(client, success_urls_redirect)
def test_views_logged_in_zb_group(self): def test_views_logged_in_default_group_unshared(self):
""" Check correct status code for all requests """ Check correct status code for all requests
Assumption: User logged in and is registration office member Assumption: User logged in and is default group member but data is not shared with
Returns:
"""
# Login client
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
# Add user to default group
default_group = Group.objects.get(name=DEFAULT_GROUP)
self.superuser.groups.set([default_group])
self.intervention.users.set([])
success_urls = [
self.index_url,
self.report_url,
self.detail_url,
self.new_id_url,
self.new_url,
]
fail_urls = [
self.run_check_url,
self.record_url,
self.edit_url,
self.remove_url,
self.share_create_url,
self.log_url,
]
success_urls_redirect = {
self.share_url: self.detail_url
}
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect)
def test_views_logged_in_zb_group_shared(self):
""" Check correct status code for all requests
Assumption: User logged in and is registration office member and data is shared
Returns: Returns:
@ -188,6 +197,7 @@ class ViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
zb_group = self.groups.get(name=ZB_GROUP) zb_group = self.groups.get(name=ZB_GROUP)
self.superuser.groups.set([zb_group]) self.superuser.groups.set([zb_group])
self.intervention.users.set([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -212,10 +222,50 @@ class ViewTestCase(BaseViewTestCase):
self.assert_url_fail(client, fail_urls) self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect) self.assert_url_success_redirect(client, success_urls_redirect)
def test_views_logged_in_ets_group(self): def test_views_logged_in_zb_group_unshared(self):
""" Check correct status code for all requests
Assumption: User logged in and is registration office member but data is not shared
Returns:
"""
# Login client
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
# Add user to default group
zb_group = self.groups.get(name=ZB_GROUP)
self.superuser.groups.set([zb_group])
self.intervention.users.set([])
success_urls = [
self.index_url,
self.report_url,
self.detail_url,
]
fail_urls = [
self.log_url,
self.new_id_url,
self.new_url,
self.edit_url,
self.remove_url,
self.share_create_url,
self.record_url,
self.run_check_url,
]
success_urls_redirect = {
self.share_url: self.detail_url
}
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect)
def test_views_logged_in_ets_group_shared(self):
""" Check correct status code for all requests """ Check correct status code for all requests
Assumption: User logged in and is registration office member Assumption: User logged in and is registration office member and data is shared with
Returns: Returns:
@ -227,6 +277,7 @@ class ViewTestCase(BaseViewTestCase):
# Add user to default group # Add user to default group
ets_group = Group.objects.get(name=ETS_GROUP) ets_group = Group.objects.get(name=ETS_GROUP)
self.superuser.groups.set([ets_group]) self.superuser.groups.set([ets_group])
self.intervention.users.set([self.superuser])
success_urls = [ success_urls = [
self.index_url, self.index_url,
@ -250,3 +301,43 @@ class ViewTestCase(BaseViewTestCase):
self.assert_url_success(client, success_urls) self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls) self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect) self.assert_url_success_redirect(client, success_urls_redirect)
def test_views_logged_in_ets_group_unshared(self):
""" Check correct status code for all requests
Assumption: User logged in and is registration office member and data is not shared with
Returns:
"""
# Login client
client = Client()
client.login(username=self.superuser.username, password=self.superuser_pw)
# Add user to default group
ets_group = Group.objects.get(name=ETS_GROUP)
self.superuser.groups.set([ets_group])
self.intervention.users.set([])
success_urls = [
self.index_url,
self.report_url,
self.detail_url,
]
fail_urls = [
self.record_url,
self.log_url,
self.new_id_url,
self.new_url,
self.edit_url,
self.remove_url,
self.share_create_url,
self.run_check_url,
]
success_urls_redirect = {
self.share_url: self.detail_url
}
self.assert_url_success(client, success_urls)
self.assert_url_fail(client, fail_urls)
self.assert_url_success_redirect(client, success_urls_redirect)

@ -113,6 +113,7 @@ def new_id_view(request: HttpRequest):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def new_document_view(request: HttpRequest, id: str): def new_document_view(request: HttpRequest, id: str):
""" Renders a form for uploading new documents """ Renders a form for uploading new documents
@ -264,6 +265,7 @@ def detail_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def edit_view(request: HttpRequest, id: str): def edit_view(request: HttpRequest, id: str):
""" """
Renders a view for editing interventions Renders a view for editing interventions
@ -306,6 +308,7 @@ def edit_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def remove_view(request: HttpRequest, id: str): def remove_view(request: HttpRequest, id: str):
""" Renders a remove view for this intervention """ Renders a remove view for this intervention
@ -388,6 +391,7 @@ def share_view(request: HttpRequest, id: str, token: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def create_share_view(request: HttpRequest, id: str): def create_share_view(request: HttpRequest, id: str):
""" Renders sharing form for an intervention """ Renders sharing form for an intervention
@ -408,6 +412,7 @@ def create_share_view(request: HttpRequest, id: str):
@login_required @login_required
@registration_office_group_required @registration_office_group_required
@shared_access_required(Intervention, "id")
def run_check_view(request: HttpRequest, id: str): def run_check_view(request: HttpRequest, id: str):
""" Renders check form for an intervention """ Renders check form for an intervention
@ -429,6 +434,7 @@ def run_check_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def new_revocation_view(request: HttpRequest, id: str): def new_revocation_view(request: HttpRequest, id: str):
""" Renders sharing form for an intervention """ Renders sharing form for an intervention
@ -449,6 +455,7 @@ def new_revocation_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def log_view(request: HttpRequest, id: str): def log_view(request: HttpRequest, id: str):
""" Renders a log view using modal """ Renders a log view using modal
@ -474,6 +481,7 @@ def log_view(request: HttpRequest, id: str):
@login_required @login_required
@default_group_required @default_group_required
@shared_access_required(Intervention, "id")
def new_deduction_view(request: HttpRequest, id: str): def new_deduction_view(request: HttpRequest, id: str):
""" Renders a modal form view for creating deductions """ Renders a modal form view for creating deductions
@ -494,6 +502,7 @@ def new_deduction_view(request: HttpRequest, id: str):
@login_required @login_required
@conservation_office_group_required @conservation_office_group_required
@shared_access_required(Intervention, "id")
def record_view(request: HttpRequest, id: str): def record_view(request: HttpRequest, id: str):
""" Renders a modal form for recording an intervention """ Renders a modal form for recording an intervention

@ -149,7 +149,7 @@ class BaseObject(BaseResource):
Returns: Returns:
""" """
if hasattr(self, "users"): if isinstance(self, ShareableObject):
return self.users.filter(id=user.id) return self.users.filter(id=user.id)
else: else:
return User.objects.none() return User.objects.none()

@ -11,7 +11,11 @@ from django.contrib.auth.models import User, Group
from django.test import TestCase, Client from django.test import TestCase, Client
from django.urls import reverse from django.urls import reverse
from compensation.models import Compensation
from intervention.models import LegalData, ResponsibilityData, Intervention
from konova.management.commands.setup_data import GROUPS_DATA from konova.management.commands.setup_data import GROUPS_DATA
from konova.models import Geometry
from user.models import UserActionLogEntry, UserAction
class BaseTestCase(TestCase): class BaseTestCase(TestCase):
@ -63,10 +67,14 @@ class BaseViewTestCase(BaseTestCase):
""" """
login_url = None login_url = None
intervention = None
compensation = None
def setUp(self) -> None: def setUp(self) -> None:
self.create_users() self.create_users()
self.create_groups() self.create_groups()
self.create_dummy_intervention()
self.create_dummy_compensation()
self.login_url = reverse("simple-sso-login") self.login_url = reverse("simple-sso-login")
def assert_url_success(self, client: Client, urls: list): def assert_url_success(self, client: Client, urls: list):
@ -114,6 +122,61 @@ class BaseViewTestCase(BaseTestCase):
response = client.get(url) response = client.get(url)
self.assertEqual(response.status_code, 302, msg=f"Failed for {url}") self.assertEqual(response.status_code, 302, msg=f"Failed for {url}")
def create_dummy_intervention(self):
""" Creates an intervention which can be used for tests
Returns:
"""
# Create dummy data
# Create log entry
action = UserActionLogEntry.objects.create(
user=self.superuser,
action=UserAction.CREATED,
)
# Create legal data object (without M2M laws first)
legal_data = LegalData.objects.create()
# Create responsible data object
responsibility_data = ResponsibilityData.objects.create()
geometry = Geometry.objects.create()
# Finally create main object, holding the other objects
self.intervention = Intervention.objects.create(
identifier="TEST",
title="Test_title",
responsible=responsibility_data,
legal=legal_data,
created=action,
geometry=geometry,
comment="Test",
)
self.intervention.generate_access_token(make_unique=True)
def create_dummy_compensation(self):
""" Creates an intervention which can be used for tests
Returns:
"""
if self.intervention is None:
self.create_dummy_intervention()
# Create dummy data
# Create log entry
action = UserActionLogEntry.objects.create(
user=self.superuser,
action=UserAction.CREATED,
)
geometry = Geometry.objects.create()
# Finally create main object, holding the other objects
self.compensation = Compensation.objects.create(
identifier="TEST",
title="Test_title",
intervention=self.intervention,
created=action,
geometry=geometry,
comment="Test",
)
self.intervention.generate_access_token(make_unique=True)
class KonovaViewTestCase(BaseViewTestCase): class KonovaViewTestCase(BaseViewTestCase):
""" Holds tests for all regular views, which are not app specific """ Holds tests for all regular views, which are not app specific

@ -14,7 +14,7 @@ django-tables2==2.3.4
et-xmlfile==1.1.0 et-xmlfile==1.1.0
idna==2.10 idna==2.10
importlib-metadata==2.1.1 importlib-metadata==2.1.1
itsdangerous==0.24 itsdangerous<1.0.0
openpyxl==3.0.9 openpyxl==3.0.9
psycopg2-binary==2.9.1 psycopg2-binary==2.9.1
pytz==2020.4 pytz==2020.4

Loading…
Cancel
Save