feat: Learner Home experimental rollout (#31642)

* feat: add experimental redirect for Learner Home

As a request by Data, this system repeatably groups users into
experiment groups. Based on end of user ID, users that fall beneath a
threshold (LEARNER_HOME_MFE_REDIRECT_PERCENTAGE) will be redirected to
the Learner Home experience, if enabled. Otherwise, learners will see
the legacy dashboard.

* feat: add learner home redirect percentage setting

Adds LEARNER_HOME_MFE_REDIRECT_PERCENTAGE to common settings to avoid a
failed lookup. Can be overridden through config.

* refactor: change test to not leak implementation
This commit is contained in:
Nathan Sprenkle
2023-01-25 10:59:39 -05:00
committed by GitHub
parent 045ae44184
commit f783dce52d
5 changed files with 83 additions and 7 deletions

View File

@@ -235,13 +235,14 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
response = self.client.get(self.path)
self.assertRedirects(response, reverse('account_settings'))
def test_redirect_to_learner_home(self):
@patch('common.djangoapps.student.views.dashboard.should_redirect_to_learner_home_mfe')
def test_redirect_to_learner_home(self, mock_should_redirect_to_learner_home_mfe):
"""
if learner home mfe is enabled, redirect to learner home mfe
"""
with patch('lms.djangoapps.learner_home.waffle.ENABLE_LEARNER_HOME_MFE.is_enabled', return_value=True):
response = self.client.get(self.path)
self.assertRedirects(response, settings.LEARNER_HOME_MICROFRONTEND_URL, fetch_redirect_response=False)
mock_should_redirect_to_learner_home_mfe.return_value = True
response = self.client.get(self.path)
self.assertRedirects(response, settings.LEARNER_HOME_MICROFRONTEND_URL, fetch_redirect_response=False)
def test_course_cert_available_message_after_course_end(self):
course_key = CourseKey.from_string('course-v1:edX+DemoX+Demo_Course')

View File

@@ -521,7 +521,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem
if not UserProfile.objects.filter(user=user).exists():
return redirect(reverse('account_settings'))
if should_redirect_to_learner_home_mfe():
if should_redirect_to_learner_home_mfe(user):
return redirect(settings.LEARNER_HOME_MICROFRONTEND_URL)
platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)

View File

@@ -0,0 +1,54 @@
"""
Tests for toggles, where there is logic beyond enable/disable.
"""
from unittest.mock import patch
import ddt
from django.test import override_settings
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.learner_home.waffle import should_redirect_to_learner_home_mfe
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
@ddt.ddt
class TestLearnerHomeRedirect(SharedModuleStoreTestCase):
"""
Tests for should_redirect_to_learner_home, used for experimental rollout.
"""
def setUp(self):
super().setUp()
# Set up a user for testing
self.user = UserFactory
@patch("lms.djangoapps.learner_home.waffle.ENABLE_LEARNER_HOME_MFE")
def test_should_redirect_to_learner_home_disabled(self, mock_enable_learner_home):
# Given Learner Home MFE feature is not enabled
mock_enable_learner_home.is_enabled.return_value = False
# When I check if I should redirect
redirect_choice = should_redirect_to_learner_home_mfe(self.user)
# Then I never redirect
self.assertFalse(redirect_choice)
@ddt.data((0, True), (50, False), (100, True))
@ddt.unpack
@patch("lms.djangoapps.learner_home.waffle.ENABLE_LEARNER_HOME_MFE")
@override_settings(LEARNER_HOME_MFE_REDIRECT_PERCENTAGE=50)
def test_should_redirect_to_learner_home_enabled(
self, user_id, expect_redirect, mock_enable_learner_home
):
# Given Learner Home MFE feature is enabled
mock_enable_learner_home.is_enabled.return_value = True
self.user.id = user_id
# When I check if I should redirect
redirect_choice = should_redirect_to_learner_home_mfe(self.user)
# Then I redirect based on configuration
# (currently user ID % 100 < redirect percentage)
self.assertEqual(expect_redirect, redirect_choice)

View File

@@ -1,6 +1,7 @@
"""
Configuration for features of Learner Home
"""
from django.conf import settings
from edx_toggles.toggles import WaffleFlag
@@ -22,7 +23,25 @@ ENABLE_LEARNER_HOME_MFE = WaffleFlag(
)
def should_redirect_to_learner_home_mfe():
return configuration_helpers.get_value(
def should_redirect_to_learner_home_mfe(user):
"""
Redirect a percentage of learners to Learner Home for experimentation.
Percentage is based on the LEARNER_HOME_MFE_REDIRECT_PERCENTAGE setting.
"""
is_learning_mfe_enabled = configuration_helpers.get_value(
"ENABLE_LEARNER_HOME_MFE", ENABLE_LEARNER_HOME_MFE.is_enabled()
)
learning_mfe_redirect_percent = configuration_helpers.get_value(
"LEARNER_HOME_MFE_REDIRECT_PERCENTAGE",
settings.LEARNER_HOME_MFE_REDIRECT_PERCENTAGE,
)
# Redirect when 1) Learner Home MFE is enabled and 2) a user falls into the
# target range for experimental rollout.
if is_learning_mfe_enabled and user.id % 100 < learning_mfe_redirect_percent:
return True
return False

View File

@@ -4976,6 +4976,8 @@ HIBP_LOGIN_BLOCK_PASSWORD_FREQUENCY_THRESHOLD = 5
# .. toggle_tickets: https://openedx.atlassian.net/browse/VAN-838
ENABLE_DYNAMIC_REGISTRATION_FIELDS = False
LEARNER_HOME_MFE_REDIRECT_PERCENTAGE = 0
############### Settings for the ace_common plugin #################
# Note that all settings are actually defined by the plugin
# pylint: disable=wrong-import-position