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(
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.
If the profiles or video is not found, urls will be blank.
Args:
course_id (str): id of the course
profiles (list): list of profile_names
......@@ -292,48 +290,51 @@ def get_video_info_for_course_and_profile(course_id, profile_name):
edx_video_id
{
edx_video_id: {
'duration': length of the video in seconds,
'profiles': {
profile_name: {
'url': url of the encoding
'duration': length of the video in seconds
'file_size': size of the file in bytes
},
}
},
}
Example:
Given two videos with two profiles each in course_id 'test_course':
{
u'edx_video_id_1': {
u'duration: 1111,
u'profiles': {
u'mobile': {
'url': u'http: //www.example.com/meow',
'duration': 1111,
'file_size': 2222
},
u'desktop': {
'url': u'http: //www.example.com/woof',
'duration': 3333,
'file_size': 4444
}
}
},
u'edx_video_id_2': {
u'duration: 2222,
u'profiles': {
u'mobile': {
'url': u'http: //www.example.com/roar',
'duration': 5555,
'file_size': 6666
},
u'desktop': {
'url': u'http: //www.example.com/bzzz',
'duration': 7777,
'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)
course_id = unicode(course_id)
try:
encoded_videos = EncodedVideo.objects.filter(
profile__profile_name=profile_name,
profile__profile_name__in=profiles,
video__courses__course_id=course_id
).select_related()
except Exception:
......@@ -342,36 +343,39 @@ def get_video_info_for_course_and_profile(course_id, profile_name):
raise ValInternalError(error_message)
# DRF serializers were causing extra queries for some reason...
return {
enc_vid.video.edx_video_id: {
"url": enc_vid.url,
"file_size": enc_vid.file_size,
return_dict = {}
for enc_vid in encoded_videos:
# Add duration to edx_video_id
return_dict.setdefault(enc_vid.video.edx_video_id, {}).update(
{
"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:
old_course_id: The original course_id
new_course_id: The new course_id of the rerun
source_course_id: The original course_id
destination_course_id: The new course_id where the videos will be copied
"""
if old_course_id == new_course_id:
raise ValueError(
"Both course_id's are the same: {}".format(new_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))
if source_course_id == destination_course_id:
return
videos = Video.objects.filter(courses__course_id=unicode(source_course_id))
for video in videos:
CourseVideo.objects.create(
CourseVideo.objects.get_or_create(
video=video,
course_id=new_course_id
course_id=destination_course_id
)
......@@ -330,40 +330,43 @@ class GetVideoForCourseProfiles(TestCase):
)
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
"""
video_dict = {video['edx_video_id']: {}}
for (profile, encoded_video) in zip(profiles, encoded_videos):
video_dict[video['edx_video_id']].update(
{
profile['profile_name']: {
'url': encoded_video['url'],
'file_size': encoded_video['file_size'],
'duration': video['duration']
return {
video['edx_video_id']: {
"duration": video['duration'],
'profiles': {
profile_name: {
"url": encoding["url"],
"file_size": encoding["file_size"],
}
for (profile_name, encoding) in encoding_dict.iteritems()
}
}
}
)
return video_dict
def test_get_video_for_course_profiles_success_one_profile(self):
"""
Tests get_video_info_for_course_and_profiles for one profile
"""
videos = api.get_video_info_for_course_and_profiles(
'test-course',
self.course_id,
['mobile']
)
expected_dict = {}
expected_dict.update(self._create_video_dict(
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(
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)
def test_get_video_for_course_profiles_success_two_profiles(self):
......@@ -376,19 +379,25 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {}
expected_dict.update(self._create_video_dict(
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(
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)
def test_get_video_for_course_profiles_no_profile(self):
"""Tests get_video_info_for_course_and_profiles with no such profile"""
videos = api.get_video_info_for_course_and_profiles(
'test-course',
['no profile'])
['no_profile'])
self.assertEqual(len(videos), 0)
videos = api.get_video_info_for_course_and_profiles(
......@@ -402,12 +411,16 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {}
expected_dict.update(self._create_video_dict(
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(
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)
def test_get_video_for_course_profiles_video_with_one_profile(self):
......@@ -420,8 +433,10 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {}
expected_dict.update(self._create_video_dict(
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)
videos = api.get_video_info_for_course_and_profiles(
......@@ -430,8 +445,10 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {}
expected_dict.update(self._create_video_dict(
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)
def test_get_video_for_course_profiles_repeated_profile(self):
......@@ -444,14 +461,19 @@ class GetVideoForCourseProfiles(TestCase):
expected_dict = {}
expected_dict.update(self._create_video_dict(
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(
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)
class GetVideosForIds(TestCase):
"""
Tests the get_videos_for_ids function in api.py
......@@ -620,76 +642,56 @@ class GetVideoInfoTestWithHttpCalls(APIAuthTestCase):
api.get_video_info(constants.VIDEO_DICT_ZEBRA.get("edx_video_id"))
class TestRerunCourse(TestCase):
"""Tests rerun course"""
class TestCopyCourse(TestCase):
"""Tests copy_course_videos in api.py"""
def setUp(self):
"""
Creates a course for testing
Creates two videos, each with two encodings.
Creates a course with 2 videos and a course with 1 video
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
self.course_id = 'test-course'
# 1st video
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)
# 2nd video
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)
def _check_video_course_list(self, video, expected_course_list):
"""
Verifies that given Video has the courses in the course list
"""
courses = VideoSerializer(video).data['courses']
self.assertEqual(sorted(courses), sorted(expected_course_list))
self.course_id2 = "test-course2"
# 3rd video different course
video = Video.objects.create(**constants.VIDEO_DICT_TREE)
CourseVideo.objects.create(video=video, course_id=self.course_id2)
def test_successful_rerun(self):
"""Tests a successful rerun and 2nd rerun"""
api.copy_course_videos('test-course', 'meow-rerun')
videos = Video.objects.all()
for video in videos:
self._check_video_course_list(video,
['test-course',
'meow-rerun'])
def test_successful_copy(self):
"""Tests a successful copy course"""
api.copy_course_videos('test-course', 'course-copy1')
original_videos = Video.objects.filter(courses__course_id='test-course')
copied_videos = Video.objects.filter(courses__course_id='course-copy1')
other_course = Video.objects.filter(courses__course_id='test-course2')
api.copy_course_videos('meow-rerun', 'woof-bark')
videos = Video.objects.all()
for video in videos:
self._check_video_course_list(video,
['test-course',
'meow-rerun',
'woof-bark'])
self.assertEqual(len(original_videos), 2)
self.assertEqual(
{original_video.edx_video_id for original_video in original_videos},
{constants.VIDEO_DICT_FISH["edx_video_id"], constants.VIDEO_DICT_STAR["edx_video_id"]}
)
self.assertTrue(set(original_videos) == set(copied_videos))
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
"""
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