Commit 61f4ceca by Nimisha Asthagiri

Schedules: Emulate HTTP request needs to include host information

parent fab7f31a
...@@ -24,7 +24,7 @@ from openedx.core.djangoapps.schedules.tests.factories import ScheduleConfigFact ...@@ -24,7 +24,7 @@ from openedx.core.djangoapps.schedules.tests.factories import ScheduleConfigFact
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory, SiteFactory from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory, SiteFactory
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, FilteredQueryCountMixin from openedx.core.djangolib.testing.utils import FilteredQueryCountMixin
from student.models import CourseEnrollment from student.models import CourseEnrollment
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
...@@ -75,7 +75,7 @@ ExperienceTest = namedtuple('ExperienceTest', 'experience offset email_sent') ...@@ -75,7 +75,7 @@ ExperienceTest = namedtuple('ExperienceTest', 'experience offset email_sent')
@ddt.ddt @ddt.ddt
@freeze_time('2017-08-01 00:00:00', tz_offset=0, tick=True) @freeze_time('2017-08-01 00:00:00', tz_offset=0, tick=True)
class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase): class ScheduleSendEmailTestMixin(FilteredQueryCountMixin):
__test__ = False __test__ = False
...@@ -85,7 +85,7 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase) ...@@ -85,7 +85,7 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase)
consolidates_emails_for_learner = False consolidates_emails_for_learner = False
def setUp(self): def setUp(self):
super(ScheduleSendEmailTestBase, self).setUp() super(ScheduleSendEmailTestMixin, self).setUp()
site = SiteFactory.create() site = SiteFactory.create()
self.site_config = SiteConfigurationFactory.create(site=site) self.site_config = SiteConfigurationFactory.create(site=site)
...@@ -132,6 +132,15 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase) ...@@ -132,6 +132,15 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase)
self._courses_with_verified_modes.add(course_id) self._courses_with_verified_modes.add(course_id)
return schedule return schedule
def _update_schedule_config(self, schedule_config_kwargs):
"""
Updates the schedule config model by making sure the new entry
has a later timestamp.
"""
later_time = datetime.datetime.now(pytz.UTC) + datetime.timedelta(minutes=1)
with freeze_time(later_time):
ScheduleConfigFactory.create(**schedule_config_kwargs)
def test_command_task_binding(self): def test_command_task_binding(self):
self.assertEqual(self.command.async_send_task, self.task) self.assertEqual(self.command.async_send_task, self.task)
...@@ -239,9 +248,9 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase) ...@@ -239,9 +248,9 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase)
'site': self.site_config.site, 'site': self.site_config.site,
self.deliver_config: is_enabled, self.deliver_config: is_enabled,
} }
mock_message.from_string.return_value.recipient.username = user.username self._update_schedule_config(schedule_config_kwargs)
ScheduleConfigFactory.create(**schedule_config_kwargs)
mock_message.from_string.return_value.recipient.username = user.username
mock_msg = Mock() mock_msg = Mock()
self.deliver_task(self.site_config.site.id, mock_msg) self.deliver_task(self.site_config.site.id, mock_msg)
if is_enabled: if is_enabled:
...@@ -255,7 +264,7 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase) ...@@ -255,7 +264,7 @@ class ScheduleSendEmailTestBase(FilteredQueryCountMixin, CacheIsolationTestCase)
'site': self.site_config.site, 'site': self.site_config.site,
self.enqueue_config: is_enabled, self.enqueue_config: is_enabled,
} }
ScheduleConfigFactory.create(**schedule_config_kwargs) self._update_schedule_config(schedule_config_kwargs)
current_datetime = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC) current_datetime = datetime.datetime(2017, 8, 1, tzinfo=pytz.UTC)
with patch.object(self.task, 'apply_async') as mock_apply_async: with patch.object(self.task, 'apply_async') as mock_apply_async:
......
"""
Tests for send_course_update management command.
"""
# pylint: disable=no-member
import ddt import ddt
from mock import patch from mock import patch, _is_started
from unittest import skipUnless from unittest import skipUnless
from django.conf import settings from django.conf import settings
from edx_ace.utils.date import serialize
from openedx.core.djangoapps.schedules import resolvers, tasks from openedx.core.djangoapps.schedules import resolvers, tasks
from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_WAFFLE_FLAG
from openedx.core.djangoapps.schedules.management.commands import send_course_update as nudge from openedx.core.djangoapps.schedules.management.commands import send_course_update as nudge
from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import ( from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import (
ScheduleSendEmailTestBase, ScheduleSendEmailTestMixin,
ExperienceTest ExperienceTest
) )
from openedx.core.djangoapps.schedules.management.commands.tests.upsell_base import ScheduleUpsellTestMixin from openedx.core.djangoapps.schedules.management.commands.tests.upsell_base import ScheduleUpsellTestMixin
from openedx.core.djangoapps.schedules.models import ScheduleExperience from openedx.core.djangoapps.schedules.models import ScheduleExperience
from openedx.core.djangolib.testing.utils import skip_unless_lms from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from student.tests.factories import CourseEnrollmentFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@ddt.ddt @ddt.ddt
...@@ -21,7 +31,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms ...@@ -21,7 +31,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms
'openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS, 'openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS,
"Can't test schedules if the app isn't installed", "Can't test schedules if the app isn't installed",
) )
class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase): class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestMixin, ModuleStoreTestCase):
__test__ = True __test__ = True
# pylint: disable=protected-access # pylint: disable=protected-access
...@@ -38,10 +48,18 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase): ...@@ -38,10 +48,18 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase):
def setUp(self): def setUp(self):
super(TestSendCourseUpdate, self).setUp() super(TestSendCourseUpdate, self).setUp()
patcher = patch('openedx.core.djangoapps.schedules.resolvers.get_week_highlights') self.highlights_patcher = patch('openedx.core.djangoapps.schedules.resolvers.get_week_highlights')
mock_highlights = patcher.start() mock_highlights = self.highlights_patcher.start()
mock_highlights.return_value = ['Highlight {}'.format(num + 1) for num in range(3)] mock_highlights.return_value = ['Highlight {}'.format(num + 1) for num in range(3)]
self.addCleanup(patcher.stop) self.addCleanup(self.stop_highlights_patcher)
def stop_highlights_patcher(self):
"""
Stops the patcher for the get_week_highlights method
if the patch is still in progress.
"""
if _is_started(self.highlights_patcher):
self.highlights_patcher.stop()
@ddt.data( @ddt.data(
ExperienceTest(experience=ScheduleExperience.EXPERIENCES.default, offset=expected_offsets[0], email_sent=False), ExperienceTest(experience=ScheduleExperience.EXPERIENCES.default, offset=expected_offsets[0], email_sent=False),
...@@ -50,3 +68,30 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase): ...@@ -50,3 +68,30 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase):
) )
def test_schedule_in_different_experience(self, test_config): def test_schedule_in_different_experience(self, test_config):
self._check_if_email_sent_for_experience(test_config) self._check_if_email_sent_for_experience(test_config)
@override_waffle_flag(COURSE_UPDATE_WAFFLE_FLAG, True)
@patch('openedx.core.djangoapps.schedules.signals.get_current_site')
def test_with_course_data(self, mock_get_current_site):
self.highlights_patcher.stop()
mock_get_current_site.return_value = self.site_config.site
course = CourseFactory(highlights_enabled_for_messaging=True, self_paced=True)
with self.store.bulk_operations(course.id):
ItemFactory.create(parent=course, category='chapter', highlights=[u'highlights'])
enrollment = CourseEnrollmentFactory(course_id=course.id, user=self.user, mode=u'audit')
self.assertEqual(enrollment.schedule.get_experience_type(), ScheduleExperience.EXPERIENCES.course_updates)
_, offset, target_day, _ = self._get_dates(offset=self.expected_offsets[0])
enrollment.schedule.start = target_day
enrollment.schedule.save()
with patch.object(tasks, 'ace') as mock_ace:
self.task.apply(kwargs=dict( # pylint: disable=no-value-for-parameter
site_id=self.site_config.site.id,
target_day_str=serialize(target_day),
day_offset=offset,
bin_num=self._calculate_bin_for_user(enrollment.user),
))
self.assertTrue(mock_ace.send.called)
"""
Tests for send_recurring_nudge management command.
"""
from unittest import skipUnless from unittest import skipUnless
import ddt import ddt
...@@ -5,11 +8,13 @@ from django.conf import settings ...@@ -5,11 +8,13 @@ from django.conf import settings
from openedx.core.djangoapps.schedules import resolvers, tasks from openedx.core.djangoapps.schedules import resolvers, tasks
from openedx.core.djangoapps.schedules.management.commands import send_recurring_nudge as nudge from openedx.core.djangoapps.schedules.management.commands import send_recurring_nudge as nudge
from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import ScheduleSendEmailTestBase, \ from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import (
ExperienceTest ScheduleSendEmailTestMixin,
ExperienceTest,
)
from openedx.core.djangoapps.schedules.management.commands.tests.upsell_base import ScheduleUpsellTestMixin from openedx.core.djangoapps.schedules.management.commands.tests.upsell_base import ScheduleUpsellTestMixin
from openedx.core.djangoapps.schedules.models import ScheduleExperience from openedx.core.djangoapps.schedules.models import ScheduleExperience
from openedx.core.djangolib.testing.utils import skip_unless_lms from openedx.core.djangolib.testing.utils import skip_unless_lms, CacheIsolationTestCase
@ddt.ddt @ddt.ddt
...@@ -18,7 +23,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms ...@@ -18,7 +23,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms
'openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS, 'openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS,
"Can't test schedules if the app isn't installed", "Can't test schedules if the app isn't installed",
) )
class TestSendRecurringNudge(ScheduleUpsellTestMixin, ScheduleSendEmailTestBase): class TestSendRecurringNudge(ScheduleUpsellTestMixin, ScheduleSendEmailTestMixin, CacheIsolationTestCase):
__test__ = True __test__ = True
# pylint: disable=protected-access # pylint: disable=protected-access
......
"""
Tests for send_upgrade_reminder management command.
"""
import logging import logging
from unittest import skipUnless from unittest import skipUnless
...@@ -11,10 +14,12 @@ from opaque_keys.edx.locator import CourseLocator ...@@ -11,10 +14,12 @@ from opaque_keys.edx.locator import CourseLocator
from course_modes.models import CourseMode from course_modes.models import CourseMode
from openedx.core.djangoapps.schedules import resolvers, tasks from openedx.core.djangoapps.schedules import resolvers, tasks
from openedx.core.djangoapps.schedules.management.commands import send_upgrade_reminder as reminder from openedx.core.djangoapps.schedules.management.commands import send_upgrade_reminder as reminder
from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import ScheduleSendEmailTestBase, \ from openedx.core.djangoapps.schedules.management.commands.tests.send_email_base import (
ExperienceTest ScheduleSendEmailTestMixin,
ExperienceTest,
)
from openedx.core.djangoapps.schedules.models import ScheduleExperience from openedx.core.djangoapps.schedules.models import ScheduleExperience
from openedx.core.djangolib.testing.utils import skip_unless_lms from openedx.core.djangolib.testing.utils import skip_unless_lms, CacheIsolationTestCase
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
...@@ -25,7 +30,7 @@ LOG = logging.getLogger(__name__) ...@@ -25,7 +30,7 @@ LOG = logging.getLogger(__name__)
@skip_unless_lms @skip_unless_lms
@skipUnless('openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS, @skipUnless('openedx.core.djangoapps.schedules.apps.SchedulesConfig' in settings.INSTALLED_APPS,
"Can't test schedules if the app isn't installed") "Can't test schedules if the app isn't installed")
class TestUpgradeReminder(ScheduleSendEmailTestBase): class TestUpgradeReminder(ScheduleSendEmailTestMixin, CacheIsolationTestCase):
__test__ = True __test__ = True
resolver = resolvers.UpgradeReminderResolver resolver = resolvers.UpgradeReminderResolver
......
...@@ -99,9 +99,9 @@ class ScheduleMessageBaseTask(Task): ...@@ -99,9 +99,9 @@ class ScheduleMessageBaseTask(Task):
def run( def run(
self, site_id, target_day_str, day_offset, bin_num, override_recipient_email=None, self, site_id, target_day_str, day_offset, bin_num, override_recipient_email=None,
): ):
msg_type = self.make_message_type(day_offset)
site = Site.objects.select_related('configuration').get(id=site_id) site = Site.objects.select_related('configuration').get(id=site_id)
with emulate_http_request(site=site): with emulate_http_request(site=site):
msg_type = self.make_message_type(day_offset)
_annotate_for_monitoring(msg_type, site, bin_num, target_day_str, day_offset) _annotate_for_monitoring(msg_type, site, bin_num, target_day_str, day_offset)
return self.resolver( return self.resolver(
self.async_send_task, self.async_send_task,
......
from contextlib import contextmanager from contextlib import contextmanager
from crum import CurrentRequestUserMiddleware from crum import CurrentRequestUserMiddleware
from django.http import HttpRequest, HttpResponse
from openedx.core.djangoapps.theming.middleware import CurrentSiteThemeMiddleware from openedx.core.djangoapps.theming.middleware import CurrentSiteThemeMiddleware
from django.http import HttpResponse
from request_cache import get_request_or_stub
@contextmanager @contextmanager
...@@ -24,9 +25,9 @@ def emulate_http_request(site=None, user=None, middleware_classes=None): ...@@ -24,9 +25,9 @@ def emulate_http_request(site=None, user=None, middleware_classes=None):
middleware_classes (list): A list of classes that implement Django's middleware interface. middleware_classes (list): A list of classes that implement Django's middleware interface.
Defaults to [CurrentRequestUserMiddleware, CurrentSiteThemeMiddleware] if None. Defaults to [CurrentRequestUserMiddleware, CurrentSiteThemeMiddleware] if None.
""" """
request = HttpRequest() request = get_request_or_stub()
request.user = user
request.site = site request.site = site
request.user = user
# TODO: define the default middleware_classes in settings.py # TODO: define the default middleware_classes in settings.py
middleware_classes = middleware_classes or [ middleware_classes = middleware_classes or [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment