test_update.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #!/usr/bin/env python3
  2. # Allow direct execution
  3. import os
  4. import sys
  5. import unittest
  6. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  7. from test.helper import FakeYDL, report_warning
  8. from yt_dlp.update import UpdateInfo, Updater
  9. # XXX: Keep in sync with yt_dlp.update.UPDATE_SOURCES
  10. TEST_UPDATE_SOURCES = {
  11. 'stable': 'yt-dlp/yt-dlp',
  12. 'nightly': 'yt-dlp/yt-dlp-nightly-builds',
  13. 'master': 'yt-dlp/yt-dlp-master-builds',
  14. }
  15. TEST_API_DATA = {
  16. 'yt-dlp/yt-dlp/latest': {
  17. 'tag_name': '2023.12.31',
  18. 'target_commitish': 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
  19. 'name': 'yt-dlp 2023.12.31',
  20. 'body': 'BODY',
  21. },
  22. 'yt-dlp/yt-dlp-nightly-builds/latest': {
  23. 'tag_name': '2023.12.31.123456',
  24. 'target_commitish': 'master',
  25. 'name': 'yt-dlp nightly 2023.12.31.123456',
  26. 'body': 'Generated from: https://github.com/yt-dlp/yt-dlp/commit/cccccccccccccccccccccccccccccccccccccccc',
  27. },
  28. 'yt-dlp/yt-dlp-master-builds/latest': {
  29. 'tag_name': '2023.12.31.987654',
  30. 'target_commitish': 'master',
  31. 'name': 'yt-dlp master 2023.12.31.987654',
  32. 'body': 'Generated from: https://github.com/yt-dlp/yt-dlp/commit/dddddddddddddddddddddddddddddddddddddddd',
  33. },
  34. 'yt-dlp/yt-dlp/tags/testing': {
  35. 'tag_name': 'testing',
  36. 'target_commitish': '9999999999999999999999999999999999999999',
  37. 'name': 'testing',
  38. 'body': 'BODY',
  39. },
  40. 'fork/yt-dlp/latest': {
  41. 'tag_name': '2050.12.31',
  42. 'target_commitish': 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
  43. 'name': '2050.12.31',
  44. 'body': 'BODY',
  45. },
  46. 'fork/yt-dlp/tags/pr0000': {
  47. 'tag_name': 'pr0000',
  48. 'target_commitish': 'ffffffffffffffffffffffffffffffffffffffff',
  49. 'name': 'pr1234 2023.11.11.000000',
  50. 'body': 'BODY',
  51. },
  52. 'fork/yt-dlp/tags/pr1234': {
  53. 'tag_name': 'pr1234',
  54. 'target_commitish': '0000000000000000000000000000000000000000',
  55. 'name': 'pr1234 2023.12.31.555555',
  56. 'body': 'BODY',
  57. },
  58. 'fork/yt-dlp/tags/pr9999': {
  59. 'tag_name': 'pr9999',
  60. 'target_commitish': '1111111111111111111111111111111111111111',
  61. 'name': 'pr9999',
  62. 'body': 'BODY',
  63. },
  64. 'fork/yt-dlp-satellite/tags/pr987': {
  65. 'tag_name': 'pr987',
  66. 'target_commitish': 'master',
  67. 'name': 'pr987',
  68. 'body': 'Generated from: https://github.com/yt-dlp/yt-dlp/commit/2222222222222222222222222222222222222222',
  69. },
  70. }
  71. TEST_LOCKFILE_COMMENT = '# This file is used for regulating self-update'
  72. TEST_LOCKFILE_V1 = rf'''{TEST_LOCKFILE_COMMENT}
  73. lock 2022.08.18.36 .+ Python 3\.6
  74. lock 2023.11.16 (?!win_x86_exe).+ Python 3\.7
  75. lock 2023.11.16 win_x86_exe .+ Windows-(?:Vista|2008Server)
  76. lock 2024.10.22 py2exe .+
  77. lock 2024.10.22 linux_(?:armv7l|aarch64)_exe .+-glibc2\.(?:[12]?\d|30)\b
  78. lock 2024.10.22 (?!\w+_exe).+ Python 3\.8
  79. lock 2024.10.22 win(?:_x86)?_exe Python 3\.[78].+ Windows-(?:7-|2008ServerR2)
  80. '''
  81. TEST_LOCKFILE_V2_TMPL = r'''%s
  82. lockV2 yt-dlp/yt-dlp 2022.08.18.36 .+ Python 3\.6
  83. lockV2 yt-dlp/yt-dlp 2023.11.16 (?!win_x86_exe).+ Python 3\.7
  84. lockV2 yt-dlp/yt-dlp 2023.11.16 win_x86_exe .+ Windows-(?:Vista|2008Server)
  85. lockV2 yt-dlp/yt-dlp 2024.10.22 py2exe .+
  86. lockV2 yt-dlp/yt-dlp 2024.10.22 linux_(?:armv7l|aarch64)_exe .+-glibc2\.(?:[12]?\d|30)\b
  87. lockV2 yt-dlp/yt-dlp 2024.10.22 (?!\w+_exe).+ Python 3\.8
  88. lockV2 yt-dlp/yt-dlp 2024.10.22 win(?:_x86)?_exe Python 3\.[78].+ Windows-(?:7-|2008ServerR2)
  89. lockV2 yt-dlp/yt-dlp-nightly-builds 2023.11.15.232826 (?!win_x86_exe).+ Python 3\.7
  90. lockV2 yt-dlp/yt-dlp-nightly-builds 2023.11.15.232826 win_x86_exe .+ Windows-(?:Vista|2008Server)
  91. lockV2 yt-dlp/yt-dlp-nightly-builds 2024.10.22.051025 py2exe .+
  92. lockV2 yt-dlp/yt-dlp-nightly-builds 2024.10.22.051025 linux_(?:armv7l|aarch64)_exe .+-glibc2\.(?:[12]?\d|30)\b
  93. lockV2 yt-dlp/yt-dlp-nightly-builds 2024.10.22.051025 (?!\w+_exe).+ Python 3\.8
  94. lockV2 yt-dlp/yt-dlp-nightly-builds 2024.10.22.051025 win(?:_x86)?_exe Python 3\.[78].+ Windows-(?:7-|2008ServerR2)
  95. lockV2 yt-dlp/yt-dlp-master-builds 2023.11.15.232812 (?!win_x86_exe).+ Python 3\.7
  96. lockV2 yt-dlp/yt-dlp-master-builds 2023.11.15.232812 win_x86_exe .+ Windows-(?:Vista|2008Server)
  97. lockV2 yt-dlp/yt-dlp-master-builds 2024.10.22.045052 py2exe .+
  98. lockV2 yt-dlp/yt-dlp-master-builds 2024.10.22.060347 linux_(?:armv7l|aarch64)_exe .+-glibc2\.(?:[12]?\d|30)\b
  99. lockV2 yt-dlp/yt-dlp-master-builds 2024.10.22.060347 (?!\w+_exe).+ Python 3\.8
  100. lockV2 yt-dlp/yt-dlp-master-builds 2024.10.22.060347 win(?:_x86)?_exe Python 3\.[78].+ Windows-(?:7-|2008ServerR2)
  101. '''
  102. TEST_LOCKFILE_V2 = TEST_LOCKFILE_V2_TMPL % TEST_LOCKFILE_COMMENT
  103. TEST_LOCKFILE_ACTUAL = TEST_LOCKFILE_V2_TMPL % TEST_LOCKFILE_V1.rstrip('\n')
  104. TEST_LOCKFILE_FORK = rf'''{TEST_LOCKFILE_ACTUAL}# Test if a fork blocks updates to non-numeric tags
  105. lockV2 fork/yt-dlp pr0000 .+ Python 3.6
  106. lockV2 fork/yt-dlp pr1234 (?!win_x86_exe).+ Python 3\.7
  107. lockV2 fork/yt-dlp pr1234 win_x86_exe .+ Windows-(?:Vista|2008Server)
  108. lockV2 fork/yt-dlp pr9999 .+ Python 3.11
  109. '''
  110. class FakeUpdater(Updater):
  111. current_version = '2022.01.01'
  112. current_commit = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
  113. _channel = 'stable'
  114. _origin = 'yt-dlp/yt-dlp'
  115. _update_sources = TEST_UPDATE_SOURCES
  116. def _download_update_spec(self, *args, **kwargs):
  117. return TEST_LOCKFILE_ACTUAL
  118. def _call_api(self, tag):
  119. tag = f'tags/{tag}' if tag != 'latest' else tag
  120. return TEST_API_DATA[f'{self.requested_repo}/{tag}']
  121. def _report_error(self, msg, *args, **kwargs):
  122. report_warning(msg)
  123. class TestUpdate(unittest.TestCase):
  124. maxDiff = None
  125. def test_update_spec(self):
  126. ydl = FakeYDL()
  127. updater = FakeUpdater(ydl, 'stable')
  128. def test(lockfile, identifier, input_tag, expect_tag, exact=False, repo='yt-dlp/yt-dlp'):
  129. updater._identifier = identifier
  130. updater._exact = exact
  131. updater.requested_repo = repo
  132. result = updater._process_update_spec(lockfile, input_tag)
  133. self.assertEqual(
  134. result, expect_tag,
  135. f'{identifier!r} requesting {repo}@{input_tag} (exact={exact}) '
  136. f'returned {result!r} instead of {expect_tag!r}')
  137. for lockfile in (TEST_LOCKFILE_V1, TEST_LOCKFILE_V2, TEST_LOCKFILE_ACTUAL, TEST_LOCKFILE_FORK):
  138. # Normal operation
  139. test(lockfile, 'zip Python 3.12.0', '2023.12.31', '2023.12.31')
  140. test(lockfile, 'zip Python 3.12.0', '2023.12.31', '2023.12.31', exact=True)
  141. # py2exe should never update beyond 2024.10.22
  142. test(lockfile, 'py2exe Python 3.8', '2025.01.01', '2024.10.22')
  143. test(lockfile, 'py2exe Python 3.8', '2025.01.01', None, exact=True)
  144. # Python 3.6 --update should update only to the py3.6 lock
  145. test(lockfile, 'zip Python 3.6.0', '2023.11.16', '2022.08.18.36')
  146. # Python 3.6 --update-to an exact version later than the py3.6 lock should return None
  147. test(lockfile, 'zip Python 3.6.0', '2023.11.16', None, exact=True)
  148. # Python 3.7 should be able to update to the py3.7 lock
  149. test(lockfile, 'zip Python 3.7.0', '2023.11.16', '2023.11.16')
  150. test(lockfile, 'zip Python 3.7.1', '2023.11.16', '2023.11.16', exact=True)
  151. # Non-win_x86_exe builds on py3.7 must be locked at py3.7 lock
  152. test(lockfile, 'zip Python 3.7.1', '2023.12.31', '2023.11.16')
  153. test(lockfile, 'zip Python 3.7.1', '2023.12.31', None, exact=True)
  154. # Python 3.8 should only update to the py3.8 lock
  155. test(lockfile, 'zip Python 3.8.10', '2025.01.01', '2024.10.22')
  156. test(lockfile, 'zip Python 3.8.110', '2025.01.01', None, exact=True)
  157. test( # Windows Vista w/ win_x86_exe must be locked at Vista lock
  158. lockfile, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-Vista-6.0.6003-SP2',
  159. '2023.12.31', '2023.11.16')
  160. test( # Windows 2008Server w/ win_x86_exe must be locked at Vista lock
  161. lockfile, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-2008Server',
  162. '2023.12.31', None, exact=True)
  163. test( # Windows 7 w/ win_x86_exe py3.7 build should be able to update beyond py3.7 lock
  164. lockfile, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-7-6.1.7601-SP1',
  165. '2023.12.31', '2023.12.31', exact=True)
  166. test( # Windows 7 win_x86_exe should only update to Win7 lock
  167. lockfile, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-7-6.1.7601-SP1',
  168. '2025.01.01', '2024.10.22')
  169. test( # Windows 2008ServerR2 win_exe should only update to Win7 lock
  170. lockfile, 'win_exe Python 3.8.10 (CPython x86 32bit) - Windows-2008ServerR2',
  171. '2025.12.31', '2024.10.22')
  172. test( # Windows 8.1 w/ '2008Server' in platform string should be able to update beyond py3.7 lock
  173. lockfile, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-post2008Server-6.2.9200',
  174. '2023.12.31', '2023.12.31', exact=True)
  175. test( # win_exe built w/Python 3.8 on Windows>=8 should be able to update beyond py3.8 lock
  176. lockfile, 'win_exe Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.20348-SP0',
  177. '2025.01.01', '2025.01.01', exact=True)
  178. test( # linux_armv7l_exe w/glibc2.7 should only update to glibc<2.31 lock
  179. lockfile, 'linux_armv7l_exe Python 3.8.0 (CPython armv7l 32bit) - Linux-6.5.0-1025-azure-armv7l-with-glibc2.7',
  180. '2025.01.01', '2024.10.22')
  181. test( # linux_armv7l_exe w/Python 3.8 and glibc>=2.31 should be able to update beyond py3.8 and glibc<2.31 locks
  182. lockfile, 'linux_armv7l_exe Python 3.8.0 (CPython armv7l 32bit) - Linux-6.5.0-1025-azure-armv7l-with-glibc2.31',
  183. '2025.01.01', '2025.01.01')
  184. test( # linux_armv7l_exe w/glibc2.30 should only update to glibc<2.31 lock
  185. lockfile, 'linux_armv7l_exe Python 3.8.0 (CPython armv7l 64bit) - Linux-6.5.0-1025-azure-aarch64-with-glibc2.30 (OpenSSL',
  186. '2025.01.01', '2024.10.22')
  187. test( # linux_aarch64_exe w/glibc2.17 should only update to glibc<2.31 lock
  188. lockfile, 'linux_aarch64_exe Python 3.8.0 (CPython aarch64 64bit) - Linux-6.5.0-1025-azure-aarch64-with-glibc2.17',
  189. '2025.01.01', '2024.10.22')
  190. test( # linux_aarch64_exe w/glibc2.40 and glibc>=2.31 should be able to update beyond py3.8 and glibc<2.31 locks
  191. lockfile, 'linux_aarch64_exe Python 3.8.0 (CPython aarch64 64bit) - Linux-6.5.0-1025-azure-aarch64-with-glibc2.40',
  192. '2025.01.01', '2025.01.01')
  193. test( # linux_aarch64_exe w/glibc2.3 should only update to glibc<2.31 lock
  194. lockfile, 'linux_aarch64_exe Python 3.8.0 (CPython aarch64 64bit) - Linux-6.5.0-1025-azure-aarch64-with-glibc2.3 (OpenSSL',
  195. '2025.01.01', '2024.10.22')
  196. # Forks can block updates to non-numeric tags rather than lock
  197. test(TEST_LOCKFILE_FORK, 'zip Python 3.6.3', 'pr0000', None, repo='fork/yt-dlp')
  198. test(TEST_LOCKFILE_FORK, 'zip Python 3.7.4', 'pr0000', 'pr0000', repo='fork/yt-dlp')
  199. test(TEST_LOCKFILE_FORK, 'zip Python 3.7.4', 'pr1234', None, repo='fork/yt-dlp')
  200. test(TEST_LOCKFILE_FORK, 'zip Python 3.8.1', 'pr1234', 'pr1234', repo='fork/yt-dlp', exact=True)
  201. test(
  202. TEST_LOCKFILE_FORK, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-Vista-6.0.6003-SP2',
  203. 'pr1234', None, repo='fork/yt-dlp')
  204. test(
  205. TEST_LOCKFILE_FORK, 'win_x86_exe Python 3.7.9 (CPython x86 32bit) - Windows-7-6.1.7601-SP1',
  206. '2023.12.31', '2023.12.31', repo='fork/yt-dlp')
  207. test(TEST_LOCKFILE_FORK, 'zip Python 3.11.2', 'pr9999', None, repo='fork/yt-dlp', exact=True)
  208. test(TEST_LOCKFILE_FORK, 'zip Python 3.12.0', 'pr9999', 'pr9999', repo='fork/yt-dlp')
  209. def test_query_update(self):
  210. ydl = FakeYDL()
  211. def test(target, expected, current_version=None, current_commit=None, identifier=None):
  212. updater = FakeUpdater(ydl, target)
  213. if current_version:
  214. updater.current_version = current_version
  215. if current_commit:
  216. updater.current_commit = current_commit
  217. updater._identifier = identifier or 'zip'
  218. update_info = updater.query_update(_output=True)
  219. self.assertDictEqual(
  220. update_info.__dict__ if update_info else {}, expected.__dict__ if expected else {})
  221. test('yt-dlp/yt-dlp@latest', UpdateInfo(
  222. '2023.12.31', version='2023.12.31', requested_version='2023.12.31', commit='b' * 40))
  223. test('yt-dlp/yt-dlp-nightly-builds@latest', UpdateInfo(
  224. '2023.12.31.123456', version='2023.12.31.123456', requested_version='2023.12.31.123456', commit='c' * 40))
  225. test('yt-dlp/yt-dlp-master-builds@latest', UpdateInfo(
  226. '2023.12.31.987654', version='2023.12.31.987654', requested_version='2023.12.31.987654', commit='d' * 40))
  227. test('fork/yt-dlp@latest', UpdateInfo(
  228. '2050.12.31', version='2050.12.31', requested_version='2050.12.31', commit='e' * 40))
  229. test('fork/yt-dlp@pr0000', UpdateInfo(
  230. 'pr0000', version='2023.11.11.000000', requested_version='2023.11.11.000000', commit='f' * 40))
  231. test('fork/yt-dlp@pr1234', UpdateInfo(
  232. 'pr1234', version='2023.12.31.555555', requested_version='2023.12.31.555555', commit='0' * 40))
  233. test('fork/yt-dlp@pr9999', UpdateInfo(
  234. 'pr9999', version=None, requested_version=None, commit='1' * 40))
  235. test('fork/yt-dlp-satellite@pr987', UpdateInfo(
  236. 'pr987', version=None, requested_version=None, commit='2' * 40))
  237. test('yt-dlp/yt-dlp', None, current_version='2024.01.01')
  238. test('stable', UpdateInfo(
  239. '2023.12.31', version='2023.12.31', requested_version='2023.12.31', commit='b' * 40))
  240. test('nightly', UpdateInfo(
  241. '2023.12.31.123456', version='2023.12.31.123456', requested_version='2023.12.31.123456', commit='c' * 40))
  242. test('master', UpdateInfo(
  243. '2023.12.31.987654', version='2023.12.31.987654', requested_version='2023.12.31.987654', commit='d' * 40))
  244. test('testing', None, current_commit='9' * 40)
  245. test('testing', UpdateInfo('testing', commit='9' * 40))
  246. if __name__ == '__main__':
  247. unittest.main()