Commit 19e0e23f by christopher lee

Organized and added tests. Removed colon

-Organized tests for consistency and to increase coverage.
 Added more tests for get_video_for_ids, get_url_for_profile(s),
 and having a colon in edx_video_id.
-Deleted unused test_models.py
-Updated outdated readme note
-Added missing documentation for some functions
-Removed colon
parent 28993bd5
edx-val
=======
Note:
The naming convention for the `profile_name` in `Profile` objects will be the
medium of the profile (a-z), an underscore, and then the quality (a-z).
Examples:
desktop_high
mobile_medium
somethingelse_low
......@@ -22,7 +22,7 @@ class CourseVideoInline(admin.TabularInline): # pylint: disable=C0111
class VideoAdmin(admin.ModelAdmin): # pylint: disable=C0111
list_display = (
'id', 'edx_video_id', 'client_video_id', 'duration'
'id', 'edx_video_id', 'client_video_id', 'duration', 'created', 'status'
)
list_display_links = ('id', 'edx_video_id')
search_fields = ('id', 'edx_video_id', 'client_video_id')
......
......@@ -51,6 +51,7 @@ class ValCannotCreateError(ValError):
"""
pass
def create_video(video_data):
"""
Called on to create Video objects in the database
......@@ -85,6 +86,7 @@ def create_video(video_data):
else:
raise ValCannotCreateError(serializer.errors)
def create_profile(profile_data):
"""
Used to create Profile objects in the database
......@@ -182,10 +184,19 @@ def get_video_info(edx_video_id, location=None): # pylint: disable=W0613
raise ValInternalError(error_message)
return result.data # pylint: disable=E1101
def get_urls_for_profiles(edx_video_id, profiles):
"""Returns a dict mapping profiles to URLs.
"""
Returns a dict mapping profiles to URLs.
If the profiles or video is not found, urls will be blank.
Args:
edx_video_id (str): id of the video
profiles (list): list of profiles we want to search for
Returns:
profiles_to_urls (dict): A dict containing the profile to url pair
"""
profiles_to_urls = {profile: None for profile in profiles}
try:
......@@ -199,11 +210,23 @@ def get_urls_for_profiles(edx_video_id, profiles):
return profiles_to_urls
def get_url_for_profile(edx_video_id, profile):
"""
Uses get_urls_for_profile to obtain a single profile
Args:
edx_video_id (str): id of the video
profile (str): a string of the profile we are searching
Returns:
A dict containing the profile to url. The return type is the same as
get_urls_for_profiles for consistency.
"""
return get_urls_for_profiles(edx_video_id, [profile])[profile]
url = get_urls_for_profiles(edx_video_id, [profile])[profile]
return {profile: url}
def get_videos_for_course(course_id):
"""
......@@ -212,15 +235,24 @@ def get_videos_for_course(course_id):
videos = Video.objects.filter(courses__course_id=unicode(course_id))
return (VideoSerializer(video).data for video in videos)
def get_videos_for_ids(edx_video_ids):
"""
Returns an iterator of videos that match the given list of ids
Args:
edx_video_ids (list)
Returns:
A generator expression that contains the videos found
"""
videos = Video.objects.filter(edx_video_id__in=edx_video_ids)
return (VideoSerializer(video).data for video in videos)
def get_video_info_for_course_and_profile(course_id, profile_name):
"""Returns a dict mapping profiles to URLs.
"""
Returns a dict mapping profiles to URLs.
If the profiles or video is not found, urls will be blank.
"""
......
"""
Django models for videos for Video Abstraction Layer (VAL)
When calling a serializers' .errors function for objects, there is an
order in which the errors are returned. This may cause a partial return of errors
When calling a serializers' .errors field, there is a priority in which the
errors are returned. This may cause a partial return of errors, starting with
the highest priority.
Example:
class Profile(models.Model)
......@@ -32,7 +33,7 @@ from django.core.validators import MinValueValidator, RegexValidator
from django.core.urlresolvers import reverse
URL_REGEX = r'^[a-zA-Z0-9\-_\:]*$'
URL_REGEX = r'^[a-zA-Z0-9\-_]*$'
class Profile(models.Model):
......@@ -67,6 +68,10 @@ class Video(models.Model):
A video can have multiple formats. This model are the fields that represent
the collection of those videos that do not change across formats.
Attributes:
status: Used to keep track of the processing video as it goes through
the video pipeline, e.g., "Uploading", "File Complete"...
"""
created = models.DateTimeField(auto_now_add=True)
edx_video_id = models.CharField(
......@@ -109,8 +114,8 @@ class CourseVideo(models.Model):
"""
Model for the course_id associated with the video content.
Every course-semester has a unique course_id. A video can be paired with multiple
course_id's but each pair is unique together.
Every course-semester has a unique course_id. A video can be paired with
multiple course_id's but each pair is unique together.
"""
course_id = models.CharField(max_length=255)
video = models.ForeignKey(Video, related_name='courses')
......@@ -148,6 +153,10 @@ SUBTITLE_FORMATS = (
class Subtitle(models.Model):
"""
Subtitle for video
Attributes:
video: the video that the subtitles are for
fmt: the format of the subttitles file
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
......
......@@ -30,4 +30,4 @@ class APIAuthTestCase(APITestCase):
username = password = 'unauthorized'
else:
username, password = self.username, self.password
print self.client.login(username=username, password=password)
self.client.login(username=username, password=password)
......@@ -161,17 +161,6 @@ class GetVideoInfoTest(TestCase):
videos = list(api.get_videos_for_course('unknown'))
self.assertEqual(len(videos), 0)
def test_get_videos_for_ids(self):
"""
Tests retrieving videos for ids
"""
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
videos = list(api.get_videos_for_ids([edx_video_id]))
self.assertEqual(len(videos), 1)
self.assertEqual(videos[0]['edx_video_id'], edx_video_id)
videos = list(api.get_videos_for_ids(['unknown']))
self.assertEqual(len(videos), 0)
def test_no_such_video(self):
"""
Tests searching for a video that does not exist
......@@ -212,6 +201,141 @@ class GetVideoInfoTest(TestCase):
)
class GetUrlsForProfileTest(TestCase):
"""
Tests the get_urls_for_profile(s) function in api.py
"""
def setUp(self):
"""
Creates EncodedVideo objects in database
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
video = Video.objects.create(**constants.VIDEO_DICT_FISH)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_FISH.get("edx_video_id")
),
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE
)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_FISH.get("edx_video_id")
),
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)
def test_get_urls_for_profiles(self):
"""
Tests when the profiles to the video are found
"""
profiles = ["mobile", "desktop"]
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
urls = api.get_urls_for_profiles(edx_video_id, profiles)
self.assertEqual(len(urls), 2)
self.assertEqual(urls["mobile"], u'http://www.meowmix.com')
self.assertEqual(urls["desktop"], u'http://www.meowmagic.com')
def test_get_urls_for_profiles_no_video(self):
"""
Tests when there is no video found.
"""
urls = api.get_urls_for_profiles("not found", ["mobile"])
self.assertEqual(urls["mobile"], None)
def test_get_urls_for_profiles_no_profiles(self):
"""
Tests when the video is found, but not hte profiles.
"""
profiles = ["not", "found"]
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
urls = api.get_urls_for_profiles(edx_video_id, profiles)
self.assertEqual(len(urls), 2)
self.assertEqual(urls["not"], None)
self.assertEqual(urls["found"], None)
def test_get_url_for_profile(self):
"""
Tests get_url_for_profile
"""
profile = "mobile"
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
urls = api.get_url_for_profile(edx_video_id, profile)
self.assertEqual(len(urls), 1)
self.assertEqual(urls["mobile"], u'http://www.meowmix.com')
class GetVideosForIds(TestCase):
"""
Tests the get_videos_for_ids function in api.py
"""
def setUp(self):
"""
Creates EncodedVideo objects in database
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
video = Video.objects.create(**constants.VIDEO_DICT_FISH)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_FISH.get("edx_video_id")
),
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE
)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_FISH.get("edx_video_id")
),
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)
def test_get_videos_for_id(self):
"""
Tests retrieving videos for id
"""
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
videos = list(api.get_videos_for_ids([edx_video_id]))
self.assertEqual(len(videos), 1)
self.assertEqual(videos[0]['edx_video_id'], edx_video_id)
videos = list(api.get_videos_for_ids(['unknown']))
self.assertEqual(len(videos), 0)
def test_get_videos_for_ids(self):
"""
Tests retrieving videos for ids
"""
Video.objects.create(**constants.VIDEO_DICT_DIFFERENT_ID_FISH)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_DIFFERENT_ID_FISH.get("edx_video_id")
),
profile=Profile.objects.get(profile_name="mobile"),
**constants.ENCODED_VIDEO_DICT_MOBILE
)
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
edx_video_id_2 = constants.VIDEO_DICT_DIFFERENT_ID_FISH['edx_video_id']
videos = list(api.get_videos_for_ids([edx_video_id, edx_video_id_2]))
self.assertEqual(len(videos), 2)
def test_get_videos_for_ids_duplicates(self):
"""
Tests retrieving videos for ids when there are duplicate ids
"""
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
videos = list(api.get_videos_for_ids([edx_video_id, edx_video_id]))
self.assertEqual(len(videos), 1)
class GetVideoInfoTestWithHttpCalls(APIAuthTestCase):
"""
Tests for the get_info_video, using the HTTP requests to populate database
......
"""
Tests for Video Abstraction Layer models
"""
......@@ -72,7 +72,8 @@ class SerializerTests(TestCase):
message = error.get("edx_video_id")[0]
self.assertEqual(
message,
u"edx_video_id has invalid characters")
u"edx_video_id has invalid characters"
)
def test_encoded_video_set_output(self):
"""
......
......@@ -14,17 +14,17 @@ urlpatterns = patterns(
name="video-list"
),
url(
r'^videos/(?P<edx_video_id>[-\:\w]+)$',
r'^videos/(?P<edx_video_id>[-\w]+)$',
views.VideoDetail.as_view(),
name="video-detail"
),
url(
r'^videos/(?P<video__edx_video_id>[-\:\w]+)/(?P<language>[-_\w]+)$',
r'^videos/(?P<video__edx_video_id>[-\w]+)/(?P<language>[-_\w]+)$',
views.SubtitleDetail.as_view(),
name="subtitle-detail"
),
url(
r'^videos/(?P<edx_video_id>[-\:\w]+)/(?P<language>[-_\w]+)/subtitle$',
r'^videos/(?P<edx_video_id>[-\w]+)/(?P<language>[-_\w]+)/subtitle$',
views.get_subtitle,
name="subtitle-content"
),
......
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