Skip to content

Commit

Permalink
Merge pull request #270 from adamspd/fix-tests-for-django-q2
Browse files Browse the repository at this point in the history
Fix tests for django-q2
  • Loading branch information
adamspd authored Sep 9, 2024
2 parents cfd1d45 + 5d10798 commit 7d9404f
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 30 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ on:
pull_request:
types: [opened, reopened]

env:
USE_DJANGO_Q: 'true'

jobs:
testing:
runs-on: ubuntu-20.04
Expand All @@ -37,16 +40,22 @@ jobs:
coverage debug sys
coverage debug config
- name: Setup Database and Migrations
env:
USE_DJANGO_Q: 'true'
run: |
python manage.py makemigrations
python manage.py migrate
- name: Run Tests
env:
USE_DJANGO_Q: 'true'
run: |
python manage.py test appointment.tests --parallel=10 --shuffle --verbosity=2
- name: Install tblib for better error reporting
if: failure()
run: pip install tblib
- name: Rerun failed tests with tblib
env:
USE_DJANGO_Q: 'true'
if: failure()
run: |
python manage.py test appointment.tests --parallel=10 --shuffle --verbosity=2
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ __pycache__/
local_settings.py
db.sqlite3
db.sqlite3-journal
db.sqlite3.init
media

# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
Expand Down
59 changes: 38 additions & 21 deletions appointment/tests/utils/test_db_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import datetime
from unittest import skip
from unittest.mock import MagicMock, PropertyMock, patch
from unittest.mock import ANY, MagicMock, Mock, PropertyMock, patch

from django.apps import apps
from django.conf import settings
Expand Down Expand Up @@ -251,14 +251,14 @@ def get_mock_reverse(url_name, **kwargs):
return reverse(url_name, **kwargs)


class ScheduleEmailReminderTest(BaseTest):
@classmethod
def setUpClass(cls):
if not DJANGO_Q_AVAILABLE:
import unittest
raise unittest.SkipTest("Django-Q is not available")
super().setUpClass()
# Mock the django_q module
mock_django_q = Mock()
mock_django_q.Schedule = Mock()
mock_django_q.Schedule.ONCE = 'O'


@patch.dict('sys.modules', {'django_q': mock_django_q})
class ScheduleEmailReminderTest(BaseTest):
def setUp(self):
super().setUp()
self.factory = RequestFactory()
Expand All @@ -270,19 +270,36 @@ def tearDown(self):
AppointmentRequest.objects.all().delete()
super().tearDown()

def test_schedule_email_reminder_cluster_running(self):
with patch('appointment.settings.check_q_cluster', return_value=True), \
patch('appointment.utils.db_helpers.schedule') as mock_schedule:
schedule_email_reminder(self.appointment, self.request)
mock_schedule.assert_called_once()
# Further assertions can be made here based on the arguments passed to schedule

def test_schedule_email_reminder_cluster_not_running(self):
with patch('appointment.settings.check_q_cluster', return_value=False), \
patch('appointment.utils.db_helpers.logger') as mock_logger:
schedule_email_reminder(self.appointment, self.request)
mock_logger.warning.assert_called_with(
"Django-Q cluster is not running. Email reminder will not be scheduled.")
@patch('appointment.utils.db_helpers.DJANGO_Q_AVAILABLE', True)
@patch('appointment.utils.db_helpers.schedule')
@patch('appointment.utils.db_helpers.logger')
@patch('appointment.utils.db_helpers.get_absolute_url_')
@patch('appointment.utils.db_helpers.reverse')
def test_schedule_email_reminder_django_q_available(self, mock_reverse, mock_get_absolute_url, mock_logger,
mock_schedule):
mock_reverse.return_value = '/reschedule'
mock_get_absolute_url.return_value = "https://test.com/reschedule"

schedule_email_reminder(self.appointment, self.request)

mock_logger.info.assert_called_once()
mock_schedule.assert_called_once_with(
'appointment.tasks.send_email_reminder',
to_email=self.appointment.client.email,
name=f"reminder_{self.appointment.id_request}",
first_name=self.appointment.client.first_name,
reschedule_link="https://test.com/reschedule",
appointment_id=self.appointment.id,
schedule_type='O',
next_run=ANY
)

