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.
174 lines
6.7 KiB
174 lines
6.7 KiB
from io import StringIO
|
|
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from django.core.management import call_command
|
|
from django.test import TestCase
|
|
|
|
from apps.account.models import ProfessorUser
|
|
from apps.course.models.course import Course, CourseCategory
|
|
from apps.course.models.lesson import CourseChapter, CourseLesson, Lesson
|
|
|
|
|
|
class LessonsCountSyncTests(TestCase):
|
|
def setUp(self):
|
|
self.professor = ProfessorUser.objects.create(
|
|
email='prof-sync@example.com',
|
|
fullname='Professor Sync',
|
|
experience_years=5,
|
|
)
|
|
self.category = CourseCategory.objects.create(
|
|
name='Sync Category',
|
|
slug='sync-category',
|
|
)
|
|
|
|
def _create_course(self, slug, title, lessons_count=0):
|
|
thumbnail = SimpleUploadedFile(f'{slug}.jpg', b'filecontent', content_type='image/jpeg')
|
|
return Course.objects.create(
|
|
title=title,
|
|
slug=slug,
|
|
category=self.category,
|
|
professor=self.professor,
|
|
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=lessons_count,
|
|
description='Description',
|
|
short_description='Short description',
|
|
status=Course.StatusChoices.ONGOING,
|
|
is_free=True,
|
|
)
|
|
|
|
def _create_chapter(self, course, title='Chapter', priority=1):
|
|
return CourseChapter.objects.create(
|
|
course=course,
|
|
title=title,
|
|
priority=priority,
|
|
is_active=True,
|
|
)
|
|
|
|
def _create_course_lesson(self, course, chapter=None, title='Lesson', is_active=True, priority=1):
|
|
if chapter is None:
|
|
chapter = self._create_chapter(course, title=f'{course.title} Chapter', priority=priority)
|
|
|
|
lesson = Lesson.objects.create(
|
|
title=title,
|
|
content_type=Lesson.ContentTypeChoices.VIDEO_FILE,
|
|
duration=5,
|
|
)
|
|
return CourseLesson.objects.create(
|
|
course=course,
|
|
chapter=chapter,
|
|
lesson=lesson,
|
|
priority=priority,
|
|
is_active=is_active,
|
|
)
|
|
|
|
def test_creating_active_course_lesson_updates_lessons_count(self):
|
|
course = self._create_course('create-active-course', 'Create Active Course')
|
|
|
|
self._create_course_lesson(course, title='Lesson 1')
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 1)
|
|
|
|
def test_deleting_active_course_lesson_updates_lessons_count(self):
|
|
course = self._create_course('delete-active-course', 'Delete Active Course')
|
|
course_lesson = self._create_course_lesson(course, title='Lesson 1')
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 1)
|
|
|
|
course_lesson.delete()
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 0)
|
|
|
|
def test_toggling_is_active_updates_lessons_count(self):
|
|
course = self._create_course('toggle-active-course', 'Toggle Active Course')
|
|
course_lesson = self._create_course_lesson(course, title='Lesson 1', is_active=False)
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 0)
|
|
|
|
course_lesson.is_active = True
|
|
course_lesson.save()
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 1)
|
|
|
|
course_lesson.is_active = False
|
|
course_lesson.save()
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 0)
|
|
|
|
def test_moving_course_lesson_updates_old_and_new_course_counts(self):
|
|
old_course = self._create_course('old-course', 'Old Course')
|
|
new_course = self._create_course('new-course', 'New Course')
|
|
old_chapter = self._create_chapter(old_course, title='Old Chapter', priority=1)
|
|
new_chapter = self._create_chapter(new_course, title='New Chapter', priority=1)
|
|
course_lesson = self._create_course_lesson(
|
|
old_course,
|
|
chapter=old_chapter,
|
|
title='Lesson 1',
|
|
is_active=True,
|
|
priority=1,
|
|
)
|
|
|
|
old_course.refresh_from_db()
|
|
new_course.refresh_from_db()
|
|
self.assertEqual(old_course.lessons_count, 1)
|
|
self.assertEqual(new_course.lessons_count, 0)
|
|
|
|
course_lesson.chapter = new_chapter
|
|
course_lesson.save()
|
|
|
|
old_course.refresh_from_db()
|
|
new_course.refresh_from_db()
|
|
self.assertEqual(old_course.lessons_count, 0)
|
|
self.assertEqual(new_course.lessons_count, 1)
|
|
|
|
def test_inactive_lessons_are_not_counted(self):
|
|
course = self._create_course('inactive-course', 'Inactive Course')
|
|
|
|
self._create_course_lesson(course, title='Lesson 1', is_active=False)
|
|
self._create_course_lesson(course, title='Lesson 2', is_active=True, priority=2)
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 1)
|
|
|
|
def test_sync_course_lessons_count_command_updates_mismatched_courses(self):
|
|
first_course = self._create_course('sync-first-course', 'Sync First Course', lessons_count=99)
|
|
second_course = self._create_course('sync-second-course', 'Sync Second Course', lessons_count=7)
|
|
|
|
self._create_course_lesson(first_course, title='Lesson 1', is_active=True)
|
|
self._create_course_lesson(first_course, title='Lesson 2', is_active=False, priority=2)
|
|
self._create_course_lesson(second_course, title='Lesson 3', is_active=True)
|
|
self._create_course_lesson(second_course, title='Lesson 4', is_active=True, priority=2)
|
|
|
|
Course.objects.filter(pk=first_course.pk).update(lessons_count=99)
|
|
Course.objects.filter(pk=second_course.pk).update(lessons_count=7)
|
|
|
|
stdout = StringIO()
|
|
call_command('sync_course_lessons_count', stdout=stdout)
|
|
|
|
first_course.refresh_from_db()
|
|
second_course.refresh_from_db()
|
|
self.assertEqual(first_course.lessons_count, 1)
|
|
self.assertEqual(second_course.lessons_count, 2)
|
|
self.assertIn('Sync complete. 2 course(s) updated.', stdout.getvalue())
|
|
|
|
def test_sync_course_lessons_count_command_dry_run_does_not_persist_changes(self):
|
|
course = self._create_course('sync-dry-course', 'Sync Dry Course', lessons_count=5)
|
|
self._create_course_lesson(course, title='Lesson 1', is_active=True)
|
|
Course.objects.filter(pk=course.pk).update(lessons_count=5)
|
|
|
|
stdout = StringIO()
|
|
call_command('sync_course_lessons_count', '--dry-run', stdout=stdout)
|
|
|
|
course.refresh_from_db()
|
|
self.assertEqual(course.lessons_count, 5)
|
|
self.assertIn('Dry run complete. 1 course(s) would be updated.', stdout.getvalue())
|