139 lines
4.5 KiB
Python
139 lines
4.5 KiB
Python
|
|
# SPDX-FileCopyrightText: 2025 Blender Authors
|
||
|
|
#
|
||
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
|
||
|
|
"""
|
||
|
|
blender -b --factory-startup -P tests/python/bl_http_downloader.py -- output-dir /tmp/should-not-exist --verbose
|
||
|
|
"""
|
||
|
|
|
||
|
|
|
||
|
|
__all__ = (
|
||
|
|
"main",
|
||
|
|
)
|
||
|
|
|
||
|
|
import unittest
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
output_dir: Path
|
||
|
|
|
||
|
|
|
||
|
|
class BasicImportTest(unittest.TestCase):
|
||
|
|
"""Just do a basic import and instantiation of classes.
|
||
|
|
|
||
|
|
This doesn't test the functionality, but does ensure that dependencies like
|
||
|
|
third-party libraries are available.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def test_downloader(self) -> None:
|
||
|
|
from _bpy_internal.http import downloader as http_dl
|
||
|
|
|
||
|
|
metadata_provider = http_dl.MetadataProviderFilesystem(
|
||
|
|
cache_location=output_dir / "http_metadata"
|
||
|
|
)
|
||
|
|
downloader = http_dl.ConditionalDownloader(metadata_provider=metadata_provider)
|
||
|
|
self.assertIsNotNone(downloader)
|
||
|
|
|
||
|
|
def test_background_downloader(self) -> None:
|
||
|
|
from _bpy_internal.http import downloader as http_dl
|
||
|
|
|
||
|
|
metadata_provider = http_dl.MetadataProviderFilesystem(
|
||
|
|
cache_location=output_dir / "http_metadata"
|
||
|
|
)
|
||
|
|
options = http_dl.DownloaderOptions(
|
||
|
|
metadata_provider=metadata_provider,
|
||
|
|
timeout=1,
|
||
|
|
http_headers={'X-Unit-Test': self.__class__.__name__}
|
||
|
|
)
|
||
|
|
|
||
|
|
def on_error(req_desc: http_dl.RequestDescription, local_path: Path, ex: Exception) -> None:
|
||
|
|
self.fail(f"unexpected call to on_error({req_desc}, {local_path}, {ex})")
|
||
|
|
|
||
|
|
downloader = http_dl.BackgroundDownloader(
|
||
|
|
options=options,
|
||
|
|
on_callback_error=on_error,
|
||
|
|
)
|
||
|
|
|
||
|
|
# Test some trivial properties that don't require anything running.
|
||
|
|
self.assertTrue(downloader.all_downloads_done)
|
||
|
|
self.assertEqual(0, downloader.num_pending_downloads)
|
||
|
|
self.assertFalse(downloader.is_shutdown_requested)
|
||
|
|
self.assertFalse(downloader.is_shutdown_complete)
|
||
|
|
self.assertFalse(downloader.is_subprocess_alive)
|
||
|
|
|
||
|
|
|
||
|
|
class BackgroundDownloaderProcessTest(unittest.TestCase):
|
||
|
|
"""Start & stop the background process for the BackgroundDownloader.
|
||
|
|
|
||
|
|
This doesn't test any HTTP requests, but does start & stop the background
|
||
|
|
process to check that this is at least possible.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def test_start_stop(self) -> None:
|
||
|
|
from _bpy_internal.http import downloader as http_dl
|
||
|
|
|
||
|
|
metadata_provider = http_dl.MetadataProviderFilesystem(
|
||
|
|
cache_location=output_dir / "http_metadata"
|
||
|
|
)
|
||
|
|
options = http_dl.DownloaderOptions(
|
||
|
|
metadata_provider=metadata_provider,
|
||
|
|
timeout=1,
|
||
|
|
http_headers={'X-Unit-Test': self.__class__.__name__}
|
||
|
|
)
|
||
|
|
|
||
|
|
def on_error(req_desc: http_dl.RequestDescription, local_path: Path, ex: Exception) -> None:
|
||
|
|
self.fail(f"unexpected call to on_error({req_desc}, {local_path}, {ex})")
|
||
|
|
|
||
|
|
downloader = http_dl.BackgroundDownloader(
|
||
|
|
options=options,
|
||
|
|
on_callback_error=on_error,
|
||
|
|
)
|
||
|
|
|
||
|
|
# Queueing a download before the downloader has started should be rejected.
|
||
|
|
with self.assertRaises(RuntimeError):
|
||
|
|
downloader.queue_download("https://example.com/", output_dir / "download.tmp")
|
||
|
|
|
||
|
|
downloader.start()
|
||
|
|
|
||
|
|
try:
|
||
|
|
self.assertFalse(downloader.is_shutdown_requested)
|
||
|
|
self.assertFalse(downloader.is_shutdown_complete)
|
||
|
|
self.assertTrue(downloader.is_subprocess_alive)
|
||
|
|
|
||
|
|
# For good measure, call the update function a few times to ensure that
|
||
|
|
# any messages are sent. There shouldn't be any, but this should also
|
||
|
|
# not be a problem.
|
||
|
|
downloader.update()
|
||
|
|
downloader.update()
|
||
|
|
downloader.update()
|
||
|
|
finally:
|
||
|
|
# In case any of the pre-shutdown assertions fail, the downloader
|
||
|
|
# should still be shut down.
|
||
|
|
if downloader.is_subprocess_alive:
|
||
|
|
downloader.shutdown()
|
||
|
|
|
||
|
|
downloader.shutdown()
|
||
|
|
|
||
|
|
self.assertTrue(downloader.is_shutdown_requested)
|
||
|
|
self.assertTrue(downloader.is_shutdown_complete)
|
||
|
|
self.assertFalse(downloader.is_subprocess_alive)
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
global output_dir
|
||
|
|
|
||
|
|
import sys
|
||
|
|
import tempfile
|
||
|
|
|
||
|
|
argv = [sys.argv[0]]
|
||
|
|
if '--' in sys.argv:
|
||
|
|
argv.extend(sys.argv[sys.argv.index('--') + 1:])
|
||
|
|
|
||
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||
|
|
output_dir = Path(temp_dir)
|
||
|
|
unittest.main(argv=argv)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|