@patch('appointment.utils.db_helpers.DJANGO_Q_AVAILABLE', False)
@patch('appointment.utils.db_helpers.logger')
def test_schedule_email_reminder_django_q_not_available(self, mock_logger):
schedule_email_reminder(self.appointment, self.request)
mock_logger.warning.assert_called_once_with(
"Django-Q is not available. Email reminder will not be scheduled.")


class UpdateAppointmentReminderTest(BaseTest, TestCase):
Expand Down
23 changes: 15 additions & 8 deletions appointment/tests/utils/test_staff_member_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
from unittest.mock import patch

from django.core.cache import cache
from django.test import override_settings
from django.test import TransactionTestCase, override_settings

from appointment.models import StaffMember
from appointment.tests.base.base_test import BaseTest
from appointment.utils.db_helpers import Config, WorkingHours, get_staff_member_buffer_time, \
get_staff_member_end_time, get_staff_member_slot_duration, get_staff_member_start_time


class BaseStaffMemberTimeTestSetup(BaseTest):
class BaseStaffMemberTimeTestSetup(BaseTest, TransactionTestCase):
"""Base setup class for staff member time function tests."""

@classmethod
Expand All @@ -23,6 +23,9 @@ def tearDownClass(cls):

def setUp(self):
super().setUp()
cache.clear()
Config.objects.all().delete()
WorkingHours.objects.all().delete()

# Set staff member-specific settings
self.staff_member1.slot_duration = 15
Expand All @@ -43,34 +46,38 @@ def setUp(self):
def tearDown(self):
super().tearDown()
StaffMember.objects.all().delete()
if Config.objects.exists():
Config.objects.all().delete()
Config.objects.all().delete()
WorkingHours.objects.all().delete()
cache.clear()


@patch('appointment.utils.db_helpers.APPOINTMENT_BUFFER_TIME', 59)
class TestGetStaffMemberBufferTime(BaseStaffMemberTimeTestSetup):
"""Test suite for get_staff_member_buffer_time function."""

@patch('appointment.utils.db_helpers.APPOINTMENT_BUFFER_TIME', 59)
def test_staff_member_buffer_time_with_global_setting(self):
"""Test buffer time when staff member-specific setting is None."""
self.staff_member1.appointment_buffer_time = None
self.staff_member1.save()
buffer_time = get_staff_member_buffer_time(self.staff_member1, datetime.date(2023, 10, 9))

with patch('appointment.utils.db_helpers.get_config', return_value=None):
buffer_time = get_staff_member_buffer_time(self.staff_member1, datetime.date(2023, 10, 9))

self.assertEqual(buffer_time, 59) # Global setting

@patch('appointment.utils.db_helpers.APPOINTMENT_BUFFER_TIME', 59)
def test_staff_member_buffer_time_with_staff_member_setting(self):
"""Test buffer time using staff member-specific setting."""
buffer_time = get_staff_member_buffer_time(self.staff_member1, datetime.date(2023, 10, 9))
self.assertEqual(buffer_time, 45) # Staff member specific setting

@patch('appointment.utils.db_helpers.APPOINTMENT_BUFFER_TIME', 59)
def test_staff_member_buffer_time_with_working_hours_conflict(self):
"""Test buffer time when it conflicts with WorkingHours."""
self.staff_member1.appointment_buffer_time = 120 # Set a buffer time greater than WorkingHours start time
self.staff_member1.appointment_buffer_time = 120
self.staff_member1.save()
buffer_time = get_staff_member_buffer_time(self.staff_member1, datetime.date(2023, 10, 9))
self.assertEqual(buffer_time, 120) # Should still use staff member-specific setting even if it causes conflict
self.assertEqual(buffer_time, 120)


@patch('appointment.utils.db_helpers.APPOINTMENT_SLOT_DURATION', 31)
Expand Down
2 changes: 1 addition & 1 deletion appointment/utils/db_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def schedule_email_reminder(appointment, request, appointment_datetime=None):
first_name=appointment.client.first_name,
reschedule_link=reschedule_link,
appointment_id=appointment.id,
schedule_type=Schedule.ONCE, # Use Schedule.ONCE for a one-time task
schedule_type=Schedule.ONCE,
next_run=reminder_datetime)


Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ setuptools==74.1.2
requests~=2.32.3
python-dotenv==1.0.1
colorama~=0.4.6
django-q2==1.6.2

0 comments on commit 7d9404f

Please sign in to comment.