This means it's no longer GCS-specific, and can be tested using the local storage implementation. Required implementation of a rename operation. To mirror Google's API, I've implemented the renaming of a Blob as a function on the Bucket class. To me this makes sense, as it requires creating a new Blob instance, which shouldn't be done by another Blob.
273 lines
12 KiB
Python
273 lines
12 KiB
Python
"""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'])
|