You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
6.9 KiB
176 lines
6.9 KiB
import datetime
|
|
from django.utils import timezone
|
|
from django.test import TestCase
|
|
from unittest.mock import patch
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
|
|
from dj_language.models import Language
|
|
from apps.account.models import StudentUser, User, Notification
|
|
from apps.course.models.course import Course, CourseCategory
|
|
from apps.quiz.models import Quiz, QuizParticipant
|
|
from apps.account.tasks import check_low_quiz_results_task
|
|
|
|
class QuizNotificationFlowTests(TestCase):
|
|
def setUp(self):
|
|
# Create languages
|
|
self.lang_ru, _ = Language.objects.update_or_create(
|
|
code='ru',
|
|
defaults={'name': 'Russian', 'status': True, 'countries': []}
|
|
)
|
|
self.lang_en, _ = Language.objects.update_or_create(
|
|
code='en',
|
|
defaults={'name': 'English', 'status': True, 'countries': []}
|
|
)
|
|
|
|
# Create category
|
|
self.category = CourseCategory.objects.create(
|
|
name=[{"title": "Category", "language_code": "en"}],
|
|
slug=[{"title": "category", "language_code": "en"}]
|
|
)
|
|
|
|
# Create student user
|
|
self.student = StudentUser.objects.create(
|
|
email='student_quiz@example.com',
|
|
username='student_quiz',
|
|
fullname='Quiz Student',
|
|
language=self.lang_ru,
|
|
fcm='token_quiz_student'
|
|
)
|
|
|
|
# Create Course
|
|
thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg')
|
|
self.course = Course.objects.create(
|
|
title=[
|
|
{"title": "Course 1", "language_code": "en"},
|
|
{"title": "Курс 1", "language_code": "ru"}
|
|
],
|
|
slug=[{"title": "course-1", "language_code": "en"}],
|
|
category=self.category,
|
|
thumbnail=thumbnail,
|
|
video_type=Course.VedioTypeChoices.YOUTUBE_LINK,
|
|
video_link='https://example.com/video',
|
|
is_online=False,
|
|
level=Course.LevelChoices.BEGINNER,
|
|
duration=10,
|
|
lessons_count=0,
|
|
description='Description',
|
|
short_description='Short description',
|
|
status=[{"title": "ongoing", "language_code": "en"}],
|
|
is_free=True,
|
|
)
|
|
|
|
# Create Quiz
|
|
self.quiz = Quiz.objects.create(
|
|
course=self.course,
|
|
title=[
|
|
{"title": "Quiz A", "language_code": "en"},
|
|
{"title": "Тест А", "language_code": "ru"}
|
|
],
|
|
each_question_timing=60,
|
|
status=True
|
|
)
|
|
|
|
@patch('apps.account.notification_service.send_notification')
|
|
def test_low_quiz_result_triggers_on_intervals(self, mock_send):
|
|
# Event: Low Quiz Result (score < 70)
|
|
# Create failed attempt exactly 2 days ago
|
|
attempt_2_days = QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=2, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=2),
|
|
total_timing=300,
|
|
question_score=50,
|
|
timing_score=0,
|
|
total_score=50
|
|
)
|
|
|
|
# Run periodic task
|
|
check_low_quiz_results_task()
|
|
|
|
# Verify reminder sent to the student (Russian template check)
|
|
notif = Notification.objects.filter(user=self.student, title="Предложение пересдать тест").first()
|
|
self.assertIsNotNone(notif)
|
|
self.assertIn("Тест А", notif.message)
|
|
self.assertTrue(mock_send.called)
|
|
|
|
@patch('apps.account.notification_service.send_notification')
|
|
def test_no_reminder_if_passed_initially(self, mock_send):
|
|
# Create successful attempt exactly 2 days ago (score = 80)
|
|
QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=2, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=2),
|
|
total_timing=300,
|
|
question_score=80,
|
|
timing_score=0,
|
|
total_score=80
|
|
)
|
|
|
|
check_low_quiz_results_task()
|
|
|
|
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())
|
|
self.assertFalse(mock_send.called)
|
|
|
|
@patch('apps.account.notification_service.send_notification')
|
|
def test_no_reminder_if_retaken_and_passed(self, mock_send):
|
|
# Create failed attempt exactly 7 days ago
|
|
attempt_failed = QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=7, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=7),
|
|
total_timing=300,
|
|
question_score=40,
|
|
timing_score=0,
|
|
total_score=40
|
|
)
|
|
|
|
# Create a newer successful attempt 3 days ago
|
|
QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=3, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=3),
|
|
total_timing=300,
|
|
question_score=90,
|
|
timing_score=0,
|
|
total_score=90
|
|
)
|
|
|
|
check_low_quiz_results_task()
|
|
|
|
# Should not suggest retake since they passed subsequently
|
|
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())
|
|
|
|
@patch('apps.account.notification_service.send_notification')
|
|
def test_no_reminder_if_already_retaken_even_if_failed(self, mock_send):
|
|
# Create failed attempt exactly 21 days ago
|
|
attempt_failed = QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=21, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=21),
|
|
total_timing=300,
|
|
question_score=30,
|
|
timing_score=0,
|
|
total_score=30
|
|
)
|
|
|
|
# Create a newer attempt 10 days ago (also failed, e.g. score = 50)
|
|
# Since they already attempted a retake 10 days ago, we shouldn't trigger the 21-day reminder of the first failure.
|
|
QuizParticipant.objects.create(
|
|
quiz=self.quiz,
|
|
user=self.student,
|
|
started_at=timezone.now() - datetime.timedelta(days=10, hours=1),
|
|
ended_at=timezone.now() - datetime.timedelta(days=10),
|
|
total_timing=300,
|
|
question_score=50,
|
|
timing_score=0,
|
|
total_score=50
|
|
)
|
|
|
|
check_low_quiz_results_task()
|
|
|
|
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())
|