Commit bbe3c6d1 by Qubad786 Committed by muzaffaryousaf

Heal fixes: To avoid transcript status override in VAL

- Fix - HEAL overwrite transcript statuses for completed videos in VAL.
- Add source_language and transcript_status to VideoSerializer and Admin.
- Add tests coverage for Model Serializers.
parent acae00b4
...@@ -34,8 +34,10 @@ class VideoAdmin(admin.ModelAdmin): ...@@ -34,8 +34,10 @@ class VideoAdmin(admin.ModelAdmin):
'studio_id', 'studio_id',
'video_trans_start', 'video_trans_start',
'video_trans_status', 'video_trans_status',
'transcript_status',
'video_active', 'video_active',
'process_transcription', 'process_transcription',
'source_language',
'provider', 'provider',
'three_play_turnaround', 'three_play_turnaround',
'cielo24_turnaround', 'cielo24_turnaround',
......
...@@ -72,9 +72,11 @@ class VideoSerializer(serializers.ModelSerializer): ...@@ -72,9 +72,11 @@ class VideoSerializer(serializers.ModelSerializer):
'video_trans_start', 'video_trans_start',
'video_trans_end', 'video_trans_end',
'video_trans_status', 'video_trans_status',
'transcript_status',
'video_glacierid', 'video_glacierid',
'course_ids', 'course_ids',
'process_transcription', 'process_transcription',
'source_language',
'provider', 'provider',
'three_play_turnaround', 'three_play_turnaround',
'cielo24_turnaround', 'cielo24_turnaround',
...@@ -130,6 +132,10 @@ class VideoSerializer(serializers.ModelSerializer): ...@@ -130,6 +132,10 @@ class VideoSerializer(serializers.ModelSerializer):
'video_trans_status', 'video_trans_status',
instance.video_trans_status instance.video_trans_status
) )
instance.transcript_status = validated_data.get(
'transcript_status',
instance.transcript_status
)
instance.video_glacierid = validated_data.get( instance.video_glacierid = validated_data.get(
'video_glacierid', 'video_glacierid',
instance.video_glacierid instance.video_glacierid
...@@ -138,6 +144,10 @@ class VideoSerializer(serializers.ModelSerializer): ...@@ -138,6 +144,10 @@ class VideoSerializer(serializers.ModelSerializer):
'process_transcription', 'process_transcription',
instance.process_transcription instance.process_transcription
) )
instance.source_language = validated_data.get(
'source_language',
instance.source_language
)
instance.provider = validated_data.get( instance.provider = validated_data.get(
'provider', 'provider',
instance.provider instance.provider
......
from django.test import TestCase
from VEDA_OS01.models import Course, Destination, Encode, URL, Video
from VEDA_OS01.serializers import CourseSerializer, EncodeSerializer, URLSerializer, VideoSerializer
class TestCourseSerializer(TestCase):
"""
Tests for `CourseSerializer`.
"""
def setUp(self):
self.course_props = dict(
course_name=u'Intro to VEDA',
institution=u'MAx',
edx_classid=u'123',
semesterid=u'2017',
)
def test_create_course(self):
"""
Tests that `CourseSerializer.create` works as expected.
"""
course_serializer = CourseSerializer(data=self.course_props)
course_serializer.is_valid(raise_exception=True)
course_serializer.save()
# Now, get the created course record.
serialized_course = CourseSerializer(
instance=Course.objects.get(**self.course_props)
).data
self.assertDictEqual(serialized_course, course_serializer.data)
def test_update_course(self):
"""
Tests that `CourseSerializer.update` works as expected.
"""
course = Course.objects.create(**self.course_props)
# Perform the update via serializer.
updated_course_props = dict(self.course_props, course_name=u'Intro to edx-video-pipeline')
course_serializer = CourseSerializer(instance=course, data=updated_course_props, partial=True)
course_serializer.is_valid(raise_exception=True)
course_serializer.save()
# Now, see if its updated
serialized_course = CourseSerializer(
instance=Course.objects.first()
).data
self.assertDictEqual(serialized_course, course_serializer.data)
class TestVideoSerializer(TestCase):
"""
Tests for `VideoSerializer`.
"""
def setUp(self):
self.course = Course.objects.create(
course_name=u'Intro to VEDA',
institution=u'MAx',
edx_classid=u'123',
semesterid=u'2017',
local_storedir='course_id1, course_id2',
)
self.video_props = dict(
inst_class=self.course.pk,
client_title=u'Intro to video',
edx_id=u'12345678',
studio_id=u'43211234',
video_active=True,
process_transcription=True,
source_language=u'fr',
)
def test_create_video(self):
"""
Tests that `VideoSerializer.create` works as expected.
"""
video_serializer = VideoSerializer(data=self.video_props)
video_serializer.is_valid(raise_exception=True)
video_serializer.save()
# Now, get the created video record.
serialized_video = VideoSerializer(
instance=Video.objects.get(**self.video_props)
).data
self.assertDictEqual(serialized_video, video_serializer.data)
def test_update_video(self):
"""
Tests that `VideoSerializer.update` works as expected.
"""
video = Video.objects.create(**dict(self.video_props, inst_class=self.course))
# Perform the update via serializer.
updated_video_props = dict(self.video_props, client_title=u'Intro to new Video')
video_serializer = VideoSerializer(instance=video, data=updated_video_props, partial=True)
video_serializer.is_valid(raise_exception=True)
video_serializer.save()
# Now, see if its updated
serialized_video = VideoSerializer(
instance=Video.objects.first()
).data
self.assertDictEqual(serialized_video, video_serializer.data)
class TestURLSerializer(TestCase):
"""
Tests for `URLSerializer`.
"""
def setUp(self):
# Setup an encode
destination = Destination.objects.create(
destination_name='test_destination',
destination_nick='des',
destination_active=True
)
encode = Encode.objects.create(
encode_destination=destination,
encode_name='desktop_mp4',
profile_active=True,
)
# Setup a video
course = Course.objects.create(
course_name=u'Intro to VEDA',
institution=u'MAx',
edx_classid=u'123',
semesterid=u'2017',
local_storedir='course_id1, course_id2',
)
video = Video.objects.create(
inst_class=course,
client_title=u'Intro to video',
edx_id=u'12345678',
studio_id=u'43211234'
)
# Setup URL properties
self.url_props = dict(
encode_profile=encode.pk,
videoID=video.pk,
encode_url='https://www.s3.amazon.com/123.mp4'
)
def test_create_url(self):
"""
Tests that `URLSerializer.create` works as expected.
"""
url_serializer = URLSerializer(data=self.url_props)
url_serializer.is_valid(raise_exception=True)
url_serializer.save()
# Now, get the created URL record.
serialized_url = URLSerializer(
instance=URL.objects.first()
).data
self.assertDictEqual(serialized_url, url_serializer.data)
class TestEncodeSerializer(TestCase):
"""
Tests for `EncodeSerializer`.
"""
def test_serialized_encode(self):
"""
Tests that serializing/de-serializing 'Encode' works as expected.
"""
destination = Destination.objects.create(
destination_name='test_destination',
destination_nick='des',
destination_active=True
)
encode = Encode.objects.create(
encode_destination=destination,
encode_name='desktop_mp4',
profile_active=True,
)
self.assertEqual(Encode.objects.count(), 1)
actual_serialized_encode = EncodeSerializer(encode).data
for attr, actual_value in actual_serialized_encode.iteritems():
expected_value = getattr(encode, attr)
self.assertEqual(actual_value, expected_value)
...@@ -8,14 +8,13 @@ import sys ...@@ -8,14 +8,13 @@ import sys
from django.test import TestCase from django.test import TestCase
from datetime import timedelta from datetime import timedelta
from ddt import data, ddt, unpack from ddt import data, ddt, unpack
from unittest import skip
import responses import responses
from django.utils.timezone import utc from django.utils.timezone import utc
from mock import PropertyMock, patch from mock import PropertyMock, patch
from control.veda_heal import VedaHeal from control.veda_heal import VedaHeal
from VEDA_OS01.models import URL, Course, Destination, Encode, Video from VEDA_OS01.models import URL, Course, Destination, Encode, Video, TranscriptStatus
from VEDA_OS01.utils import build_url, get_config from VEDA_OS01.utils import build_url, get_config, ValTranscriptStatus
sys.path.append(os.path.dirname(os.path.dirname( sys.path.append(os.path.dirname(os.path.dirname(
os.path.abspath(__file__) os.path.abspath(__file__)
...@@ -169,50 +168,103 @@ class HealTests(TestCase): ...@@ -169,50 +168,103 @@ class HealTests(TestCase):
{ {
'uncompleted_encodes': [], 'uncompleted_encodes': [],
'expected_encodes': ['test_obj'], 'expected_encodes': ['test_obj'],
'video_object': { 'video_props': {
'edx_id': '1', 'edx_id': '1',
'video_trans_status': 'Complete', 'video_trans_status': 'Complete',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc), 'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True, 'video_active': True,
} },
'result': []
}, },
{ {
'uncompleted_encodes': ['test_obj'], 'uncompleted_encodes': ['test_obj'],
'expected_encodes': ['test_obj'], 'expected_encodes': ['test_obj'],
'video_object': { 'video_props': {
'edx_id': '2', 'edx_id': '2',
'video_trans_status': 'Ingest', 'video_trans_status': 'Ingest',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc), 'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True, 'video_active': True,
} },
'result': ['test_obj']
} }
) )
@unpack @unpack
def test_differentiate_encodes(self, uncompleted_encodes, expected_encodes, video_object): def test_differentiate_encodes(self, uncompleted_encodes, expected_encodes, video_props, result):
""" """
Tests that differentiate_encodes list comparison works as expected. This doesn't test video states, Tests that differentiate_encodes list comparison works as expected. This doesn't test video states,
just the list comparison function. just the list comparison function.
""" """
video_instance = Video( video_instance = Video.objects.create(inst_class=self.course_object, **video_props)
edx_id=video_object['edx_id'],
video_trans_status=video_object['video_trans_status'],
video_trans_start=video_object['video_trans_start'],
video_active=video_object['video_active'],
inst_class=self.course_object
)
video_instance.save()
encode_list = self.heal_instance.differentiate_encodes( encode_list = self.heal_instance.differentiate_encodes(
uncompleted_encodes, uncompleted_encodes,
expected_encodes, expected_encodes,
video_instance video_instance
) )
self.assertEqual(encode_list, result)
if video_instance.edx_id == '1': @data(
self.assertEqual(encode_list, []) {
elif video_instance.edx_id == '2': 'uncompleted_encodes': [],
self.assertEqual(encode_list, ['test_obj']) 'expected_encodes': ['test_obj'],
'video_props': {
'edx_id': '1',
'video_trans_status': 'Complete',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True,
'transcript_status': TranscriptStatus.PENDING
},
'expected_val_status': 'file_complete'
},
{
'uncompleted_encodes': [],
'expected_encodes': ['test_obj'],
'video_props': {
'edx_id': '1',
'video_trans_status': 'Complete',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True,
'transcript_status': TranscriptStatus.IN_PROGRESS
},
'expected_val_status': ValTranscriptStatus.TRANSCRIPTION_IN_PROGRESS
},
{
'uncompleted_encodes': [],
'expected_encodes': ['test_obj'],
'video_props': {
'edx_id': '1',
'video_trans_status': 'Complete',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True,
'transcript_status': TranscriptStatus.READY
},
'expected_val_status': ValTranscriptStatus.TRANSCRIPT_READY
},
{
'uncompleted_encodes': ['test_obj'],
'expected_encodes': ['test_obj'],
'video_props': {
'edx_id': '2',
'video_trans_status': 'Ingest',
'video_trans_start': datetime.datetime.utcnow().replace(tzinfo=utc),
'video_active': True,
'transcript_status': TranscriptStatus.READY
},
'expected_val_status': 'transcode_queue'
}
)
@unpack
def test_differentiate_encodes_val_status(self, uncompleted_encodes,
expected_encodes, video_props, expected_val_status):
"""
Tests that the val status changes as expected based on encode list.
"""
video_instance = Video.objects.create(inst_class=self.course_object, **video_props)
self.heal_instance.differentiate_encodes(
uncompleted_encodes,
expected_encodes,
video_instance
)
self.assertEqual(self.heal_instance.val_status, expected_val_status)
@data( @data(
{ {
......
...@@ -8,14 +8,19 @@ Roll through videos, check for completion ...@@ -8,14 +8,19 @@ Roll through videos, check for completion
""" """
import datetime import datetime
import uuid
from datetime import timedelta from datetime import timedelta
import os
import sys
import uuid
import yaml import yaml
from django.utils.timezone import utc from django.utils.timezone import utc
from VEDA_OS01.models import Encode, URL, Video
from VEDA_OS01.utils import VAL_TRANSCRIPT_STATUS_MAP
import celeryapp import celeryapp
from control_env import * from control_env import WORK_DIRECTORY
from veda_encode import VedaEncode from veda_encode import VedaEncode
from veda_val import VALAPICall from veda_val import VALAPICall
...@@ -73,6 +78,11 @@ class VedaHeal(object): ...@@ -73,6 +78,11 @@ class VedaHeal(object):
encode_list = self.determine_fault(video_object=v) encode_list = self.determine_fault(video_object=v)
# Using the 'Video Proto' Model # Using the 'Video Proto' Model
if self.val_status is not None: if self.val_status is not None:
# Update to VAL is also happening for those videos which are already marked complete,
# All these retries are for the data-parity between VAL and VEDA, as calls to VAL api are
# unreliable and times out. For a completed Video, VEDA heal will keep doing this unless
# the Video is old enough and escapes from the time-span that HEAL is picking up on.
# cc Greg Martin
VAC = VALAPICall( VAC = VALAPICall(
video_proto=None, video_proto=None,
video_object=v, video_object=v,
...@@ -138,8 +148,19 @@ class VedaHeal(object): ...@@ -138,8 +148,19 @@ class VedaHeal(object):
# These encodes don't count towards 'file_complete' # These encodes don't count towards 'file_complete'
if e != 'mobile_high' and e != 'audio_mp3' and e != 'review': if e != 'mobile_high' and e != 'audio_mp3' and e != 'review':
check_list.append(e) check_list.append(e)
# See if VEDA's Video data model is already having transcript status which corresponds
# to any of Val's Video transcript statuses. If its True, set `val_status` to that status
# instead of `file_complete` as transcription phase comes after encoding phase of a Video,
# and `file_complete` shows that a Video's encodes are complete, while there may be possibility
# that the Video has gone through transcription phase as well after the encodes were ready.
val_transcription_status = VAL_TRANSCRIPT_STATUS_MAP.get(video_object.transcript_status, None)
if check_list is None or len(check_list) == 0: if check_list is None or len(check_list) == 0:
self.val_status = 'file_complete' if val_transcription_status:
self.val_status = val_transcription_status
else:
self.val_status = 'file_complete'
# File is complete! # File is complete!
# Check for data parity, and call done # Check for data parity, and call done
if video_object.video_trans_status != 'Complete': if video_object.video_trans_status != 'Complete':
...@@ -156,7 +177,11 @@ class VedaHeal(object): ...@@ -156,7 +177,11 @@ class VedaHeal(object):
if self.determine_longterm_corrupt(uncompleted_encodes, expected_encodes, video_object): if self.determine_longterm_corrupt(uncompleted_encodes, expected_encodes, video_object):
return [] return []
if self.val_status != 'file_complete': complete_statuses = ['file_complete']
if val_transcription_status:
complete_statuses.append(val_transcription_status)
if self.val_status not in complete_statuses:
self.val_status = 'transcode_queue' self.val_status = 'transcode_queue'
return uncompleted_encodes return uncompleted_encodes
......
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