Commit 1cdf8497 by John Eskew

Merge pull request #5556 from edx/jeskew/fix_split_old_analytics_call

Fix old analytics api call for Split modulestore.
parents 1f97031f 5e103a91
...@@ -23,12 +23,12 @@ class ProgressTest(unittest.TestCase): ...@@ -23,12 +23,12 @@ class ProgressTest(unittest.TestCase):
def test_create_object(self): def test_create_object(self):
# These should work: # These should work:
p = Progress(0, 2) prg1 = Progress(0, 2) # pylint: disable=W0612
p = Progress(1, 2) prg2 = Progress(1, 2) # pylint: disable=W0612
p = Progress(2, 2) prg3 = Progress(2, 2) # pylint: disable=W0612
p = Progress(2.5, 5.0) prg4 = Progress(2.5, 5.0) # pylint: disable=W0612
p = Progress(3.7, 12.3333) prg5 = Progress(3.7, 12.3333) # pylint: disable=W0612
# These shouldn't # These shouldn't
self.assertRaises(ValueError, Progress, 0, 0) self.assertRaises(ValueError, Progress, 0, 0)
...@@ -44,10 +44,10 @@ class ProgressTest(unittest.TestCase): ...@@ -44,10 +44,10 @@ class ProgressTest(unittest.TestCase):
self.assertEqual((0, 2), Progress(-2, 2).frac()) self.assertEqual((0, 2), Progress(-2, 2).frac())
def test_frac(self): def test_frac(self):
p = Progress(1, 2) prg = Progress(1, 2)
(a, b) = p.frac() (a_mem, b_mem) = prg.frac()
self.assertEqual(a, 1) self.assertEqual(a_mem, 1)
self.assertEqual(b, 2) self.assertEqual(b_mem, 2)
def test_percent(self): def test_percent(self):
self.assertEqual(self.not_started.percent(), 0) self.assertEqual(self.not_started.percent(), 0)
...@@ -98,38 +98,38 @@ class ProgressTest(unittest.TestCase): ...@@ -98,38 +98,38 @@ class ProgressTest(unittest.TestCase):
def test_to_js_detail_str(self): def test_to_js_detail_str(self):
'''Test the Progress.to_js_detail_str() method''' '''Test the Progress.to_js_detail_str() method'''
f = Progress.to_js_detail_str f = Progress.to_js_detail_str
for p in (self.not_started, self.half_done, self.done): for prg in (self.not_started, self.half_done, self.done):
self.assertEqual(f(p), str(p)) self.assertEqual(f(prg), str(prg))
# But None should be encoded as 0 # But None should be encoded as 0
self.assertEqual(f(None), "0") self.assertEqual(f(None), "0")
def test_add(self): def test_add(self):
'''Test the Progress.add_counts() method''' '''Test the Progress.add_counts() method'''
p = Progress(0, 2) prg1 = Progress(0, 2)
p2 = Progress(1, 3) prg2 = Progress(1, 3)
p3 = Progress(2, 5) prg3 = Progress(2, 5)
pNone = None prg_none = None
add = lambda a, b: Progress.add_counts(a, b).frac() add = lambda a, b: Progress.add_counts(a, b).frac()
self.assertEqual(add(p, p), (0, 4)) self.assertEqual(add(prg1, prg1), (0, 4))
self.assertEqual(add(p, p2), (1, 5)) self.assertEqual(add(prg1, prg2), (1, 5))
self.assertEqual(add(p2, p3), (3, 8)) self.assertEqual(add(prg2, prg3), (3, 8))
self.assertEqual(add(p2, pNone), p2.frac()) self.assertEqual(add(prg2, prg_none), prg2.frac())
self.assertEqual(add(pNone, p2), p2.frac()) self.assertEqual(add(prg_none, prg2), prg2.frac())
def test_equality(self): def test_equality(self):
'''Test that comparing Progress objects for equality '''Test that comparing Progress objects for equality
works correctly.''' works correctly.'''
p = Progress(1, 2) prg1 = Progress(1, 2)
p2 = Progress(2, 4) prg2 = Progress(2, 4)
p3 = Progress(1, 2) prg3 = Progress(1, 2)
self.assertTrue(p == p3) self.assertTrue(prg1 == prg3)
self.assertFalse(p == p2) self.assertFalse(prg1 == prg2)
# Check != while we're at it # Check != while we're at it
self.assertTrue(p != p2) self.assertTrue(prg1 != prg2)
self.assertFalse(p != p3) self.assertFalse(prg1 != prg3)
class ModuleProgressTest(unittest.TestCase): class ModuleProgressTest(unittest.TestCase):
...@@ -137,6 +137,6 @@ class ModuleProgressTest(unittest.TestCase): ...@@ -137,6 +137,6 @@ class ModuleProgressTest(unittest.TestCase):
''' '''
def test_xmodule_default(self): def test_xmodule_default(self):
'''Make sure default get_progress exists, returns None''' '''Make sure default get_progress exists, returns None'''
xm = x_module.XModule(Mock(), get_test_system(), DictFieldData({'location': 'a://b/c/d/e'}), Mock()) xmod = x_module.XModule(Mock(), get_test_system(), DictFieldData({'location': 'a://b/c/d/e'}), Mock())
p = xm.get_progress() prg = xmod.get_progress()
self.assertEqual(p, None) self.assertEqual(prg, None)
...@@ -29,6 +29,8 @@ from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE ...@@ -29,6 +29,8 @@ from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from courseware.tests.helpers import LoginEnrollmentTestCase from courseware.tests.helpers import LoginEnrollmentTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from courseware.tests.factories import StaffFactory, InstructorFactory, BetaTesterFactory from courseware.tests.factories import StaffFactory, InstructorFactory, BetaTesterFactory
from student.roles import CourseBetaTesterRole from student.roles import CourseBetaTesterRole
...@@ -2563,6 +2565,7 @@ class TestInstructorEmailContentList(ModuleStoreTestCase, LoginEnrollmentTestCas ...@@ -2563,6 +2565,7 @@ class TestInstructorEmailContentList(ModuleStoreTestCase, LoginEnrollmentTestCas
self.assertDictEqual(expected_info, returned_info) self.assertDictEqual(expected_info, returned_info)
@ddt.ddt
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) @override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
@override_settings(ANALYTICS_SERVER_URL="http://robotanalyticsserver.netbot:900/") @override_settings(ANALYTICS_SERVER_URL="http://robotanalyticsserver.netbot:900/")
@override_settings(ANALYTICS_API_KEY="robot_api_key") @override_settings(ANALYTICS_API_KEY="robot_api_key")
...@@ -2590,25 +2593,84 @@ class TestInstructorAPIAnalyticsProxy(ModuleStoreTestCase, LoginEnrollmentTestCa ...@@ -2590,25 +2593,84 @@ class TestInstructorAPIAnalyticsProxy(ModuleStoreTestCase, LoginEnrollmentTestCa
self.instructor = InstructorFactory(course_key=self.course.id) self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test') self.client.login(username=self.instructor.username, password='test')
@ddt.data((ModuleStoreEnum.Type.mongo, False), (ModuleStoreEnum.Type.split, True))
@ddt.unpack
@patch.object(instructor.views.api.requests, 'get') @patch.object(instructor.views.api.requests, 'get')
def test_analytics_proxy_url(self, act): def test_analytics_proxy_url(self, store_type, assert_wo_encoding, act):
""" Test legacy analytics proxy url generation. """ """ Test legacy analytics proxy url generation. """
with modulestore().default_store(store_type):
course = CourseFactory.create()
instructor_local = InstructorFactory(course_key=course.id)
self.client.login(username=instructor_local.username, password='test')
act.return_value = self.FakeProxyResponse()
url = reverse('proxy_legacy_analytics', kwargs={'course_id': course.id.to_deprecated_string()})
response = self.client.get(url, {
'aname': 'ProblemGradeDistribution'
})
self.assertEqual(response.status_code, 200)
# Make request URL pattern - everything but course id.
url_pattern = "{url}get?aname={aname}&course_id={course_id}&apikey={api_key}".format(
url="http://robotanalyticsserver.netbot:900/",
aname="ProblemGradeDistribution",
course_id="{course_id!s}",
api_key="robot_api_key",
)
if assert_wo_encoding:
# Format url with no URL-encoding of parameters.
assert_url = url_pattern.format(course_id=course.id.to_deprecated_string())
with self.assertRaises(AssertionError):
act.assert_called_once_with(assert_url)
# Format url *with* URL-encoding of parameters.
expected_url = url_pattern.format(course_id=quote(course.id.to_deprecated_string()))
act.assert_called_once_with(expected_url)
@override_settings(ANALYTICS_SERVER_URL="")
@patch.object(instructor.views.api.requests, 'get')
def test_analytics_proxy_server_url(self, act):
"""
Test legacy analytics when empty server url.
"""
act.return_value = self.FakeProxyResponse() act.return_value = self.FakeProxyResponse()
url = reverse('proxy_legacy_analytics', kwargs={'course_id': self.course.id.to_deprecated_string()}) url = reverse('proxy_legacy_analytics', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, { response = self.client.get(url, {
'aname': 'ProblemGradeDistribution' 'aname': 'ProblemGradeDistribution'
}) })
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 501)
# check request url @override_settings(ANALYTICS_API_KEY="")
expected_url = "{url}get?aname={aname}&course_id={course_id!s}&apikey={api_key}".format( @patch.object(instructor.views.api.requests, 'get')
url="http://robotanalyticsserver.netbot:900/", def test_analytics_proxy_api_key(self, act):
aname="ProblemGradeDistribution", """
course_id=self.course.id.to_deprecated_string(), Test legacy analytics when empty server API key.
api_key="robot_api_key", """
) act.return_value = self.FakeProxyResponse()
act.assert_called_once_with(expected_url)
url = reverse('proxy_legacy_analytics', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {
'aname': 'ProblemGradeDistribution'
})
self.assertEqual(response.status_code, 501)
@override_settings(ANALYTICS_SERVER_URL="")
@override_settings(ANALYTICS_API_KEY="")
@patch.object(instructor.views.api.requests, 'get')
def test_analytics_proxy_empty_url_and_api_key(self, act):
"""
Test legacy analytics when empty server url & API key.
"""
act.return_value = self.FakeProxyResponse()
url = reverse('proxy_legacy_analytics', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {
'aname': 'ProblemGradeDistribution'
})
self.assertEqual(response.status_code, 501)
@patch.object(instructor.views.api.requests, 'get') @patch.object(instructor.views.api.requests, 'get')
def test_analytics_proxy(self, act): def test_analytics_proxy(self, act):
......
...@@ -25,6 +25,7 @@ from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbid ...@@ -25,6 +25,7 @@ from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbid
from django.utils.html import strip_tags from django.utils.html import strip_tags
import string # pylint: disable=W0402 import string # pylint: disable=W0402
import random import random
import urllib
from util.json_request import JsonResponse from util.json_request import JsonResponse
from instructor.views.instructor_task_helpers import extract_email_features, extract_task_features from instructor.views.instructor_task_helpers import extract_email_features, extract_task_features
...@@ -1696,7 +1697,7 @@ def send_email(request, course_id): ...@@ -1696,7 +1697,7 @@ def send_email(request, course_id):
course_id, course_id,
request.user, request.user,
send_to, send_to,
subject,message, subject, message,
template_name=template_name, template_name=template_name,
from_addr=from_addr from_addr=from_addr
) )
...@@ -1791,13 +1792,15 @@ def proxy_legacy_analytics(request, course_id): ...@@ -1791,13 +1792,15 @@ def proxy_legacy_analytics(request, course_id):
analytics_name = request.GET.get('aname') analytics_name = request.GET.get('aname')
# abort if misconfigured # abort if misconfigured
if not (hasattr(settings, 'ANALYTICS_SERVER_URL') and hasattr(settings, 'ANALYTICS_API_KEY')): if not (hasattr(settings, 'ANALYTICS_SERVER_URL') and
hasattr(settings, 'ANALYTICS_API_KEY') and
settings.ANALYTICS_SERVER_URL and settings.ANALYTICS_API_KEY):
return HttpResponse("Analytics service not configured.", status=501) return HttpResponse("Analytics service not configured.", status=501)
url = "{}get?aname={}&course_id={}&apikey={}".format( url = "{}get?aname={}&course_id={}&apikey={}".format(
settings.ANALYTICS_SERVER_URL, settings.ANALYTICS_SERVER_URL,
analytics_name, analytics_name,
course_id.to_deprecated_string(), urllib.quote(unicode(course_id)),
settings.ANALYTICS_API_KEY, settings.ANALYTICS_API_KEY,
) )
......
...@@ -11,6 +11,7 @@ import logging ...@@ -11,6 +11,7 @@ import logging
import os import os
import re import re
import requests import requests
import urllib
from collections import defaultdict, OrderedDict from collections import defaultdict, OrderedDict
from markupsafe import escape from markupsafe import escape
...@@ -910,7 +911,7 @@ def instructor_dashboard(request, course_id): ...@@ -910,7 +911,7 @@ def instructor_dashboard(request, course_id):
""" """
url = settings.ANALYTICS_SERVER_URL + \ url = settings.ANALYTICS_SERVER_URL + \
u"get?aname={}&course_id={}&apikey={}".format( u"get?aname={}&course_id={}&apikey={}".format(
analytics_name, course_key.to_deprecated_string(), settings.ANALYTICS_API_KEY analytics_name, urllib.quote(unicode(course_key)), settings.ANALYTICS_API_KEY
) )
try: try:
res = requests.get(url) res = requests.get(url)
......
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