fix: VAN-1223 - Add is_control property to recommendations viewed event

This commit is contained in:
Shafqat Farhan
2023-01-03 04:12:11 +05:00
parent 849699732a
commit 030267f5ee
6 changed files with 122 additions and 30 deletions

View File

@@ -6,6 +6,7 @@ import json
from unittest import mock
from unittest.mock import Mock
import ddt
from django.urls import reverse_lazy
from edx_toggles.toggles.testutils import override_waffle_flag
@@ -24,6 +25,7 @@ from xmodule.modulestore.tests.django_utils import (
)
@ddt.ddt
class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
"""Unit tests for the course recommendations on learner home page."""
@@ -115,7 +117,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
"""
Verify API returns general recommendations if no course recommendations from amplitude.
"""
mocked_get_personalized_course_recommendations.return_value = [False, []]
mocked_get_personalized_course_recommendations.return_value = [False, True, []]
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
@@ -161,6 +163,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
"""
mocked_get_personalized_course_recommendations.return_value = [
False,
True,
self.recommended_courses,
]
mocked_get_course_data.return_value = self.course_data
@@ -187,6 +190,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
Test that a user gets general recommendations for the control group.
"""
mocked_get_personalized_course_recommendations.return_value = [
True,
True,
self.recommended_courses,
]
@@ -214,6 +218,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
"""
mocked_get_personalized_course_recommendations.return_value = [
False,
True,
self.recommended_courses,
]
mocked_get_course_data.return_value = self.course_data
@@ -244,6 +249,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
"""
mocked_get_personalized_course_recommendations.return_value = [
False,
True,
self.recommended_courses,
]
mocked_get_course_data.return_value = self.course_data
@@ -261,3 +267,40 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
response_content.get("courses"),
self.SERIALIZED_GENERAL_RECOMMENDATIONS,
)
@ddt.data(
(True, False, None),
(False, True, False),
(False, False, None),
(True, True, True),
)
@mock.patch("lms.djangoapps.learner_home.recommendations.views.segment.track")
@mock.patch("lms.djangoapps.learner_home.recommendations.views.get_course_data")
@mock.patch(
"lms.djangoapps.learner_home.recommendations.views.get_personalized_course_recommendations"
)
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
@ddt.unpack
def test_recommendations_viewed_segment_event(
self,
is_control,
has_is_control,
expected_is_control,
mocked_get_personalized_course_recommendations,
mocked_get_course_data,
segment_track_mock
):
"""
Test that Segment event is emitted with desired properties.
"""
mocked_get_personalized_course_recommendations.return_value = [
is_control,
has_is_control,
self.recommended_courses,
]
mocked_get_course_data.return_value = self.course_data
self.client.get(self.url)
assert segment_track_mock.call_count == 1
assert segment_track_mock.call_args[0][1] == "edx.bi.user.recommendations.viewed"
self.assertEqual(segment_track_mock.call_args[0][2]["is_control"], expected_is_control)

View File

@@ -25,7 +25,8 @@ def get_personalized_course_recommendations(user_id):
recommendations = response.get("userData", {}).get("recommendations", [])
if recommendations:
is_control = recommendations[0].get("is_control")
has_is_control = recommendations[0].get("has_is_control")
recommended_course_keys = recommendations[0].get("items")
return is_control, recommended_course_keys
return is_control, has_is_control, recommended_course_keys
return True, []
return True, False, []

View File

@@ -52,6 +52,7 @@ class CourseRecommendationApiView(APIView):
if not should_show_learner_home_amplitude_recommendations():
return Response(status=404)
recommended_courses = []
general_recommendations_response = Response(
CourseRecommendationSerializer(
{
@@ -64,24 +65,17 @@ class CourseRecommendationApiView(APIView):
try:
user_id = request.user.id
is_control, course_keys = get_personalized_course_recommendations(user_id)
is_control, has_is_control, course_keys = get_personalized_course_recommendations(user_id)
except Exception as ex: # pylint: disable=broad-except
logger.warning(f"Cannot get recommendations from Amplitude: {ex}")
return general_recommendations_response
# Emits an event to track student dashboard page visits.
segment.track(
user_id,
"edx.bi.user.recommendations.viewed",
{
"is_personalized_recommendation": not is_control,
},
)
if is_control or not course_keys:
self._emit_recommendations_viewed_event(
user_id, is_control, has_is_control, recommended_courses
)
return general_recommendations_response
recommended_courses = []
user_enrolled_course_keys = set()
fields = ["title", "owners", "marketing_url"]
@@ -105,6 +99,9 @@ class CourseRecommendationApiView(APIView):
"marketing_url": course_data.get("marketing_url"),
}
)
self._emit_recommendations_viewed_event(
user_id, is_control, has_is_control, recommended_courses
)
# If no courses are left after filtering already enrolled courses from
# the list of amplitude recommendations, show general recommendations
@@ -121,3 +118,15 @@ class CourseRecommendationApiView(APIView):
).data,
status=200,
)
def _emit_recommendations_viewed_event(self, user_id, is_control, has_is_control, recommended_courses):
"""Emits an event to track Learner Home page visits."""
segment.track(
user_id,
"edx.bi.user.recommendations.viewed",
{
"is_personalized_recommendation": not is_control,
"is_control": is_control if has_is_control else None,
"course_key_array": [course["course_key"] for course in recommended_courses],
},
)