]> jfr.im git - yt-dlp.git/blame - test/test_download.py
Add function add_default_info_extractors to YoutubeDL
[yt-dlp.git] / test / test_download.py
CommitLineData
fd5ff020
FV
1#!/usr/bin/env python
2
5c892b0b 3import errno
efe8902f 4import hashlib
fd5ff020 5import io
efe8902f 6import os
7f60b5aa 7import json
cdab8aa3
PH
8import unittest
9import sys
6b3aef80 10import socket
78d3442b 11import binascii
fd5ff020
FV
12
13# Allow direct execution
14sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
cdab8aa3 15
8222d8de 16import youtube_dl.YoutubeDL
fd5ff020 17from youtube_dl.utils import *
1535ac2a 18
fd5ff020
FV
19PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json")
20
8cc83b8d
FV
21RETRIES = 3
22
fd5ff020
FV
23# General configuration (from __init__, not very elegant...)
24jar = compat_cookiejar.CookieJar()
25cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
26proxy_handler = compat_urllib_request.ProxyHandler()
27opener = compat_urllib_request.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler())
28compat_urllib_request.install_opener(opener)
d8bbf201 29socket.setdefaulttimeout(10)
fd5ff020 30
5c892b0b
PH
31def _try_rm(filename):
32 """ Remove a file if it exists """
33 try:
34 os.remove(filename)
35 except OSError as ose:
36 if ose.errno != errno.ENOENT:
37 raise
38
ee55fcbe 39md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest()
78d3442b 40
8222d8de 41class YoutubeDL(youtube_dl.YoutubeDL):
fd5ff020 42 def __init__(self, *args, **kwargs):
fd5ff020 43 self.to_stderr = self.to_screen
0eaf520d 44 self.processed_info_dicts = []
8222d8de 45 super(YoutubeDL, self).__init__(*args, **kwargs)
476203d0 46 def report_warning(self, message):
be95cac1
FV
47 # Don't accept warnings during tests
48 raise ExtractorError(message)
0eaf520d
FV
49 def process_info(self, info_dict):
50 self.processed_info_dicts.append(info_dict)
8222d8de 51 return super(YoutubeDL, self).process_info(info_dict)
1535ac2a 52
fd5ff020
FV
53def _file_md5(fn):
54 with open(fn, 'rb') as f:
55 return hashlib.md5(f.read()).hexdigest()
56
fc2c063e
PH
57from helper import get_testcases
58defs = get_testcases()
6b47c7f2 59
fd5ff020
FV
60with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
61 parameters = json.load(pf)
1535ac2a 62
0eaf520d 63
1535ac2a 64class TestDownload(unittest.TestCase):
744435f2 65 maxDiff = None
fd5ff020
FV
66 def setUp(self):
67 self.parameters = parameters
68 self.defs = defs
69
911ee27e 70### Dynamically generate tests
5d01a647
PH
71def generator(test_case):
72
1535ac2a 73 def test_template(self):
d1cade5a 74 ie = youtube_dl.extractor.get_info_extractor(test_case['name'])
fd5ff020
FV
75 if not ie._WORKING:
76 print('Skipping: IE marked as not _WORKING')
77 return
5c892b0b 78 if 'playlist' not in test_case and not test_case['file']:
6985325e
PH
79 print('Skipping: No output file specified')
80 return
fd5ff020
FV
81 if 'skip' in test_case:
82 print('Skipping: {0}'.format(test_case['skip']))
83 return
0eaf520d 84
c073e35b
PH
85 params = self.parameters.copy()
86 params.update(test_case.get('params', {}))
0eaf520d 87
8222d8de 88 ydl = YoutubeDL(params)
023fa8c4 89 ydl.add_default_info_extractors()
bffbd5f0
PH
90 finished_hook_called = set()
91 def _hook(status):
92 if status['status'] == 'finished':
93 finished_hook_called.add(status['filename'])
8222d8de 94 ydl.fd.add_progress_hook(_hook)
5c892b0b
PH
95
96 test_cases = test_case.get('playlist', [test_case])
97 for tc in test_cases:
98 _try_rm(tc['file'])
3a648b20 99 _try_rm(tc['file'] + '.part')
5c892b0b
PH
100 _try_rm(tc['file'] + '.info.json')
101 try:
8cc83b8d
FV
102 for retry in range(1, RETRIES + 1):
103 try:
8222d8de 104 ydl.download([test_case['url']])
8cc83b8d
FV
105 except (DownloadError, ExtractorError) as err:
106 if retry == RETRIES: raise
107
108 # Check if the exception is not a network related one
90a99c1b 109 if not err.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError):
8cc83b8d
FV
110 raise
111
112 print('Retrying: {0} failed tries\n\n##########\n\n'.format(retry))
113 else:
114 break
5c892b0b
PH
115
116 for tc in test_cases:
511eda8e 117 if not test_case.get('params', {}).get('skip_download', False):
233a2296 118 self.assertTrue(os.path.exists(tc['file']), msg='Missing file ' + tc['file'])
bffbd5f0 119 self.assertTrue(tc['file'] in finished_hook_called)
5c892b0b
PH
120 self.assertTrue(os.path.exists(tc['file'] + '.info.json'))
121 if 'md5' in tc:
122 md5_for_file = _file_md5(tc['file'])
123 self.assertEqual(md5_for_file, tc['md5'])
124 with io.open(tc['file'] + '.info.json', encoding='utf-8') as infof:
125 info_dict = json.load(infof)
51ce3a75
PH
126 for (info_field, expected) in tc.get('info_dict', {}).items():
127 if isinstance(expected, compat_str) and expected.startswith('md5:'):
128 self.assertEqual(expected, 'md5:' + md5(info_dict.get(info_field)))
78d3442b 129 else:
51ce3a75
PH
130 got = info_dict.get(info_field)
131 self.assertEqual(
132 expected, got,
133 u'invalid value for field %s, expected %r, got %r' % (info_field, expected, got))
78d3442b
FV
134
135 # If checkable fields are missing from the test case, print the info_dict
ee55fcbe 136 test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value))
78d3442b
FV
137 for key, value in info_dict.items()
138 if value and key in ('title', 'description', 'uploader', 'upload_date', 'uploader_id', 'location'))
139 if not all(key in tc.get('info_dict', {}).keys() for key in test_info_dict.keys()):
140 sys.stderr.write(u'\n"info_dict": ' + json.dumps(test_info_dict, ensure_ascii=False, indent=2) + u'\n')
141
142 # Check for the presence of mandatory fields
143 for key in ('id', 'url', 'title', 'ext'):
144 self.assertTrue(key in info_dict.keys() and info_dict[key])
5c892b0b
PH
145 finally:
146 for tc in test_cases:
147 _try_rm(tc['file'])
3a648b20 148 _try_rm(tc['file'] + '.part')
5c892b0b 149 _try_rm(tc['file'] + '.info.json')
fd5ff020 150
1535ac2a 151 return test_template
fd5ff020 152
5d01a647 153### And add them to TestDownload
f7ab6cbe 154for n, test_case in enumerate(defs):
5d01a647 155 test_method = generator(test_case)
2eb88d95
PH
156 tname = 'test_' + str(test_case['name'])
157 i = 1
158 while hasattr(TestDownload, tname):
41beccba 159 tname = 'test_' + str(test_case['name']) + '_' + str(i)
2eb88d95
PH
160 i += 1
161 test_method.__name__ = tname
fd5ff020 162 setattr(TestDownload, test_method.__name__, test_method)
5d01a647 163 del test_method
cdab8aa3
PH
164
165
166if __name__ == '__main__':
167 unittest.main()