Commit 595d4f28 by christopher lee

implemented correct identities for PUT

Assigned profile_name to be the identifier for EncodedVideos.
Tests for PUT have been added to check for expected behavior.
Attempting to PUT multiple EncodedVideos with the same profile
will return an error.

Other notes:
-url now accepts dashes
-reduced number of unique constants
-updated api.py tests with HTTP requests
-removed unused repr
parent e793792a
......@@ -13,26 +13,18 @@ class Profile(models.Model):
profile_name = models.CharField(
max_length=50,
unique=True,
)
)
extension = models.CharField(max_length=10)
width = models.PositiveIntegerField()
height = models.PositiveIntegerField()
def __repr__(self):
return (
u"Profile(profile_name={0.profile_name})"
).format(self)
def __unicode__(self):
return repr(self)
class Video(models.Model):
"""
Model for a Video group with the same content.
A video can have multiple formats. This model is the collection of those
videos with fields that do not change across formats.
A video can have multiple formats. This model are the fields that represent
the collection of those videos that do not change across formats.
"""
edx_video_id = models.CharField(
max_length=50,
......@@ -48,14 +40,6 @@ class Video(models.Model):
client_video_id = models.CharField(max_length=255, db_index=True)
duration = models.FloatField(validators=[MinValueValidator(0)])
def __repr__(self):
return (
u"Video(client_video_id={0.client_video_id}, duration={0.duration})"
).format(self)
def __unicode__(self):
return repr(self)
class CourseVideos(models.Model):
"""
......@@ -83,12 +67,3 @@ class EncodedVideo(models.Model):
profile = models.ForeignKey(Profile, related_name="+")
video = models.ForeignKey(Video, related_name="encoded_videos")
def __repr__(self):
return (
u"EncodedVideo(video={0.video.client_video_id}, "
u"profile={0.profile.profile_name})"
).format(self)
def __unicode__(self):
return repr(self)
......@@ -2,6 +2,7 @@
Serializers for Video Abstraction Layer
"""
from rest_framework import serializers
from django.core.exceptions import ValidationError
from edxval.models import Profile, Video, EncodedVideo
......@@ -31,10 +32,44 @@ class EncodedVideoSerializer(serializers.ModelSerializer):
"profile",
)
def get_identity(self, data):
"""
This hook is required for bulk update.
We need to override the default, to use the slug as the identity.
"""
return data.get('profile', None)
class VideoSerializer(serializers.HyperlinkedModelSerializer):
encoded_videos = EncodedVideoSerializer(many=True, allow_add_remove=True)
encoded_videos = EncodedVideoSerializer(
many=True,
allow_add_remove=True
)
class Meta:
model = Video
lookup_field = "edx_video_id"
def restore_fields(self, data, files):
"""
Converts a dictionary of data into a dictionary of deserialized fields. Also
checks if there are duplicate profile_name(s). If there is, the deserialization
is rejected.
"""
reverted_data = {}
if data is not None and not isinstance(data, dict):
self._errors['non_field_errors'] = ['Invalid data']
return None
profiles = [ev["profile"] for ev in data.get("encoded_videos", [])]
if len(profiles) != len(set(profiles)):
self._errors['non_field_errors'] = ['Invalid data: duplicate profiles']
for field_name, field in self.fields.items():
field.initialize(parent=self, field_name=field_name)
try:
field.field_from_native(data, files, field_name, reverted_data)
except ValidationError as err:
self._errors[field_name] = list(err.messages)
return reverted_data
......@@ -23,7 +23,6 @@ ENCODED_VIDEO_DICT_MOBILE = dict(
file_size=4545,
bitrate=6767,
)
ENCODED_VIDEO_DICT_DESKTOP = dict(
url="http://www.meowmagic.com",
file_size=1212,
......@@ -38,28 +37,27 @@ VIDEO_DICT_NEGATIVE_DURATION = dict(
edx_video_id="thisis12char-thisis7",
encoded_videos=[]
)
ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE = dict(
url="http://www.meowmix.com",
file_size=-25556,
bitrate=9600,
)
ENCODED_VIDEO_DICT_NEGATIVE_BITRATE = dict(
url="http://www.meowmix.com",
file_size=25556,
bitrate=-9600,
)
VIDEO_DICT_BEE_INVALID = dict(
client_video_id="Barking Bee",
duration=111.00,
edx_video_id="wa/sps",
)
VIDEO_DICT_INVALID_ID = dict(
client_video_id="SuperSloth",
duration=42,
edx_video_id="sloppy/sloth!!",
encoded_videos=[]
)
ENCODED_VIDEO_DICT_NEGATIVE_FILESIZE = dict(
url="http://www.meowmix.com",
file_size=-25556,
bitrate=9600,
)
ENCODED_VIDEO_DICT_NEGATIVE_BITRATE = dict(
url="http://www.meowmix.com",
file_size=25556,
bitrate=-9600,
)
"""
Non-latin/invalid
"""
......@@ -87,30 +85,43 @@ Fish
VIDEO_DICT_FISH = dict(
client_video_id="Shallow Swordfish",
duration=122.00,
edx_video_id="supersoaker"
edx_video_id="super-soaker"
)
VIDEO_DICT_DIFFERENT_ID_FISH = dict(
client_video_id="Shallow Swordfish",
duration=122.00,
edx_video_id="medium-soaker"
)
ENCODED_VIDEO_DICT_FISH_MOBILE = dict(
url="https://www.swordsingers.com",
file_size=9000,
bitrate=42,
profile="mobile",
)
ENCODED_VIDEO_DICT_FISH_DESKTOP = dict(
url="https://www.swordsplints.com",
file_size=1234,
bitrate=4222,
profile="desktop",
)
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE = dict(
url="https://www.fishfellow.com",
file_size=1,
bitrate=1,
profile="mobile",
)
ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP = dict(
url="https://www.furryfish.com",
file_size=2,
bitrate=2,
profile="desktop",
)
ENCODED_VIDEO_DICT_FISH_INVALID_PROFILE = dict(
url="https://www.swordsplints.com",
file_size=1234,
bitrate=4222,
profile=11,
profile="bird"
)
COMPLETE_SET_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
......@@ -118,7 +129,40 @@ COMPLETE_SET_FISH = dict(
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_TWO_MOBILE_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_MOBILE
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_UPDATE_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE,
ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_DIFFERENT_ID_UPDATE_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE,
ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP
],
**VIDEO_DICT_DIFFERENT_ID_FISH
)
COMPLETE_SET_FIRST_HALF_UPDATE_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_DESKTOP
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_UPDATE_ONLY_DESKTOP_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_INVALID_ENCODED_VIDEO_FISH = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE,
......@@ -126,7 +170,6 @@ COMPLETE_SET_INVALID_ENCODED_VIDEO_FISH = dict(
],
**VIDEO_DICT_FISH
)
COMPLETE_SET_INVALID_VIDEO_FISH = dict(
client_video_id="Shallow Swordfish",
duration=122.00,
......@@ -141,8 +184,6 @@ COMPLETE_SETS_ALL_INVALID = [
COMPLETE_SET_INVALID_VIDEO_FISH,
COMPLETE_SET_INVALID_VIDEO_FISH
]
"""
Star
"""
......@@ -157,14 +198,24 @@ ENCODED_VIDEO_DICT_STAR = dict(
bitrate=42,
profile="mobile"
)
ENCODED_VIDEO_UPDATE_DICT_STAR = dict(
url="https://www.whatyouare.com",
file_size=9000,
bitrate=42,
profile="mobile"
)
COMPLETE_SET_STAR = dict(
encoded_videos=[
ENCODED_VIDEO_DICT_STAR
],
**VIDEO_DICT_STAR
)
COMPLETE_SET_UPDATE_STAR = dict(
encoded_videos=[
ENCODED_VIDEO_UPDATE_DICT_STAR
],
**VIDEO_DICT_STAR
)
COMPLETE_SET_NOT_A_LIST = dict(
encoded_videos=dict(
url="https://www.howIwonder.com",
......@@ -174,7 +225,6 @@ COMPLETE_SET_NOT_A_LIST = dict(
),
**VIDEO_DICT_STAR
)
COMPLETE_SET_EXTRA_VIDEO_FIELD = dict(
encoded_videos=[
dict(
......@@ -188,12 +238,13 @@ COMPLETE_SET_EXTRA_VIDEO_FIELD = dict(
**VIDEO_DICT_STAR
)
"""
Unsorted
Other
"""
VIDEO_DICT_COAT = dict(
client_video_id="Callous Coat",
VIDEO_DICT_ZEBRA = dict(
client_video_id="Zesty Zebra",
duration=111.00,
edx_video_id="itchyjacket"
edx_video_id="zestttt",
encoded_videos=[]
)
VIDEO_DICT_ANIMAL = dict(
client_video_id="Average Animal",
......@@ -201,48 +252,9 @@ VIDEO_DICT_ANIMAL = dict(
edx_video_id="mediocrity",
encoded_videos=[]
)
VIDEO_DICT_ZEBRA = dict(
client_video_id="Zesty Zebra",
duration=111.00,
edx_video_id="zestttt",
encoded_videos=[]
)
VIDEO_DICT_UPDATE_ANIMAL = dict(
client_video_id="Lolcat",
duration=122.00,
client_video_id="Above Average Animal",
duration=999.00,
edx_video_id="mediocrity",
encoded_videos=[]
)
VIDEO_DICT_CRAYFISH = dict(
client_video_id="Crazy Crayfish",
duration=111.00,
edx_video_id="craycray",
)
VIDEO_DICT_DUPLICATES = [
VIDEO_DICT_CRAYFISH,
VIDEO_DICT_CRAYFISH,
VIDEO_DICT_CRAYFISH
]
COMPLETE_SETS = [
COMPLETE_SET_STAR,
COMPLETE_SET_FISH
]
COMPLETE_SETS_ONE_INVALID = [
COMPLETE_SET_STAR,
COMPLETE_SET_INVALID_VIDEO_FISH
]
VIDEO_DICT_SET_OF_THREE = [
VIDEO_DICT_COAT,
VIDEO_DICT_ANIMAL,
VIDEO_DICT_CRAYFISH
]
VIDEO_DICT_INVALID_SET = [
VIDEO_DICT_COAT,
VIDEO_DICT_INVALID_ID,
VIDEO_DICT_BEE_INVALID
]
......@@ -7,6 +7,9 @@ import mock
from django.test import TestCase
from django.db import DatabaseError
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from edxval.models import Profile, Video, EncodedVideo
from edxval import api as api
......@@ -16,26 +19,23 @@ from edxval.tests import constants
class GetVideoInfoTest(TestCase):
#TODO When upload portion is finished, do not forget to create tests for validating
#TODO regex for models. Currently, objects are created manually and validators
#TODO are not triggered.
def setUp(self):
"""
Creates EncodedVideo objects in database
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
Video.objects.create(**constants.VIDEO_DICT_COAT)
Video.objects.create(**constants.VIDEO_DICT_FISH)
EncodedVideo.objects.create(
video=Video.objects.get(
edx_video_id=constants.VIDEO_DICT_COAT.get("edx_video_id")
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_COAT.get("edx_video_id")
edx_video_id=constants.VIDEO_DICT_FISH.get("edx_video_id")
),
profile=Profile.objects.get(profile_name="desktop"),
**constants.ENCODED_VIDEO_DICT_DESKTOP
......@@ -45,7 +45,9 @@ class GetVideoInfoTest(TestCase):
"""
Tests for successful video request
"""
self.assertIsNotNone(api.get_video_info(constants.EDX_VIDEO_ID))
self.assertIsNotNone(api.get_video_info(
constants.VIDEO_DICT_FISH.get("edx_video_id"))
)
def test_no_such_video(self):
"""
......@@ -71,7 +73,9 @@ class GetVideoInfoTest(TestCase):
"""
mock_init.side_effect = Exception("Mock error")
with self.assertRaises(api.ValInternalError):
api.get_video_info(constants.EDX_VIDEO_ID)
api.get_video_info(
constants.VIDEO_DICT_FISH.get("edx_video_id")
)
@mock.patch.object(Video.objects, 'get')
def test_force_database_error(self, mock_get):
......@@ -80,4 +84,66 @@ class GetVideoInfoTest(TestCase):
"""
mock_get.side_effect = DatabaseError("DatabaseError")
with self.assertRaises(api.ValInternalError):
api.get_video_info(constants.EDX_VIDEO_ID)
api.get_video_info(
constants.VIDEO_DICT_FISH.get("edx_video_id")
)
class GetVideoInfoTestWithHttpCalls(APITestCase):
def setUp(self):
"""
Creates EncodedVideo objects in database with HTTP requests.
The tests are similar to the GetVideoInfoTest class. This class
is to tests that we have the same results, using a populated
database via HTTP uploads.
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
url = reverse('video-list')
response = self.client.post(
url, constants.COMPLETE_SET_FISH, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_get_video_found(self):
"""
Tests for successful video request
"""
self.assertIsNotNone(
api.get_video_info(
constants.COMPLETE_SET_FISH.get("edx_video_id")
)
)
def test_get_info_queries_for_two_encoded_video(self):
"""
Tests number of queries for a Video/EncodedVideo(1) pair
"""
with self.assertNumQueries(4):
api.get_video_info(constants.COMPLETE_SET_FISH.get("edx_video_id"))
def test_get_info_queries_for_one_encoded_video(self):
"""
Tests number of queries for a Video/EncodedVideo(1) pair
"""
url = reverse('video-list')
response = self.client.post(
url, constants.COMPLETE_SET_STAR, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(3):
api.get_video_info(constants.COMPLETE_SET_STAR.get("edx_video_id"))
def test_get_info_queries_for_only_video(self):
"""
Tests number of queries for a Video with no Encoded Videopair
"""
url = reverse('video-list')
response = self.client.post(
url, constants.VIDEO_DICT_ZEBRA, format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(2):
api.get_video_info(constants.VIDEO_DICT_ZEBRA.get("edx_video_id"))
......@@ -63,13 +63,6 @@ class SerializerTests(TestCase):
ProfileSerializer
)
def test_non_latin_deserialization(self):
"""
Tests deserialization of non-latin data
"""
#TODO write a test for this when we understand what we want
pass
def test_invalid_edx_video_id(self):
"""
Test the Video model regex validation for edx_video_id field
......@@ -84,7 +77,7 @@ class SerializerTests(TestCase):
"""
Tests for basic structure of EncodedVideoSetSerializer
"""
video = Video.objects.create(**constants.VIDEO_DICT_COAT)
video = Video.objects.create(**constants.VIDEO_DICT_FISH)
EncodedVideo.objects.create(
video=video,
profile=Profile.objects.get(profile_name="desktop"),
......@@ -99,4 +92,4 @@ class SerializerTests(TestCase):
# Check for 2 EncodedVideo entries
self.assertEqual(len(result.get("encoded_videos")), 2)
# Check for original Video data
self.assertDictContainsSubset(constants.VIDEO_DICT_COAT, result)
self.assertDictContainsSubset(constants.VIDEO_DICT_FISH, result)
......@@ -3,7 +3,293 @@ from rest_framework import status
from rest_framework.test import APITestCase
from edxval.tests import constants
from edxval.models import Profile
from edxval.models import Profile, Video
class VideoDetail(APITestCase):
"""
Tests Retrieve, Update and Destroy requests
"""
def setUp(self):
"""
Used for manually creating profile objects which EncodedVideos require.
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
"""
Tests for successful PUT requests.
These tests should be returning HTTP_200_OK responses.
"""
def test_update_video(self):
"""
Tests PUTting a single video with no encoded videos.
"""
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.VIDEO_DICT_ANIMAL.get("edx_video_id")}
)
response = self.client.put(
url,
constants.VIDEO_DICT_UPDATE_ANIMAL,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertNotEqual(
videos[0].duration,
constants.VIDEO_DICT_ANIMAL.get("duration"))
self.assertEqual(
videos[0].duration,
constants.VIDEO_DICT_UPDATE_ANIMAL.get("duration")
)
def test_update_one_encoded_video(self):
"""
Tests PUTting one encoded video.
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_STAR.get("edx_video_id")}
)
response = self.client.put(
url,
constants.COMPLETE_SET_UPDATE_STAR,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 1)
new_url = videos[0].encoded_videos.all()[0].url
self.assertNotEqual(
constants.ENCODED_VIDEO_UPDATE_DICT_STAR,
constants.ENCODED_VIDEO_DICT_STAR.get("url"))
self.assertEqual(
new_url,
constants.ENCODED_VIDEO_UPDATE_DICT_STAR.get("url")
)
def test_update_two_encoded_videos(self):
"""
Tests PUTting two encoded videos and then PUT back.
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_FISH.get("edx_video_id")}
)
response = self.client.patch(
path=url,
data=constants.COMPLETE_SET_UPDATE_FISH,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 2)
first_url = videos[0].encoded_videos.all()[0].url
self.assertNotEqual(
constants.ENCODED_VIDEO_DICT_FISH_MOBILE,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE.get("url"))
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertNotEqual(
constants.ENCODED_VIDEO_DICT_FISH_DESKTOP,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP.get("url"))
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP.get("url")
)
response = self.client.put(
path=url,
data=constants.COMPLETE_SET_FISH,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
first_url = videos[0].encoded_videos.all()[0].url
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_FISH_DESKTOP.get("url")
)
def test_update_one_of_two_encoded_videos(self):
"""
Tests PUTting one of two EncodedVideo(s) and then a single EncodedVideo PUT back.
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_FISH.get("edx_video_id")}
)
response = self.client.put(
path=url,
data=constants.COMPLETE_SET_FIRST_HALF_UPDATE_FISH,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 2)
first_url = videos[0].encoded_videos.all()[0].url
self.assertNotEqual(
constants.ENCODED_VIDEO_DICT_FISH_MOBILE,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE.get("url"))
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_FISH_DESKTOP.get("url")
)
response = self.client.put(
path=url,
data=constants.COMPLETE_SET_UPDATE_ONLY_DESKTOP_FISH,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
first_url = videos[0].encoded_videos.all()[0].url
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP.get("url")
)
self.assertEqual(len(videos[0].encoded_videos.all()), 1)
def test_update_invalid_video(self):
"""
Tests PUTting a video with different edx_video_id.
The new edx_video_id is ignored in the VideoDetail view.
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_FISH.get("edx_video_id")}
)
response = self.client.put(
url,
constants.COMPLETE_SET_DIFFERENT_ID_UPDATE_FISH,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 2)
first_url = videos[0].encoded_videos.all()[0].url
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP.get("url")
)
"""
Tests for bad PUT requests.
These tests should be returning HTTP_400_BAD_REQUEST responses.
"""
def test_update_an_invalid_encoded_videos(self):
"""
Tests PUTting one of two invalid EncodedVideo(s)
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_FISH.get("edx_video_id")}
)
response = self.client.put(
path=url,
data=constants.COMPLETE_SET_INVALID_ENCODED_VIDEO_FISH,
format='json'
)
self.assertEqual(
response.data.get("encoded_videos")[1].get("profile")[0],
"Object with profile_name=bird does not exist."
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 2)
first_url = videos[0].encoded_videos.all()[0].url
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_FISH_DESKTOP.get("url")
)
def test_update_duplicate_encoded_video_profiles(self):
"""
Tests PUTting duplicate EncodedVideos for a Video
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse(
'video-detail',
kwargs={"edx_video_id": constants.COMPLETE_SET_FISH.get("edx_video_id")}
)
response = self.client.put(
path=url,
data=constants.COMPLETE_SET_TWO_MOBILE_FISH,
format='json'
)
self.assertEqual(
response.data.get("non_field_errors")[0],
"Invalid data: duplicate profiles"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
videos = Video.objects.all()
self.assertEqual(len(videos), 1)
self.assertEqual(len(videos[0].encoded_videos.all()), 2)
first_url = videos[0].encoded_videos.all()[0].url
self.assertEqual(
first_url,
constants.ENCODED_VIDEO_DICT_FISH_MOBILE.get("url")
)
second_url = videos[0].encoded_videos.all()[1].url
self.assertEqual(
second_url,
constants.ENCODED_VIDEO_DICT_FISH_DESKTOP.get("url")
)
class VideoListTest(APITestCase):
......@@ -71,6 +357,20 @@ class VideoListTest(APITestCase):
response = self.client.post(url, constants.VIDEO_DICT_NON_LATIN_TITLE, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_post_video_with_duplicate_encoded_videos(self):
"""
Tests POSTing a single video with duplicate EncodedVideos
"""
url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_TWO_MOBILE_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
video = self.client.get("/edxval/video/").data
self.assertEqual(len(video), 0)
self.assertEqual(
response.data.get("non_field_errors")[0],
"Invalid data: duplicate profiles"
)
"""
Tests for POSTing invalid data
......@@ -177,25 +477,11 @@ class VideoListTest(APITestCase):
url = reverse('video-list')
with self.assertNumQueries(7):
self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
"""
Tests for GET
"""
def test_get_all_videos(self):
"""
Tests getting all Video objects
"""
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.post(url, constants.VIDEO_DICT_ZEBRA, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
videos = self.client.get("/edxval/video/").data
self.assertEqual(len(videos), 2)
def test_queries_for_get(self):
'''
"""
Tests number of queries when GETting all videos
'''
"""
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
......@@ -211,4 +497,20 @@ class VideoListTest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(5):
self.client.get("/edxval/video/").data
"""
Tests for GET
"""
def test_get_all_videos(self):
"""
Tests getting all Video objects
"""
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.post(url, constants.VIDEO_DICT_ZEBRA, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
videos = self.client.get("/edxval/video/").data
self.assertEqual(len(videos), 2)
......@@ -9,7 +9,7 @@ admin.autodiscover()
urlpatterns = patterns('',
url(r'^edxval/video/$', views.VideoList.as_view(),
name="video-list"),
url(r'^edxval/video/(?P<edx_video_id>\w+)',
url(r'^edxval/video/(?P<edx_video_id>[-\w]+)',
views.VideoDetail.as_view(),
name="video-detail"),
url(r'^admin/', include(admin.site.urls)),
......
from rest_framework import generics
from edxval.models import Video
from edxval.models import Video, Profile
from edxval.serializers import (
VideoSerializer
VideoSerializer,
ProfileSerializer
)
......@@ -14,6 +15,14 @@ class VideoList(generics.ListCreateAPIView):
lookup_field = "edx_video_id"
serializer_class = VideoSerializer
class ProfileList(generics.ListCreateAPIView):
"""
GETs or POST video objects
"""
queryset = Profile.objects.all()
lookup_field = "profile_name"
serializer_class = ProfileSerializer
class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
"""
......
from django.conf.urls import patterns, include, url
from rest_framework.urlpatterns import format_suffix_patterns
from edxval import views
......
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