"""Test cases for the zencoder notifications.""" import dateutil.parser from bson import ObjectId from pillar.tests import AbstractPillarTest from pillar.tests import common_test_data as ctd class SizeDescriptorTest(AbstractPillarTest): def test_known_sizes(self): from pillar.api.encoding import size_descriptor self.assertEqual('720p', size_descriptor(1280, 720)) # 720p at 16:9 aspect self.assertEqual('720p', size_descriptor(1280, 548)) # 720p at 21:9 aspect self.assertEqual('720p', size_descriptor(1280, 500)) # 720p at 23:9 aspect self.assertEqual('4k', size_descriptor(4096, 2304)) # 4k at 16:9 aspect self.assertEqual('4k', size_descriptor(4096, 1602)) # 4k at 23:9 aspect self.assertEqual('4k', size_descriptor(4096, 1602)) # 4k at 23:9 aspect self.assertEqual('UHD', size_descriptor(3840, 2160)) # UHD at 16:9 aspect def test_unknown_sizes(self): from pillar.api.encoding import size_descriptor self.assertEqual('240p', size_descriptor(320, 240)) # old VGA resolution class ZencoderNotificationTest(AbstractPillarTest): def setUp(self, **kwargs): super().setUp(**kwargs) self.enter_app_context() self.secret = self.app.config['ZENCODER_NOTIFICATIONS_SECRET'] def test_missing_secret(self): self.post('/api/encoding/zencoder/notifications', expected_status=401) def test_wrong_secret(self): self.post('/api/encoding/zencoder/notifications', headers={'X-Zencoder-Notification-Secret': 'koro'}, expected_status=401) def test_good_secret_existing_file(self): file_id, _ = self.ensure_file_exists(file_overrides={ 'backend': 'local', 'processing': {'backend': 'zencoder', 'job_id': 'koro-007', 'status': 'processing'} }) self.post('/api/encoding/zencoder/notifications', json={'job': {'id': 'koro-007', 'state': 'finished'}, 'outputs': [{ 'format': 'jpg', 'height': 1080, 'width': 2048, 'file_size_in_bytes': 15, 'md5_checksum': None, }], 'input': { 'duration_in_ms': 5000, }}, headers={'X-Zencoder-Notification-Secret': self.secret}, expected_status=204) db_file = self.app.db('files').find_one(file_id) self.assertEqual('complete', db_file['status']) self.assertEqual('finished', db_file['processing']['status']) def test_failed_job(self): file_id, _ = self.ensure_file_exists(file_overrides={ 'processing': {'backend': 'zencoder', 'job_id': 'koro-007', 'status': 'processing'} }) self.post('/api/encoding/zencoder/notifications', json={'job': {'id': 'koro-007', 'state': 'failed'}, 'outputs': [{ 'format': 'jpg', 'height': 1080, 'width': 2048, 'file_size_in_bytes': 15, 'md5_checksum': None, 'error': 'Lama support malfunctioning', 'url': 'http://example.com/file.mp4', }], 'input': { 'duration_in_ms': 5000, }}, headers={'X-Zencoder-Notification-Secret': self.secret}) db_file = self.app.db('files').find_one(file_id) self.assertEqual('failed', db_file['status']) self.assertEqual('failed', db_file['processing']['status']) def test_failure_saving(self): # This document is intentionally created with non-existing project ID. As a result, # it cannot be saved any more with Eve. file_doc = { "_id": ObjectId("5a6751b33bea6a01fdfd59f0"), "name": "02a877a1d9da45509cdba97e283ef0bc.mkv", "filename": "4. pose-library-previews.mkv", "file_path": "02a877a1d9da45509cdba97e283ef0bc.mkv", "user": ctd.EXAMPLE_PROJECT_OWNER_ID, "backend": "local", "md5": "", "content_type": "video/x-matroska", "length": 39283494, "project": ObjectId('deadbeefcafef00dbeefcace'), "status": "processing", "length_aggregate_in_bytes": 45333852, "format": "x-matroska", "variations": [{ "format": "mp4", "content_type": "video/mp4", "file_path": "02a877a1d9da45509cdba97e283ef0bc-1080p.mp4", "size": "1080p", "duration": 100, "width": 1920, "height": 1080, "length": 6050358, "md5": "", "link": "https://storage.googleapis.com/59d69c94f4/_%2F02-1080p.mp4" }], "processing": { "status": "processing", "job_id": "447043841", "backend": "zencoder" }, "link_expires": dateutil.parser.parse("2018-01-27T06:24:31.827+0100"), "_updated": dateutil.parser.parse("2018-01-26T07:24:54.000+0100"), "_created": dateutil.parser.parse("2018-01-23T16:16:03.000+0100"), "_deleted": False, "_etag": "54f1d65326f4d856b740480dc52edefa96476d8a", "link": "https://storage.googleapis.com/59d69c94f4/_%2F02.mkv" } files_coll = self.app.db('files') files_coll.insert_one(file_doc) file_id = file_doc['_id'] notif = { 'job': {'created_at': '2018-01-23T15:16:17Z', 'id': 447043841, 'pass_through': None, 'state': 'finished', 'submitted_at': '2018-01-23T15:16:17Z', 'test': False, 'updated_at': '2018-01-23T15:16:42Z'}, 'outputs': [{'height': 1080, 'id': 1656104422, 'format': 'je moeder', 'url': 'gcs://59d69c94f488551661254569/_/02-mp4.mp4', 'width': 1920}]} self.post('/api/encoding/zencoder/notifications', json=notif, headers={'X-Zencoder-Notification-Secret': self.secret}, expected_status=500) db_file = files_coll.find_one(file_id) self.assertEqual('processing', db_file['status']) self.assertEqual('processing', db_file['processing']['status']) def test_actual_notification(self): """Test with actual file and notification documents.""" self.ensure_project_exists() file_doc = { "_id": ObjectId("5a6751b33bea6a01fdfd59f0"), "name": "02a877a1d9da45509cdba97e283ef0bc.mkv", "filename": "4. pose-library-previews.mkv", "file_path": "02a877a1d9da45509cdba97e283ef0bc.mkv", "user": ctd.EXAMPLE_PROJECT_OWNER_ID, "backend": "local", "md5": "", "content_type": "video/x-matroska", "length": 39283494, "project": ctd.EXAMPLE_PROJECT_ID, "status": "processing", "length_aggregate_in_bytes": 45333852, "format": "x-matroska", "variations": [{ "format": "mp4", "content_type": "video/mp4", "file_path": "02a877a1d9da45509cdba97e283ef0bc-1080p.mp4", "size": "1080p", "duration": 100, "width": 1920, "height": 1080, "length": 6050358, "md5": "", "link": "https://storage.googleapis.com/59d69c94f4/_%2F02-1080p.mp4" }], "processing": { "status": "processing", "job_id": "447043841", "backend": "zencoder" }, "link_expires": dateutil.parser.parse("2018-01-27T06:24:31.827+0100"), "_updated": dateutil.parser.parse("2018-01-26T07:24:54.000+0100"), "_created": dateutil.parser.parse("2018-01-23T16:16:03.000+0100"), "_deleted": False, "_etag": "54f1d65326f4d856b740480dc52edefa96476d8a", "link": "https://storage.googleapis.com/59d69c94f4/_%2F02.mkv" } # Make sure the to-be-renamed file exists on the local storage bucket. from pillar.api.file_storage_backends import Bucket, local bucket_class = Bucket.for_backend('local') bucket = bucket_class(str(file_doc['project'])) blob: local.LocalBlob = bucket.blob('02a877a1d9da45509cdba97e283ef0bc-1080p.mp4') blob.touch() files_coll = self.app.db('files') files_coll.insert_one(file_doc) file_id = file_doc['_id'] notif = { 'input': {'audio_bitrate_in_kbps': None, 'audio_codec': None, 'audio_sample_rate': None, 'channels': None, 'duration_in_ms': 100840, 'file_size_in_bytes': 39283494, 'format': 'matroska', 'frame_rate': 25.0, 'height': 1080, 'id': 447014781, 'md5_checksum': None, 'state': 'finished', 'total_bitrate_in_kbps': None, 'video_bitrate_in_kbps': 3054, 'video_codec': 'h264', 'width': 1920}, 'job': {'created_at': '2018-01-23T15:16:17Z', 'id': 447043841, 'pass_through': None, 'state': 'finished', 'submitted_at': '2018-01-23T15:16:17Z', 'test': False, 'updated_at': '2018-01-23T15:16:42Z'}, 'outputs': [{'audio_bitrate_in_kbps': None, 'audio_codec': None, 'audio_sample_rate': None, 'channels': None, 'duration_in_ms': 100840, 'file_size_in_bytes': 6050358, 'format': 'mpeg4', 'fragment_duration_in_ms': None, 'frame_rate': 25.0, 'height': 1080, 'id': 1656104422, 'label': None, 'md5_checksum': None, 'rfc_6381_audio_codec': None, 'rfc_6381_video_codec': 'avc1.420028', 'state': 'finished', 'total_bitrate_in_kbps': 479, 'type': 'standard', 'url': 'gcs://59d69c94f488551661254569/_/02-mp4.mp4', 'video_bitrate_in_kbps': 479, 'video_codec': 'h264', 'width': 1920}]} self.post('/api/encoding/zencoder/notifications', json=notif, headers={'X-Zencoder-Notification-Secret': self.secret}, expected_status=204) db_file = files_coll.find_one(file_id) self.assertEqual('complete', db_file['status']) self.assertEqual('finished', db_file['processing']['status'])