Commit 3d15bdca by Nimisha Asthagiri Committed by GitHub

Merge pull request #16028 from edx/ret/log-level-per-message

Schedules/ACE - support debug logging via waffle
parents ef5e6560 813007bb
...@@ -807,7 +807,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase): ...@@ -807,7 +807,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
as the issued date for instructor-paced courses as the issued date for instructor-paced courses
""" """
self.course.self_paced = self_paced self.course.self_paced = self_paced
today = datetime.datetime.today() today = datetime.datetime.utcnow()
self.course.certificate_available_date = today + datetime.timedelta(cert_avail_delta) self.course.certificate_available_date = today + datetime.timedelta(cert_avail_delta)
self.store.update_item(self.course, self.user.id) self.store.update_item(self.course, self.user.id)
self._add_course_certificates(count=1, signatory_count=1, is_active=True) self._add_course_certificates(count=1, signatory_count=1, is_active=True)
......
...@@ -26,7 +26,7 @@ from courseware.models import DynamicUpgradeDeadlineConfiguration, CourseDynamic ...@@ -26,7 +26,7 @@ from courseware.models import DynamicUpgradeDeadlineConfiguration, CourseDynamic
from lms.djangoapps.verify_student.models import VerificationDeadline from lms.djangoapps.verify_student.models import VerificationDeadline
from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.schedules.signals import SCHEDULE_WAFFLE_FLAG from openedx.core.djangoapps.schedules.signals import CREATE_SCHEDULE_WAFFLE_FLAG
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
...@@ -481,7 +481,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase): ...@@ -481,7 +481,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase):
mock_get_current_site.return_value = SiteFactory.create() mock_get_current_site.return_value = SiteFactory.create()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_date_with_self_paced_with_enrollment_before_course_start(self): def test_date_with_self_paced_with_enrollment_before_course_start(self):
""" Enrolling before a course begins should result in the upgrade deadline being set relative to the """ Enrolling before a course begins should result in the upgrade deadline being set relative to the
course start date. """ course start date. """
...@@ -493,7 +493,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase): ...@@ -493,7 +493,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase):
block = VerifiedUpgradeDeadlineDate(course, enrollment.user) block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
self.assertEqual(block.date, expected) self.assertEqual(block.date, expected)
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_date_with_self_paced_with_enrollment_after_course_start(self): def test_date_with_self_paced_with_enrollment_after_course_start(self):
""" Enrolling after a course begins should result in the upgrade deadline being set relative to the """ Enrolling after a course begins should result in the upgrade deadline being set relative to the
enrollment date. """ enrollment date. """
...@@ -513,7 +513,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase): ...@@ -513,7 +513,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase):
expected = enrollment.created + timedelta(days=course_config.deadline_days) expected = enrollment.created + timedelta(days=course_config.deadline_days)
self.assertEqual(block.date, expected) self.assertEqual(block.date, expected)
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_date_with_self_paced_without_dynamic_upgrade_deadline(self): def test_date_with_self_paced_without_dynamic_upgrade_deadline(self):
""" Disabling the dynamic upgrade deadline functionality should result in the verified mode's """ Disabling the dynamic upgrade deadline functionality should result in the verified mode's
expiration date being returned. """ expiration date being returned. """
...@@ -524,7 +524,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase): ...@@ -524,7 +524,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase):
block = VerifiedUpgradeDeadlineDate(course, enrollment.user) block = VerifiedUpgradeDeadlineDate(course, enrollment.user)
self.assertEqual(block.date, expected) self.assertEqual(block.date, expected)
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_date_with_self_paced_with_single_course(self): def test_date_with_self_paced_with_single_course(self):
""" If the global switch is off, a single course can still be enabled. """ """ If the global switch is off, a single course can still be enabled. """
course = create_self_paced_course_run(days_till_start=-1) course = create_self_paced_course_run(days_till_start=-1)
...@@ -536,7 +536,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase): ...@@ -536,7 +536,7 @@ class TestScheduleOverrides(SharedModuleStoreTestCase):
expected = enrollment.created + timedelta(days=course_config.deadline_days) expected = enrollment.created + timedelta(days=course_config.deadline_days)
self.assertEqual(block.date, expected) self.assertEqual(block.date, expected)
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_date_with_existing_schedule(self): def test_date_with_existing_schedule(self):
""" If a schedule is created while deadlines are disabled, they shouldn't magically appear once the feature is """ If a schedule is created while deadlines are disabled, they shouldn't magically appear once the feature is
turned on. """ turned on. """
......
from openedx.core.djangoapps.waffle_utils import WaffleFlagNamespace, CourseWaffleFlag, WaffleFlag
WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name=u'schedules')
CREATE_SCHEDULE_WAFFLE_FLAG = CourseWaffleFlag(
waffle_namespace=WAFFLE_FLAG_NAMESPACE,
flag_name=u'create_schedules_for_course',
flag_undefined_default=False
)
DEBUG_MESSAGE_WAFFLE_FLAG = WaffleFlag(WAFFLE_FLAG_NAMESPACE, u'enable_debugging')
...@@ -4,17 +4,15 @@ import datetime ...@@ -4,17 +4,15 @@ import datetime
from dateutil.tz import tzutc, gettz from dateutil.tz import tzutc, gettz
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.test.utils import CaptureQueriesContext
from django.db.models import Prefetch from django.db.models import Prefetch
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import DEFAULT_DB_ALIAS, connections
from django.utils.http import urlquote from django.utils.http import urlquote
from openedx.core.djangoapps.schedules.message_type import ScheduleMessageType
from openedx.core.djangoapps.schedules.models import Schedule from openedx.core.djangoapps.schedules.models import Schedule
from openedx.core.djangoapps.user_api.models import UserPreference from openedx.core.djangoapps.user_api.models import UserPreference
from edx_ace.message import MessageType
from edx_ace.recipient_resolver import RecipientResolver from edx_ace.recipient_resolver import RecipientResolver
from edx_ace import ace from edx_ace import ace
from edx_ace.recipient import Recipient from edx_ace.recipient import Recipient
...@@ -24,7 +22,7 @@ from course_modes.models import CourseMode, format_course_price ...@@ -24,7 +22,7 @@ from course_modes.models import CourseMode, format_course_price
from lms.djangoapps.experiments.utils import check_and_get_upgrade_link from lms.djangoapps.experiments.utils import check_and_get_upgrade_link
class VerifiedUpgradeDeadlineReminder(MessageType): class VerifiedUpgradeDeadlineReminder(ScheduleMessageType):
pass pass
......
...@@ -30,6 +30,8 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -30,6 +30,8 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
# pylint: disable=protected-access # pylint: disable=protected-access
def setUp(self): def setUp(self):
super(TestSendRecurringNudge, self).setUp()
ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC)) ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 15, 44, 30, tzinfo=pytz.UTC))
ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC)) ScheduleFactory.create(start=datetime.datetime(2017, 8, 1, 17, 34, 30, tzinfo=pytz.UTC))
ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC)) ScheduleFactory.create(start=datetime.datetime(2017, 8, 2, 15, 34, 30, tzinfo=pytz.UTC))
...@@ -74,7 +76,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -74,7 +76,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
] ]
test_time_str = serialize(datetime.datetime(2017, 8, 1, 18, tzinfo=pytz.UTC)) test_time_str = serialize(datetime.datetime(2017, 8, 1, 18, tzinfo=pytz.UTC))
with self.assertNumQueries(1): with self.assertNumQueries(2):
tasks.recurring_nudge_schedule_hour( tasks.recurring_nudge_schedule_hour(
self.site_config.site.id, 3, test_time_str, [schedules[0].enrollment.course.org], self.site_config.site.id, 3, test_time_str, [schedules[0].enrollment.course.org],
) )
...@@ -91,7 +93,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -91,7 +93,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
schedule.enrollment.save() schedule.enrollment.save()
test_time_str = serialize(datetime.datetime(2017, 8, 1, 20, tzinfo=pytz.UTC)) test_time_str = serialize(datetime.datetime(2017, 8, 1, 20, tzinfo=pytz.UTC))
with self.assertNumQueries(1): with self.assertNumQueries(2):
tasks.recurring_nudge_schedule_hour( tasks.recurring_nudge_schedule_hour(
self.site_config.site.id, 3, test_time_str, [schedule.enrollment.course.org], self.site_config.site.id, 3, test_time_str, [schedule.enrollment.course.org],
) )
...@@ -152,7 +154,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -152,7 +154,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
) )
test_time_str = serialize(datetime.datetime(2017, 8, 2, 17, tzinfo=pytz.UTC)) test_time_str = serialize(datetime.datetime(2017, 8, 2, 17, tzinfo=pytz.UTC))
with self.assertNumQueries(1): with self.assertNumQueries(2):
tasks.recurring_nudge_schedule_hour( tasks.recurring_nudge_schedule_hour(
limited_config.site.id, 3, test_time_str, org_list=org_list, exclude_orgs=exclude_orgs, limited_config.site.id, 3, test_time_str, org_list=org_list, exclude_orgs=exclude_orgs,
) )
...@@ -180,7 +182,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -180,7 +182,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
] ]
test_time_str = serialize(datetime.datetime(2017, 8, 1, test_hour, tzinfo=pytz.UTC)) test_time_str = serialize(datetime.datetime(2017, 8, 1, test_hour, tzinfo=pytz.UTC))
with self.assertNumQueries(1): with self.assertNumQueries(2):
tasks.recurring_nudge_schedule_hour( tasks.recurring_nudge_schedule_hour(
self.site_config.site.id, 3, test_time_str, [schedules[0].enrollment.course.org], self.site_config.site.id, 3, test_time_str, [schedules[0].enrollment.course.org],
) )
...@@ -217,7 +219,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase): ...@@ -217,7 +219,7 @@ class TestSendRecurringNudge(CacheIsolationTestCase):
with patch.object(tasks, '_recurring_nudge_schedule_send') as mock_schedule_send: with patch.object(tasks, '_recurring_nudge_schedule_send') as mock_schedule_send:
mock_schedule_send.apply_async = lambda args, *_a, **_kw: sent_messages.append(args) mock_schedule_send.apply_async = lambda args, *_a, **_kw: sent_messages.append(args)
with self.assertNumQueries(1): with self.assertNumQueries(2):
tasks.recurring_nudge_schedule_hour( tasks.recurring_nudge_schedule_hour(
self.site_config.site.id, day, test_time_str, [schedules[0].enrollment.course.org], self.site_config.site.id, day, test_time_str, [schedules[0].enrollment.course.org],
) )
......
import logging
from edx_ace.message import MessageType
from openedx.core.djangoapps.schedules.config import DEBUG_MESSAGE_WAFFLE_FLAG
class ScheduleMessageType(MessageType):
def __init__(self, *args, **kwargs):
super(ScheduleMessageType, self).__init__(*args, **kwargs)
self.log_level = logging.DEBUG if DEBUG_MESSAGE_WAFFLE_FLAG.is_enabled() else None
...@@ -10,8 +10,8 @@ from courseware.models import DynamicUpgradeDeadlineConfiguration, CourseDynamic ...@@ -10,8 +10,8 @@ from courseware.models import DynamicUpgradeDeadlineConfiguration, CourseDynamic
from edx_ace.utils import date from edx_ace.utils import date
from openedx.core.djangoapps.signals.signals import COURSE_START_DATE_CHANGED from openedx.core.djangoapps.signals.signals import COURSE_START_DATE_CHANGED
from openedx.core.djangoapps.theming.helpers import get_current_site from openedx.core.djangoapps.theming.helpers import get_current_site
from openedx.core.djangoapps.waffle_utils import WaffleFlagNamespace, CourseWaffleFlag
from student.models import CourseEnrollment from student.models import CourseEnrollment
from .config import CREATE_SCHEDULE_WAFFLE_FLAG
from .models import Schedule, ScheduleConfig from .models import Schedule, ScheduleConfig
from .tasks import update_course_schedules from .tasks import update_course_schedules
...@@ -19,13 +19,6 @@ from .tasks import update_course_schedules ...@@ -19,13 +19,6 @@ from .tasks import update_course_schedules
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
SCHEDULE_WAFFLE_FLAG = CourseWaffleFlag(
waffle_namespace=WaffleFlagNamespace('schedules'),
flag_name='create_schedules_for_course',
flag_undefined_default=False
)
@receiver(post_save, sender=CourseEnrollment, dispatch_uid='create_schedule_for_enrollment') @receiver(post_save, sender=CourseEnrollment, dispatch_uid='create_schedule_for_enrollment')
def create_schedule(sender, **kwargs): def create_schedule(sender, **kwargs):
if not kwargs['created']: if not kwargs['created']:
...@@ -41,7 +34,7 @@ def create_schedule(sender, **kwargs): ...@@ -41,7 +34,7 @@ def create_schedule(sender, **kwargs):
schedule_config = ScheduleConfig.current(current_site) schedule_config = ScheduleConfig.current(current_site)
if ( if (
not schedule_config.create_schedules not schedule_config.create_schedules
and not SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id) and not CREATE_SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)
): ):
log.debug('Schedules: Creation not enabled for this course or for this site') log.debug('Schedules: Creation not enabled for this course or for this site')
return return
......
...@@ -13,12 +13,13 @@ from django.db.models import Min ...@@ -13,12 +13,13 @@ from django.db.models import Min
from django.db.utils import DatabaseError from django.db.utils import DatabaseError
from django.utils.http import urlquote from django.utils.http import urlquote
from edx_ace import ace from edx_ace import ace
from edx_ace.message import Message, MessageType from edx_ace.message import Message
from edx_ace.recipient import Recipient from edx_ace.recipient import Recipient
from edx_ace.utils.date import deserialize from edx_ace.utils.date import deserialize
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from edxmako.shortcuts import marketing_link from edxmako.shortcuts import marketing_link
from openedx.core.djangoapps.schedules.message_type import ScheduleMessageType
from openedx.core.djangoapps.schedules.models import Schedule, ScheduleConfig from openedx.core.djangoapps.schedules.models import Schedule, ScheduleConfig
log = getLogger(__name__) log = getLogger(__name__)
...@@ -48,7 +49,7 @@ def update_course_schedules(self, **kwargs): ...@@ -48,7 +49,7 @@ def update_course_schedules(self, **kwargs):
raise self.retry(kwargs=kwargs, exc=exc) raise self.retry(kwargs=kwargs, exc=exc)
class RecurringNudge(MessageType): class RecurringNudge(ScheduleMessageType):
def __init__(self, day, *args, **kwargs): def __init__(self, day, *args, **kwargs):
super(RecurringNudge, self).__init__(*args, **kwargs) super(RecurringNudge, self).__init__(*args, **kwargs)
self.name = "recurringnudge_day{}".format(day) self.name = "recurringnudge_day{}".format(day)
......
from collections import namedtuple
import datetime import datetime
import ddt import ddt
from enum import Enum
from mock import patch from mock import patch
from pytz import utc from pytz import utc
from course_modes.models import CourseMode from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory from course_modes.tests.factories import CourseModeFactory
from courseware.models import DynamicUpgradeDeadlineConfiguration from courseware.models import DynamicUpgradeDeadlineConfiguration
from openedx.core.djangoapps.schedules.signals import SCHEDULE_WAFFLE_FLAG from openedx.core.djangoapps.schedules.signals import CREATE_SCHEDULE_WAFFLE_FLAG
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.core.djangolib.testing.utils import skip_unless_lms from openedx.core.djangolib.testing.utils import skip_unless_lms
...@@ -37,40 +35,40 @@ class CreateScheduleTests(SharedModuleStoreTestCase): ...@@ -37,40 +35,40 @@ class CreateScheduleTests(SharedModuleStoreTestCase):
with self.assertRaises(Schedule.DoesNotExist): with self.assertRaises(Schedule.DoesNotExist):
enrollment.schedule enrollment.schedule
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_create_schedule(self, mock_get_current_site): def test_create_schedule(self, mock_get_current_site):
site = SiteFactory.create() site = SiteFactory.create()
mock_get_current_site.return_value = site mock_get_current_site.return_value = site
ScheduleConfigFactory.create(site=site) ScheduleConfigFactory.create(site=site)
self.assert_schedule_created() self.assert_schedule_created()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_no_current_site(self, mock_get_current_site): def test_no_current_site(self, mock_get_current_site):
mock_get_current_site.return_value = None mock_get_current_site.return_value = None
self.assert_schedule_not_created() self.assert_schedule_not_created()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_schedule_config_disabled_waffle_enabled(self, mock_get_current_site): def test_schedule_config_disabled_waffle_enabled(self, mock_get_current_site):
site = SiteFactory.create() site = SiteFactory.create()
mock_get_current_site.return_value = site mock_get_current_site.return_value = site
ScheduleConfigFactory.create(site=site, create_schedules=False) ScheduleConfigFactory.create(site=site, create_schedules=False)
self.assert_schedule_created() self.assert_schedule_created()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, False) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, False)
def test_schedule_config_enabled_waffle_disabled(self, mock_get_current_site): def test_schedule_config_enabled_waffle_disabled(self, mock_get_current_site):
site = SiteFactory.create() site = SiteFactory.create()
mock_get_current_site.return_value = site mock_get_current_site.return_value = site
ScheduleConfigFactory.create(site=site, create_schedules=True) ScheduleConfigFactory.create(site=site, create_schedules=True)
self.assert_schedule_created() self.assert_schedule_created()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, False) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, False)
def test_schedule_config_disabled_waffle_disabled(self, mock_get_current_site): def test_schedule_config_disabled_waffle_disabled(self, mock_get_current_site):
site = SiteFactory.create() site = SiteFactory.create()
mock_get_current_site.return_value = site mock_get_current_site.return_value = site
ScheduleConfigFactory.create(site=site, create_schedules=False) ScheduleConfigFactory.create(site=site, create_schedules=False)
self.assert_schedule_not_created() self.assert_schedule_not_created()
@override_waffle_flag(SCHEDULE_WAFFLE_FLAG, True) @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True)
def test_schedule_config_creation_enabled_instructor_paced(self, mock_get_current_site): def test_schedule_config_creation_enabled_instructor_paced(self, mock_get_current_site):
site = SiteFactory.create() site = SiteFactory.create()
mock_get_current_site.return_value = site mock_get_current_site.return_value = site
......
...@@ -38,7 +38,7 @@ django==1.8.18 ...@@ -38,7 +38,7 @@ django==1.8.18
django-waffle==0.12.0 django-waffle==0.12.0
djangorestframework-jwt==1.11.0 djangorestframework-jwt==1.11.0
enum34==1.1.6 enum34==1.1.6
edx-ace==0.1.2 edx-ace==0.1.4
edx-ccx-keys==0.2.1 edx-ccx-keys==0.2.1
edx-celeryutils==0.2.6 edx-celeryutils==0.2.6
edx-drf-extensions==1.2.3 edx-drf-extensions==1.2.3
......
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