chore(members/tests): various tests

Co-authored by: Claude
pull/154/head^2
Christian Merten 4 months ago
parent 44354cb681
commit 7ea500ebaa
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -1 +1,4 @@
from .basic import *
from .views import *
from .tasks import *
from .rules import *

@ -416,7 +416,7 @@ class AdminTestCase(TestCase):
self.em = EmailAddress.objects.create(name='foobar')
self.staff = Group.objects.create(name='Jugendleiter', contact_email=self.em)
cool_kids = Group.objects.create(name='cool kids')
cool_kids = Group.objects.create(name='cool kids', show_website=True)
super_kids = Group.objects.create(name='super kids')
p1 = PermissionMember.objects.create(member=paul)

@ -0,0 +1,179 @@
from django.test import TestCase
from django.utils import timezone
from django.contrib.auth.models import User
from ..models import Member, Group, Freizeit, DIVERSE, GEMEINSCHAFTS_TOUR, MemberTraining, TrainingCategory, LJPProposal
from ..rules import is_oneself, may_view, may_change, may_delete, is_own_training, is_leader_of_excursion, is_leader, statement_not_submitted, _is_leader
from finance.models import Statement
from mailer.models import EmailAddress
class RulesTestCase(TestCase):
def setUp(self):
# Create email address for groups
self.email_address = EmailAddress.objects.create(name='test@example.com')
# Create test users and members
self.user1 = User.objects.create_user(username='user1', email='user1@example.com')
self.member1 = Member.objects.create(
prename='Test',
lastname='Member1',
birth_date=timezone.now().date(),
email='member1@example.com',
gender=DIVERSE
)
self.user1.member = self.member1
self.user1.save()
self.user2 = User.objects.create_user(username='user2', email='user2@example.com')
self.member2 = Member.objects.create(
prename='Test',
lastname='Member2',
birth_date=timezone.now().date(),
email='member2@example.com',
gender=DIVERSE
)
self.user2.member = self.member2
self.user2.save()
self.user3 = User.objects.create_user(username='user3', email='user3@example.com')
self.member3 = Member.objects.create(
prename='Test',
lastname='Member3',
birth_date=timezone.now().date(),
email='member3@example.com',
gender=DIVERSE
)
self.user3.member = self.member3
self.user3.save()
# Create test group
self.group = Group.objects.create(name='Test Group')
self.group.contact_email = self.email_address
self.group.leiters.add(self.member2)
self.group.save()
# Create test excursion
self.excursion = Freizeit.objects.create(
name='Test Excursion',
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1
)
self.excursion.jugendleiter.add(self.member1)
self.excursion.groups.add(self.group)
self.excursion.save()
# Create training category and training
self.training_category = TrainingCategory.objects.create(
name='Test Training',
permission_needed=False
)
self.training = MemberTraining.objects.create(
member=self.member1,
title='Test Training',
category=self.training_category,
participated=True,
passed=True
)
# Create LJP proposal
self.ljp_proposal = LJPProposal.objects.create(
title='Test LJP',
excursion=self.excursion
)
# Create statement
self.statement_unsubmitted = Statement.objects.create(
short_description='Unsubmitted Statement',
excursion=self.excursion,
submitted=False
)
self.statement_submitted = Statement.objects.create(
short_description='Submitted Statement',
submitted=True
)
def test_is_oneself(self):
"""Test is_oneself rule - member can identify themselves."""
# Same member
self.assertTrue(is_oneself(self.user1, self.member1))
# Different members
self.assertFalse(is_oneself(self.user1, self.member2))
def test_may(self):
"""Test `may_` rules."""
self.assertTrue(may_view(self.user1, self.member1))
self.assertTrue(may_change(self.user1, self.member1))
self.assertTrue(may_delete(self.user1, self.member1))
def test_is_own_training(self):
"""Test is_own_training rule - member can access their own training."""
# Own training
self.assertTrue(is_own_training(self.user1, self.training))
# Other member's training
self.assertFalse(is_own_training(self.user2, self.training))
def test_is_leader_of_excursion(self):
"""Test is_leader_of_excursion rule for LJP proposals."""
# LJP proposal with excursion - member3 is not a leader
self.assertFalse(is_leader_of_excursion(self.user3, self.ljp_proposal))
# Directly pass an excursion
self.assertTrue(is_leader_of_excursion(self.user1, self.excursion))
def test_is_leader(self):
"""Test is_leader rule for excursions."""
# Direct excursion leader
self.assertTrue(is_leader(self.user1, self.excursion))
# Group leader (member2 is leader of group that is part of excursion)
self.assertTrue(is_leader(self.user2, self.excursion))
# member3 is unrelated
self.assertFalse(is_leader(self.user3, self.excursion))
# Test user without member attribute
user_no_member = User.objects.create_user(username='nomember', email='nomember@example.com')
self.assertFalse(is_leader(user_no_member, self.excursion))
# Test member without pk attribute
class MemberNoPk:
pass
member_no_pk = MemberNoPk()
self.assertFalse(_is_leader(member_no_pk, self.excursion))
# Test member with None pk
class MemberNonePk:
pk = None
member_none_pk = MemberNonePk()
self.assertFalse(_is_leader(member_none_pk, self.excursion))
def test_statement_not_submitted(self):
"""Test statement_not_submitted rule."""
# Unsubmitted statement with excursion
self.assertTrue(statement_not_submitted(self.user1, self.excursion))
# Submitted statement
self.excursion.statement = self.statement_submitted
self.excursion.save()
self.assertFalse(statement_not_submitted(self.user1, self.excursion))
# Excursion without statement
excursion_no_statement = Freizeit.objects.create(
name='No Statement Excursion',
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1
)
self.assertFalse(statement_not_submitted(self.user1, excursion_no_statement))
# Test the excursion.statement is None case
# Create a special test object to directly trigger
class ExcursionWithNoneStatement:
def __init__(self):
self.statement = None
# if excursion.statement is None: return False
self.assertFalse(statement_not_submitted(self.user1, ExcursionWithNoneStatement()))

@ -0,0 +1,141 @@
from unittest.mock import patch, MagicMock
from django.test import TestCase
from django.utils import timezone
from django.conf import settings
from ..models import MemberWaitingList, Freizeit, Group, DIVERSE, GEMEINSCHAFTS_TOUR
from ..tasks import ask_for_waiting_confirmation, send_crisis_intervention_list, send_notification_crisis_intervention_list
from mailer.models import EmailAddress
class TasksTestCase(TestCase):
def setUp(self):
# Create test email address
self.email_address = EmailAddress.objects.create(name='test@example.com')
# Create test group
self.group = Group.objects.create(name='Test Group')
self.group.contact_email = self.email_address
self.group.save()
# Create test waiters
now = timezone.now()
old_confirmation = now - timezone.timedelta(days=settings.WAITING_CONFIRMATION_FREQUENCY + 1)
old_reminder = now - timezone.timedelta(days=settings.CONFIRMATION_REMINDER_FREQUENCY + 1)
self.waiter1 = MemberWaitingList.objects.create(
prename='Test',
lastname='Waiter1',
birth_date=now.date(),
email='waiter1@example.com',
gender=DIVERSE,
last_wait_confirmation=old_confirmation,
last_reminder=old_reminder,
sent_reminders=0
)
self.waiter2 = MemberWaitingList.objects.create(
prename='Test',
lastname='Waiter2',
birth_date=now.date(),
email='waiter2@example.com',
gender=DIVERSE,
last_wait_confirmation=old_confirmation,
last_reminder=old_reminder,
sent_reminders=settings.MAX_REMINDER_COUNT - 1
)
# Create waiter that shouldn't receive reminder (too recent confirmation)
self.waiter3 = MemberWaitingList.objects.create(
prename='Test',
lastname='Waiter3',
birth_date=now.date(),
email='waiter3@example.com',
gender=DIVERSE,
last_wait_confirmation=now,
last_reminder=old_reminder,
sent_reminders=0
)
# Create waiter that shouldn't receive reminder (max reminders reached)
self.waiter4 = MemberWaitingList.objects.create(
prename='Test',
lastname='Waiter4',
birth_date=now.date(),
email='waiter4@example.com',
gender=DIVERSE,
last_wait_confirmation=old_confirmation,
last_reminder=old_reminder,
sent_reminders=settings.MAX_REMINDER_COUNT
)
# Create test excursions
today = timezone.now().date()
tomorrow = today + timezone.timedelta(days=1)
self.excursion_today_not_sent = Freizeit.objects.create(
name='Today Excursion 1',
date=timezone.now().replace(hour=10, minute=0, second=0, microsecond=0),
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1,
crisis_intervention_list_sent=False,
notification_crisis_intervention_list_sent=False
)
self.excursion_today_sent = Freizeit.objects.create(
name='Today Excursion 2',
date=timezone.now().replace(hour=14, minute=0, second=0, microsecond=0),
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1,
crisis_intervention_list_sent=True,
notification_crisis_intervention_list_sent=True
)
self.excursion_tomorrow_not_sent = Freizeit.objects.create(
name='Tomorrow Excursion 1',
date=(timezone.now() + timezone.timedelta(days=1)).replace(hour=10, minute=0, second=0, microsecond=0),
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1,
crisis_intervention_list_sent=False,
notification_crisis_intervention_list_sent=False
)
self.excursion_tomorrow_sent = Freizeit.objects.create(
name='Tomorrow Excursion 2',
date=(timezone.now() + timezone.timedelta(days=1)).replace(hour=14, minute=0, second=0, microsecond=0),
tour_type=GEMEINSCHAFTS_TOUR,
kilometers_traveled=10,
difficulty=1,
crisis_intervention_list_sent=True,
notification_crisis_intervention_list_sent=True
)
@patch.object(MemberWaitingList, 'ask_for_wait_confirmation')
def test_ask_for_waiting_confirmation(self, mock_ask):
"""Test ask_for_waiting_confirmation task calls correct waiters."""
result = ask_for_waiting_confirmation()
# Should call ask_for_wait_confirmation for waiter1 and waiter2 only
self.assertEqual(result, 2)
self.assertEqual(mock_ask.call_count, 2)
@patch.object(Freizeit, 'send_crisis_intervention_list')
def test_send_crisis_intervention_list(self, mock_send):
"""Test send_crisis_intervention_list task calls correct excursions."""
result = send_crisis_intervention_list()
# Should call send_crisis_intervention_list for today's excursions that haven't been sent
self.assertEqual(result, 1)
self.assertEqual(mock_send.call_count, 1)
@patch.object(Freizeit, 'notify_leaders_crisis_intervention_list')
def test_send_notification_crisis_intervention_list(self, mock_notify):
"""Test send_notification_crisis_intervention_list task calls correct excursions."""
result = send_notification_crisis_intervention_list()
# Should call notify_leaders_crisis_intervention_list for tomorrow's excursions that haven't been sent
self.assertEqual(result, 1)
self.assertEqual(mock_notify.call_count, 1)

