Commit 6bba9e86 by christopher lee

MA-169 return all requested profiles

get_video_info_for_course_and_profile only returned one profile.
This has been changed to get_video_info_for_course_and_profiles
where it now takes a list of profiles and then returns the profiles
found.
parent ea9c5408
...@@ -278,12 +278,10 @@ def get_videos_for_ids( ...@@ -278,12 +278,10 @@ def get_videos_for_ids(
return (VideoSerializer(video).data for video in videos) return (VideoSerializer(video).data for video in videos)
def get_video_info_for_course_and_profile(course_id, profile_name): def get_video_info_for_course_and_profiles(course_id, profiles):
""" """
Returns a dict of edx_video_ids with a dict of requested profiles. Returns a dict of edx_video_ids with a dict of requested profiles.
If the profiles or video is not found, urls will be blank.
Args: Args:
course_id (str): id of the course course_id (str): id of the course
profiles (list): list of profile_names profiles (list): list of profile_names
...@@ -292,48 +290,51 @@ def get_video_info_for_course_and_profile(course_id, profile_name): ...@@ -292,48 +290,51 @@ def get_video_info_for_course_and_profile(course_id, profile_name):
edx_video_id edx_video_id
{ {
edx_video_id: { edx_video_id: {
profile_name: { 'duration': length of the video in seconds,
'url': url of the encoding 'profiles': {
'duration': length of the video in seconds profile_name: {
'file_size': size of the file in bytes 'url': url of the encoding
}, 'file_size': size of the file in bytes
},
}
}, },
} }
Example: Example:
Given two videos with two profiles each in course_id 'test_course': Given two videos with two profiles each in course_id 'test_course':
{ {
u'edx_video_id_1': { u'edx_video_id_1': {
u'mobile': { u'duration: 1111,
'url': u'http: //www.example.com/meow', u'profiles': {
'duration': 1111, u'mobile': {
'file_size': 2222 'url': u'http: //www.example.com/meow',
}, 'file_size': 2222
u'desktop': { },
'url': u'http: //www.example.com/woof', u'desktop': {
'duration': 3333, 'url': u'http: //www.example.com/woof',
'file_size': 4444 'file_size': 4444
}
} }
}, },
u'edx_video_id_2': { u'edx_video_id_2': {
u'mobile': { u'duration: 2222,
'url': u'http: //www.example.com/roar', u'profiles': {
'duration': 5555, u'mobile': {
'file_size': 6666 'url': u'http: //www.example.com/roar',
}, 'file_size': 6666
u'desktop': { },
'url': u'http: //www.example.com/bzzz', u'desktop': {
'duration': 7777, 'url': u'http: //www.example.com/bzzz',
'file_size': 8888 'file_size': 8888
}
} }
} }
} }
""" """
#TODO This function needs unit tests. Write them when addressing MA-169
# In case someone passes in a key (VAL doesn't really understand opaque keys) # In case someone passes in a key (VAL doesn't really understand opaque keys)
course_id = unicode(course_id) course_id = unicode(course_id)
try: try:
encoded_videos = EncodedVideo.objects.filter( encoded_videos = EncodedVideo.objects.filter(
profile__profile_name=profile_name, profile__profile_name__in=profiles,
video__courses__course_id=course_id video__courses__course_id=course_id
).select_related() ).select_related()
except Exception: except Exception:
...@@ -342,36 +343,39 @@ def get_video_info_for_course_and_profile(course_id, profile_name): ...@@ -342,36 +343,39 @@ def get_video_info_for_course_and_profile(course_id, profile_name):
raise ValInternalError(error_message) raise ValInternalError(error_message)
# DRF serializers were causing extra queries for some reason... # DRF serializers were causing extra queries for some reason...
return { return_dict = {}
enc_vid.video.edx_video_id: { for enc_vid in encoded_videos:
"url": enc_vid.url, # Add duration to edx_video_id
"file_size": enc_vid.file_size, return_dict.setdefault(enc_vid.video.edx_video_id, {}).update(
"duration": enc_vid.video.duration, {
} "duration": enc_vid.video.duration,
for enc_vid in encoded_videos }
} )
# Add profile information to edx_video_id's profiles
return_dict[enc_vid.video.edx_video_id].setdefault("profiles", {}).update(
{enc_vid.profile.profile_name: {
"url": enc_vid.url,
"file_size": enc_vid.file_size,
}}
)
return return_dict
def copy_course_videos(old_course_id, new_course_id): def copy_course_videos(source_course_id, destination_course_id):
""" """
Adds the new_course_id to the videos taken from the old_course_id Adds the destination_course_id to the videos taken from the source_course_id
Args: Args:
old_course_id: The original course_id source_course_id: The original course_id
new_course_id: The new course_id of the rerun destination_course_id: The new course_id where the videos will be copied
""" """
if old_course_id == new_course_id: if source_course_id == destination_course_id:
raise ValueError( return
"Both course_id's are the same: {}".format(new_course_id)
) videos = Video.objects.filter(courses__course_id=unicode(source_course_id))
if Video.objects.filter(courses__course_id=unicode(new_course_id)):
raise ValCannotCreateError(
"New course id already exists: {}".format(new_course_id)
)
videos = Video.objects.filter(courses__course_id=unicode(old_course_id))
for video in videos: for video in videos:
CourseVideo.objects.create( CourseVideo.objects.get_or_create(
video=video, video=video,
course_id=new_course_id course_id=destination_course_id
) )
...@@ -330,40 +330,43 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -330,40 +330,43 @@ class GetVideoForCourseProfiles(TestCase):
) )
CourseVideo.objects.create(video=video, course_id=self.course_id2) CourseVideo.objects.create(video=video, course_id=self.course_id2)
def _create_video_dict(self, video, profiles, encoded_videos): def _create_video_dict(self, video, encoding_dict):
""" """
Creates a video dict object from given constants Creates a video dict object from given constants
""" """
video_dict = {video['edx_video_id']: {}} return {
for (profile, encoded_video) in zip(profiles, encoded_videos): video['edx_video_id']: {
video_dict[video['edx_video_id']].update( "duration": video['duration'],
{ 'profiles': {
profile['profile_name']: { profile_name: {
'url': encoded_video['url'], "url": encoding["url"],
'file_size': encoded_video['file_size'], "file_size": encoding["file_size"],
'duration': video['duration']
}
} }
) for (profile_name, encoding) in encoding_dict.iteritems()
return video_dict }
}
}
def test_get_video_for_course_profiles_success_one_profile(self): def test_get_video_for_course_profiles_success_one_profile(self):
""" """
Tests get_video_info_for_course_and_profiles for one profile Tests get_video_info_for_course_and_profiles for one profile
""" """
videos = api.get_video_info_for_course_and_profiles( videos = api.get_video_info_for_course_and_profiles(
'test-course', self.course_id,
['mobile'] ['mobile']
) )
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_FISH, constants.VIDEO_DICT_FISH,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE
}
))
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_STAR, constants.VIDEO_DICT_STAR,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE2])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE2
}))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
def test_get_video_for_course_profiles_success_two_profiles(self): def test_get_video_for_course_profiles_success_two_profiles(self):
...@@ -376,19 +379,25 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -376,19 +379,25 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_FISH, constants.VIDEO_DICT_FISH,
[constants.PROFILE_DICT_MOBILE, constants.PROFILE_DICT_DESKTOP], {
[constants.ENCODED_VIDEO_DICT_MOBILE, constants.ENCODED_VIDEO_DICT_DESKTOP])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE,
constants.PROFILE_DICT_DESKTOP["profile_name"]: constants.ENCODED_VIDEO_DICT_DESKTOP,
}
))
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_STAR, constants.VIDEO_DICT_STAR,
[constants.PROFILE_DICT_MOBILE, constants.PROFILE_DICT_DESKTOP], {
[constants.ENCODED_VIDEO_DICT_MOBILE2, constants.ENCODED_VIDEO_DICT_DESKTOP2])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE2,
constants.PROFILE_DICT_DESKTOP["profile_name"]: constants.ENCODED_VIDEO_DICT_DESKTOP2,
}
))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
def test_get_video_for_course_profiles_no_profile(self): def test_get_video_for_course_profiles_no_profile(self):
"""Tests get_video_info_for_course_and_profiles with no such profile""" """Tests get_video_info_for_course_and_profiles with no such profile"""
videos = api.get_video_info_for_course_and_profiles( videos = api.get_video_info_for_course_and_profiles(
'test-course', 'test-course',
['no profile']) ['no_profile'])
self.assertEqual(len(videos), 0) self.assertEqual(len(videos), 0)
videos = api.get_video_info_for_course_and_profiles( videos = api.get_video_info_for_course_and_profiles(
...@@ -402,12 +411,16 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -402,12 +411,16 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_FISH, constants.VIDEO_DICT_FISH,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE
}
))
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_STAR, constants.VIDEO_DICT_STAR,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE2])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE2
}
))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
def test_get_video_for_course_profiles_video_with_one_profile(self): def test_get_video_for_course_profiles_video_with_one_profile(self):
...@@ -420,8 +433,10 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -420,8 +433,10 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_TREE, constants.VIDEO_DICT_TREE,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE3])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE3
}
))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
videos = api.get_video_info_for_course_and_profiles( videos = api.get_video_info_for_course_and_profiles(
...@@ -430,8 +445,10 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -430,8 +445,10 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_PLANT, constants.VIDEO_DICT_PLANT,
[constants.PROFILE_DICT_DESKTOP], {
[constants.ENCODED_VIDEO_DICT_DESKTOP3])) constants.PROFILE_DICT_DESKTOP["profile_name"]: constants.ENCODED_VIDEO_DICT_DESKTOP3
}
))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
def test_get_video_for_course_profiles_repeated_profile(self): def test_get_video_for_course_profiles_repeated_profile(self):
...@@ -444,14 +461,19 @@ class GetVideoForCourseProfiles(TestCase): ...@@ -444,14 +461,19 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {} expected_dict = {}
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_FISH, constants.VIDEO_DICT_FISH,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE,
}
))
expected_dict.update(self._create_video_dict( expected_dict.update(self._create_video_dict(
constants.VIDEO_DICT_STAR, constants.VIDEO_DICT_STAR,
[constants.PROFILE_DICT_MOBILE], {
[constants.ENCODED_VIDEO_DICT_MOBILE2])) constants.PROFILE_DICT_MOBILE["profile_name"]: constants.ENCODED_VIDEO_DICT_MOBILE2
}
))
self.assertEqual(videos, expected_dict) self.assertEqual(videos, expected_dict)
class GetVideosForIds(TestCase): class GetVideosForIds(TestCase):
""" """
Tests the get_videos_for_ids function in api.py Tests the get_videos_for_ids function in api.py
...@@ -620,76 +642,56 @@ class GetVideoInfoTestWithHttpCalls(APIAuthTestCase): ...@@ -620,76 +642,56 @@ class GetVideoInfoTestWithHttpCalls(APIAuthTestCase):
api.get_video_info(constants.VIDEO_DICT_ZEBRA.get("edx_video_id")) api.get_video_info(constants.VIDEO_DICT_ZEBRA.get("edx_video_id"))
class TestRerunCourse(TestCase): class TestCopyCourse(TestCase):
"""Tests rerun course""" """Tests copy_course_videos in api.py"""
def setUp(self): def setUp(self):
""" """
Creates a course for testing Creates a course with 2 videos and a course with 1 video
Creates two videos, each with two encodings.
""" """
Profile.objects.create(**constants.PROFILE_DICT_MOBILE) self.course_id = 'test-course'
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
# 1st video # 1st video
video = Video.objects.create(**constants.VIDEO_DICT_FISH) video = Video.objects.create(**constants.VIDEO_DICT_FISH)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE
)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="desktop"),
**constants.ENCODED_VIDEO_DICT_DESKTOP
)
self.course_id = 'test-course'
CourseVideo.objects.create(video=video, course_id=self.course_id) CourseVideo.objects.create(video=video, course_id=self.course_id)
# 2nd video # 2nd video
video = Video.objects.create(**constants.VIDEO_DICT_STAR) video = Video.objects.create(**constants.VIDEO_DICT_STAR)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE2
)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="desktop"),
**constants.ENCODED_VIDEO_DICT_DESKTOP2
)
CourseVideo.objects.create(video=video, course_id=self.course_id) CourseVideo.objects.create(video=video, course_id=self.course_id)
def _check_video_course_list(self, video, expected_course_list): self.course_id2 = "test-course2"
""" # 3rd video different course
Verifies that given Video has the courses in the course list video = Video.objects.create(**constants.VIDEO_DICT_TREE)
""" CourseVideo.objects.create(video=video, course_id=self.course_id2)
courses = VideoSerializer(video).data['courses']
self.assertEqual(sorted(courses), sorted(expected_course_list))
def test_successful_rerun(self): def test_successful_copy(self):
"""Tests a successful rerun and 2nd rerun""" """Tests a successful copy course"""
api.copy_course_videos('test-course', 'meow-rerun') api.copy_course_videos('test-course', 'course-copy1')
videos = Video.objects.all() original_videos = Video.objects.filter(courses__course_id='test-course')
for video in videos: copied_videos = Video.objects.filter(courses__course_id='course-copy1')
self._check_video_course_list(video, other_course = Video.objects.filter(courses__course_id='test-course2')
['test-course',
'meow-rerun'])
api.copy_course_videos('meow-rerun', 'woof-bark') self.assertEqual(len(original_videos), 2)
videos = Video.objects.all() self.assertEqual(
for video in videos: {original_video.edx_video_id for original_video in original_videos},
self._check_video_course_list(video, {constants.VIDEO_DICT_FISH["edx_video_id"], constants.VIDEO_DICT_STAR["edx_video_id"]}
['test-course', )
'meow-rerun', self.assertTrue(set(original_videos) == set(copied_videos))
'woof-bark'])
def test_same_course_ids(self): def test_same_course_ids(self):
"""Tests when the new course id name is the same as the original""" """
with self.assertRaises(ValueError): Tests when the destination course id name is the same as the source
api.copy_course_videos('test-course', 'test-course') """
original_videos = Video.objects.filter(courses__course_id='test-course')
api.copy_course_videos('test-course', 'test-course')
copied_videos = Video.objects.filter(courses__course_id='test-course')
self.assertEqual(len(original_videos), 2)
self.assertTrue(set(original_videos) == set(copied_videos))
def test_existing_destination_course_id(self):
"""Test when the destination course id already exists"""
api.copy_course_videos('test-course', 'test-course2')
original_videos = Video.objects.filter(courses__course_id='test-course')
copied_videos = Video.objects.filter(courses__course_id='test-course2')
self.assertEqual(len(original_videos), 2)
self.assertLessEqual(set(original_videos), set(copied_videos))
self.assertEqual(len(copied_videos), 3)
def test_existing_new_course_id(self):
"""Test when the new course id already exists"""
api.copy_course_videos('test-course', 'meow-rerun')
with self.assertRaises(ValCannotCreateError):
api.copy_course_videos('test-course', 'meow-rerun')
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