Merge pull request #5406 from edx/dcs/mobile-api-tests
Added tests for mobile API
This commit is contained in:
37
lms/djangoapps/mobile_api/course_info/tests.py
Normal file
37
lms/djangoapps/mobile_api/course_info/tests.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Tests for course_info
|
||||
"""
|
||||
from django.test.utils import override_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from courseware.tests.factories import UserFactory
|
||||
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
||||
class TestVideoOutline(ModuleStoreTestCase, APITestCase):
|
||||
def setUp(self):
|
||||
super(TestVideoOutline, self).setUp()
|
||||
self.user = UserFactory.create()
|
||||
self.course = CourseFactory.create(mobile_available=True)
|
||||
self.client.login(username=self.user.username, password='test')
|
||||
|
||||
def test_about(self):
|
||||
url = reverse('course-about-detail', kwargs={'course_id': unicode(self.course.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue('overview' in response.data)
|
||||
|
||||
def test_handouts(self):
|
||||
url = reverse('course-handouts-list', kwargs={'course_id': unicode(self.course.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_updates(self):
|
||||
url = reverse('course-updates-list', kwargs={'course_id': unicode(self.course.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data, [])
|
||||
# TODO: add handouts and updates, somehow
|
||||
@@ -1,3 +1,7 @@
|
||||
"""
|
||||
Views for course info API
|
||||
"""
|
||||
from django.http import Http404
|
||||
from rest_framework import generics, permissions
|
||||
from rest_framework.authentication import OAuth2Authentication, SessionAuthentication
|
||||
from rest_framework.response import Response
|
||||
@@ -25,9 +29,8 @@ class CourseUpdatesList(generics.ListAPIView):
|
||||
course_id = CourseKey.from_string(kwargs['course_id'])
|
||||
course = modulestore().get_course(course_id)
|
||||
course_updates_module = get_course_info_section_module(request, course, 'updates')
|
||||
|
||||
updates_to_show = [
|
||||
update for update in reversed(course_updates_module.items)
|
||||
update for update in reversed(getattr(course_updates_module, 'items', []))
|
||||
if update.get("status") != "deleted"
|
||||
]
|
||||
return Response(updates_to_show)
|
||||
@@ -43,7 +46,12 @@ class CourseHandoutsList(generics.ListAPIView):
|
||||
course_id = CourseKey.from_string(kwargs['course_id'])
|
||||
course = modulestore().get_course(course_id)
|
||||
course_handouts_module = get_course_info_section_module(request, course, 'handouts')
|
||||
return Response({'handouts_html': course_handouts_module.data})
|
||||
if course_handouts_module:
|
||||
return Response({'handouts_html': course_handouts_module.data})
|
||||
else:
|
||||
# course_handouts_module could be None if there are no handouts
|
||||
# (such as while running tests)
|
||||
raise Http404(u"No handouts for {}".format(unicode(course_id)))
|
||||
|
||||
|
||||
class CourseAboutDetail(generics.RetrieveAPIView):
|
||||
|
||||
92
lms/djangoapps/mobile_api/users/tests.py
Normal file
92
lms/djangoapps/mobile_api/users/tests.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Tests for users API
|
||||
"""
|
||||
from rest_framework.test import APITestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from courseware.tests.factories import StaffFactory, UserFactory
|
||||
from django.core.urlresolvers import reverse
|
||||
from mobile_api.users.serializers import CourseEnrollmentSerializer
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
|
||||
class TestUserApi(ModuleStoreTestCase, APITestCase):
|
||||
"""
|
||||
Test the user info API
|
||||
"""
|
||||
def setUp(self):
|
||||
super(TestUserApi, self).setUp()
|
||||
self.course = CourseFactory.create(mobile_available=True)
|
||||
self.user = UserFactory.create()
|
||||
self.password = 'test'
|
||||
self.username = self.user.username
|
||||
|
||||
def tearDown(self):
|
||||
super(TestUserApi, self).tearDown()
|
||||
self.client.logout()
|
||||
|
||||
def enroll(self):
|
||||
resp = self.client.post(reverse('change_enrollment'), {
|
||||
'enrollment_action': 'enroll',
|
||||
'course_id': self.course.id.to_deprecated_string(),
|
||||
'check_access': True,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def test_user_enrollments(self):
|
||||
url = reverse('courseenrollment-detail', kwargs={'username': self.user.username})
|
||||
|
||||
self.client.login(username=self.username, password=self.password)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data, [])
|
||||
|
||||
self.enroll()
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
courses = response.data
|
||||
|
||||
self.assertTrue(len(courses), 1)
|
||||
course = courses[0]['course']
|
||||
self.assertTrue('video_outline' in course)
|
||||
self.assertTrue('course_handouts' in course)
|
||||
self.assertEqual(course['id'], self.course.id.to_deprecated_string())
|
||||
self.assertEqual(courses[0]['mode'], 'honor')
|
||||
|
||||
def test_user_overview(self):
|
||||
self.client.login(username=self.username, password=self.password)
|
||||
url = reverse('user-detail', kwargs={'username': self.user.username})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.data
|
||||
self.assertEqual(data['username'], self.user.username)
|
||||
self.assertEqual(data['email'], self.user.email)
|
||||
|
||||
def test_overview_anon(self):
|
||||
# anonymous disallowed
|
||||
url = reverse('user-detail', kwargs={'username': self.user.username})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
# can't get info on someone else
|
||||
other = UserFactory.create()
|
||||
self.client.login(username=self.username, password=self.password)
|
||||
response = self.client.get(reverse('user-detail', kwargs={'username': other.username}))
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_redirect_userinfo(self):
|
||||
url = '/api/mobile/v0.5/my_user_info'
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
self.client.login(username=self.username, password=self.password)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(self.username in response['location'])
|
||||
|
||||
def test_course_serializer(self):
|
||||
self.client.login(username=self.username, password=self.password)
|
||||
self.enroll()
|
||||
serialized = CourseEnrollmentSerializer(CourseEnrollment.enrollments_for_user(self.user)[0]).data
|
||||
self.assertEqual(serialized['course']['video_outline'], None)
|
||||
self.assertEqual(serialized['course']['name'], self.course.display_name)
|
||||
@@ -51,19 +51,11 @@ class UserCourseEnrollmentsList(generics.ListAPIView):
|
||||
).order_by('created')
|
||||
return mobile_course_enrollments(qset, self.request.user)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.user.username != kwargs['username']:
|
||||
raise PermissionDenied
|
||||
|
||||
return super(UserCourseEnrollmentsList, self).get(self, request, *args, **kwargs)
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@authentication_classes((OAuth2Authentication, SessionAuthentication))
|
||||
@permission_classes((IsAuthenticated,))
|
||||
def my_user_info(request):
|
||||
if not request.user:
|
||||
raise PermissionDenied
|
||||
return redirect("user-detail", username=request.user.username)
|
||||
|
||||
def mobile_course_enrollments(enrollments, user):
|
||||
|
||||
@@ -20,7 +20,7 @@ class BlockOutline(object):
|
||||
self.local_cache['course_videos'] = get_video_info_for_course_and_profile(
|
||||
unicode(course_id), "mobile_low"
|
||||
)
|
||||
except ValInternalError:
|
||||
except ValInternalError: # pragma: nocover
|
||||
self.local_cache['course_videos'] = {}
|
||||
|
||||
def __iter__(self):
|
||||
@@ -114,6 +114,7 @@ def video_summary(course, course_id, video_descriptor, request, local_cache):
|
||||
|
||||
# Transcripts...
|
||||
transcript_langs = video_descriptor.available_translations(verify_assets=False)
|
||||
|
||||
transcripts = {
|
||||
lang: reverse(
|
||||
'video-transcripts-detail',
|
||||
|
||||
172
lms/djangoapps/mobile_api/video_outlines/tests.py
Normal file
172
lms/djangoapps/mobile_api/video_outlines/tests.py
Normal file
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Tests for video outline API
|
||||
"""
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
from xmodule.video_module import transcripts_utils
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from courseware.tests.factories import UserFactory
|
||||
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test.utils import override_settings
|
||||
from django.conf import settings
|
||||
from rest_framework.test import APITestCase
|
||||
from edxval import api
|
||||
from uuid import uuid4
|
||||
import copy
|
||||
|
||||
TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE)
|
||||
TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'] = 'test_xcontent_%s' % uuid4().hex
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE, CONTENTSTORE=TEST_DATA_CONTENTSTORE)
|
||||
class TestVideoOutline(ModuleStoreTestCase, APITestCase):
|
||||
def setUp(self):
|
||||
super(TestVideoOutline, self).setUp()
|
||||
self.user = UserFactory.create()
|
||||
self.course = CourseFactory.create(mobile_available=True)
|
||||
section = ItemFactory.create(
|
||||
parent_location=self.course.location,
|
||||
category="chapter",
|
||||
display_name=u"test factory section omega \u03a9",
|
||||
)
|
||||
self.sub_section = ItemFactory.create(
|
||||
parent_location=section.location,
|
||||
category="sequential",
|
||||
display_name=u"test subsection omega \u03a9",
|
||||
)
|
||||
|
||||
self.unit = ItemFactory.create(
|
||||
parent_location=self.sub_section.location,
|
||||
category="vertical",
|
||||
metadata={'graded': True, 'format': 'Homework'},
|
||||
display_name=u"test unit omega \u03a9",
|
||||
)
|
||||
self.other_unit = ItemFactory.create(
|
||||
parent_location=self.sub_section.location,
|
||||
category="vertical",
|
||||
metadata={'graded': True, 'format': 'Homework'},
|
||||
display_name=u"test unit omega 2 \u03a9",
|
||||
)
|
||||
|
||||
self.edx_video_id = 'testing-123'
|
||||
|
||||
self.video_url = 'http://val.edx.org/val/video.mp4'
|
||||
self.html5_video_url = 'http://video.edx.org/html5/video.mp4'
|
||||
|
||||
api.create_profile({
|
||||
'profile_name': 'youtube',
|
||||
'extension': 'mp4',
|
||||
'width': 1280,
|
||||
'height': 720
|
||||
})
|
||||
api.create_profile({
|
||||
'profile_name': 'mobile_low',
|
||||
'extension': 'mp4',
|
||||
'width': 640,
|
||||
'height': 480
|
||||
})
|
||||
|
||||
val_video = api.create_video({
|
||||
'edx_video_id': self.edx_video_id,
|
||||
'client_video_id': u"test video omega \u03a9",
|
||||
'duration': 12,
|
||||
'courses': [unicode(self.course.id)],
|
||||
'encoded_videos': [
|
||||
{
|
||||
'profile': 'youtube',
|
||||
'url': 'xyz123',
|
||||
'file_size': 0,
|
||||
'bitrate': 1500
|
||||
},
|
||||
{
|
||||
'profile': 'mobile_low',
|
||||
'url': self.video_url,
|
||||
'file_size': 12345,
|
||||
'bitrate': 250
|
||||
}
|
||||
]})
|
||||
|
||||
subid = uuid4().hex
|
||||
self.video = ItemFactory.create(
|
||||
parent_location=self.unit.location,
|
||||
category="video",
|
||||
edx_video_id=self.edx_video_id,
|
||||
display_name=u"test video omega \u03a9",
|
||||
sub=subid
|
||||
)
|
||||
|
||||
result_location = transcripts_utils.save_subs_to_store({
|
||||
'start': [100, 200, 240, 390, 1000],
|
||||
'end': [200, 240, 380, 1000, 1500],
|
||||
'text': [
|
||||
'subs #1',
|
||||
'subs #2',
|
||||
'subs #3',
|
||||
'subs #4',
|
||||
'subs #5'
|
||||
]},
|
||||
subid,
|
||||
self.course)
|
||||
|
||||
self.client.login(username=self.user.username, password='test')
|
||||
|
||||
def test_course_not_available(self):
|
||||
nonmobile = CourseFactory.create()
|
||||
url = reverse('video-summary-list', kwargs={'course_id': unicode(nonmobile.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_course_list(self):
|
||||
second_video = ItemFactory.create(
|
||||
parent_location=self.other_unit.location,
|
||||
category="video",
|
||||
display_name=u"test video omega 2 \u03a9",
|
||||
html5_sources=[self.html5_video_url]
|
||||
)
|
||||
third_video = ItemFactory.create(
|
||||
parent_location=self.other_unit.location,
|
||||
category="video",
|
||||
display_name=u"test video omega 3 \u03a9",
|
||||
source=self.html5_video_url
|
||||
)
|
||||
|
||||
draft_video = ItemFactory.create(
|
||||
parent_location=self.unit.location,
|
||||
category="video",
|
||||
edx_video_id=self.edx_video_id,
|
||||
display_name=u"test draft video omega \u03a9",
|
||||
visible_to_staff_only=True,
|
||||
)
|
||||
|
||||
url = reverse('video-summary-list', kwargs={'course_id': unicode(self.course.id)})
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
course_outline = response.data
|
||||
self.assertEqual(len(course_outline), 3)
|
||||
vid = course_outline[0]
|
||||
self.assertTrue('test_subsection_omega_%CE%A9' in vid['section_url'])
|
||||
self.assertTrue('test_subsection_omega_%CE%A9/1' in vid['unit_url'])
|
||||
self.assertTrue(u'test_video_omega_\u03a9' in vid['summary']['id'])
|
||||
self.assertEqual(vid['summary']['video_url'], self.video_url)
|
||||
self.assertEqual(vid['summary']['size'], 12345)
|
||||
self.assertTrue('en' in vid['summary']['transcripts'])
|
||||
self.assertEqual(course_outline[1]['summary']['video_url'], self.html5_video_url)
|
||||
self.assertEqual(course_outline[1]['summary']['size'], 0)
|
||||
|
||||
self.assertEqual(course_outline[2]['summary']['video_url'], self.html5_video_url)
|
||||
self.assertEqual(course_outline[2]['summary']['size'], 0)
|
||||
|
||||
def test_transcripts(self):
|
||||
kwargs = {
|
||||
'course_id': unicode(self.course.id),
|
||||
'block_id': unicode(self.video.scope_ids.usage_id.block_id),
|
||||
'lang': 'pl'
|
||||
}
|
||||
url = reverse('video-transcripts-detail', kwargs=kwargs)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
kwargs['lang'] = 'en'
|
||||
url = reverse('video-transcripts-detail', kwargs=kwargs)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -15,6 +15,7 @@ from rest_framework import generics, permissions
|
||||
from rest_framework.authentication import OAuth2Authentication, SessionAuthentication
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from opaque_keys.edx.locator import BlockUsageLocator
|
||||
|
||||
@@ -66,7 +67,7 @@ class VideoTranscripts(generics.RetrieveAPIView):
|
||||
video_descriptor = modulestore().get_item(usage_key)
|
||||
content, filename, mimetype = video_descriptor.get_transcript(lang=lang)
|
||||
except (NotFoundError, ValueError, KeyError):
|
||||
raise Http404("Transcript not found for {}, lang: {}".format(block_id, lang))
|
||||
raise Http404(u"Transcript not found for {}, lang: {}".format(block_id, lang))
|
||||
|
||||
response = HttpResponse(content, content_type=mimetype)
|
||||
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
|
||||
|
||||
Reference in New Issue
Block a user