@ -83,7 +83,8 @@ class BasicMemberTestCase(TestCase):
"""
def setUp(self):
self.jl = Group.objects.create(name="Jugendleiter", year_from=0, year_to=0)
self.alp = Group.objects.create(name="Alpenfuechse", year_from=1900, year_to=2000)
self.alp = Group.objects.create(name="Alpenfuechse", year_from=1900, year_to=2000,
show_website=True)
self.spiel = Group.objects.create(name="Spielkinder")
self.fritz = Member.objects.create(prename="Fritz", lastname="Wulter", birth_date=timezone.now().date(),

@ -0,0 +1,110 @@
from unittest import skip
from http import HTTPStatus
from django.test import TestCase, Client
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext as _
from mailer.models import EmailAddress
from ..models import Member, Group, InvitationToGroup, MemberWaitingList, DIVERSE
class ConfirmInvitationViewTestCase(TestCase):
def setUp(self):
self.client = Client()
# Create an email address for the group
self.email_address = EmailAddress.objects.create(name='testmail')
# Create a test group
self.group = Group.objects.create(name='Test Group')
self.group.contact_email = self.email_address
self.group.save()
# Create a waiting list entry
self.waiter = MemberWaitingList.objects.create(
prename='Waiter',
lastname='User',
birth_date=timezone.now().date(),
email='waiter@example.com',
gender=DIVERSE,
wait_confirmation_key='test_wait_key',
wait_confirmation_key_expire=timezone.now() + timezone.timedelta(days=1)
)
# Create an invitation
self.invitation = InvitationToGroup.objects.create(
waiter=self.waiter,
group=self.group,
key='test_invitation_key',
date=timezone.now().date()
)
def test_confirm_invitation_get_valid_key(self):
"""Test GET request with valid key shows invitation confirmation page."""
url = reverse('members:confirm_invitation')
response = self.client.get(url, {'key': 'test_invitation_key'})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('Confirm trial group meeting invitation'))
self.assertContains(response, self.group.name)
def test_confirm_invitation_get_invalid_key(self):
"""Test GET request with invalid key shows invalid confirmation page."""
url = reverse('members:confirm_invitation')
# no key
response = self.client.get(url)
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
# invalid key
response = self.client.get(url, {'key': 'invalid_key'})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
def test_confirm_invitation_get_rejected_invitation(self):
"""Test GET request with rejected invitation shows invalid confirmation page."""
self.invitation.rejected = True
self.invitation.save()
url = reverse('members:confirm_invitation')
response = self.client.get(url, {'key': self.invitation.key})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
def test_confirm_invitation_get_expired_invitation(self):
"""Test GET request with expired invitation shows invalid confirmation page."""
# Set invitation date to more than 30 days ago to make it expired
self.invitation.date = timezone.now().date() - timezone.timedelta(days=31)
self.invitation.save()
url = reverse('members:confirm_invitation')
response = self.client.get(url, {'key': self.invitation.key})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
def test_confirm_invitation_post_invalid_key(self):
"""Test POST request with invalid key shows invalid confirmation page."""
url = reverse('members:confirm_invitation')
# no key
response = self.client.post(url)
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
# invalid key
response = self.client.post(url, {'key': 'invalid_key'})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('This invitation is invalid or expired.'))
def test_confirm_invitation_post_valid_key(self):
"""Test POST request with valid key confirms invitation and shows success page."""
url = reverse('members:confirm_invitation')
response = self.client.post(url, {'key': self.invitation.key})
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(response, _('Invitation confirmed'))
self.assertContains(response, self.group.name)
# Verify invitation was not marked as rejected (confirm() sets rejected=False)
self.invitation.refresh_from_db()
self.assertFalse(self.invitation.rejected)

@ -9,6 +9,7 @@ from members.models import Member, RegistrationPassword, MemberUnconfirmedProxy,
from django.urls import reverse
from django.utils import timezone
from django.conf import settings
from django.views.decorators.cache import never_cache
from .pdf import render_tex, media_path
@ -505,6 +506,7 @@ def render_confirm_success(request, invitation):
'timeinfo': invitation.group.get_time_info()})
@never_cache
def confirm_invitation(request):
if request.method == 'GET' and 'key' in request.GET:
key = request.GET['key']

Loading…
Cancel
Save