'commit'
This commit is contained in:
39
DouYin/dy-downloader/tests/test_config_loader.py
Normal file
39
DouYin/dy-downloader/tests/test_config_loader.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from config import ConfigLoader
|
||||
|
||||
|
||||
def test_config_loader_merges_file_and_defaults(tmp_path, monkeypatch):
|
||||
config_file = tmp_path / "config.yml"
|
||||
config_file.write_text(
|
||||
"""
|
||||
link:
|
||||
- https://www.douyin.com/video/1
|
||||
path: ./Custom/
|
||||
thread: 3
|
||||
"""
|
||||
)
|
||||
|
||||
monkeypatch.setenv('DOUYIN_THREAD', '8')
|
||||
|
||||
loader = ConfigLoader(str(config_file))
|
||||
|
||||
# Environment variable should override file
|
||||
assert loader.get('thread') == 8
|
||||
# File values should override defaults
|
||||
assert loader.get('path') == './Custom/'
|
||||
# Links should be normalized to list
|
||||
assert loader.get_links() == ['https://www.douyin.com/video/1']
|
||||
|
||||
|
||||
def test_config_validation_requires_links_and_path(tmp_path):
|
||||
config_file = tmp_path / "config.yml"
|
||||
config_file.write_text("{}")
|
||||
|
||||
loader = ConfigLoader(str(config_file))
|
||||
assert not loader.validate()
|
||||
|
||||
loader.update(link=['https://www.douyin.com/video/1'], path='./Downloaded/')
|
||||
assert loader.validate() is True
|
||||
18
DouYin/dy-downloader/tests/test_cookie_manager.py
Normal file
18
DouYin/dy-downloader/tests/test_cookie_manager.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from auth import CookieManager
|
||||
|
||||
|
||||
def test_cookie_manager_validation_requires_all_keys(tmp_path):
|
||||
cookie_file = tmp_path / '.cookies.json'
|
||||
manager = CookieManager(str(cookie_file))
|
||||
|
||||
manager.set_cookies({'msToken': 'token', 'ttwid': 'id'})
|
||||
assert manager.validate_cookies() is False
|
||||
|
||||
manager.set_cookies({
|
||||
'msToken': 'token',
|
||||
'ttwid': 'id',
|
||||
'odin_tt': 'odin',
|
||||
'passport_csrf_token': 'csrf',
|
||||
})
|
||||
|
||||
assert manager.validate_cookies() is True
|
||||
38
DouYin/dy-downloader/tests/test_database.py
Normal file
38
DouYin/dy-downloader/tests/test_database.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from storage import Database
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_database_aweme_lifecycle(tmp_path):
|
||||
db_path = tmp_path / "test.db"
|
||||
database = Database(str(db_path))
|
||||
|
||||
await database.initialize()
|
||||
|
||||
aweme_payload = {
|
||||
'aweme_id': '123',
|
||||
'aweme_type': 'video',
|
||||
'title': 'test',
|
||||
'author_id': 'author',
|
||||
'author_name': 'Author',
|
||||
'create_time': 1700000000,
|
||||
'file_path': '/tmp',
|
||||
'metadata': json.dumps({'a': 1}, ensure_ascii=False),
|
||||
}
|
||||
|
||||
await database.add_aweme(aweme_payload)
|
||||
|
||||
assert await database.is_downloaded('123') is True
|
||||
assert await database.get_aweme_count_by_author('author') == 1
|
||||
assert await database.get_latest_aweme_time('author') == 1700000000
|
||||
|
||||
await database.add_history({
|
||||
'url': 'https://www.douyin.com/video/123',
|
||||
'url_type': 'video',
|
||||
'total_count': 1,
|
||||
'success_count': 1,
|
||||
'config': json.dumps({'path': './Downloaded/'}, ensure_ascii=False),
|
||||
})
|
||||
25
DouYin/dy-downloader/tests/test_url_parser.py
Normal file
25
DouYin/dy-downloader/tests/test_url_parser.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from core.url_parser import URLParser
|
||||
|
||||
|
||||
def test_parse_video_url():
|
||||
url = "https://www.douyin.com/video/7320876060210373923"
|
||||
parsed = URLParser.parse(url)
|
||||
|
||||
assert parsed is not None
|
||||
assert parsed['type'] == 'video'
|
||||
assert parsed['aweme_id'] == '7320876060210373923'
|
||||
|
||||
|
||||
def test_parse_gallery_url_sets_aweme_id():
|
||||
url = "https://www.douyin.com/note/7320876060210373923"
|
||||
parsed = URLParser.parse(url)
|
||||
|
||||
assert parsed is not None
|
||||
assert parsed['type'] == 'gallery'
|
||||
assert parsed['aweme_id'] == '7320876060210373923'
|
||||
assert parsed['note_id'] == '7320876060210373923'
|
||||
|
||||
|
||||
def test_parse_unsupported_url_returns_none():
|
||||
url = "https://www.douyin.com/music/123456"
|
||||
assert URLParser.parse(url) is None
|
||||
81
DouYin/dy-downloader/tests/test_video_downloader.py
Normal file
81
DouYin/dy-downloader/tests/test_video_downloader.py
Normal file
@@ -0,0 +1,81 @@
|
||||
import pytest
|
||||
|
||||
from auth import CookieManager
|
||||
from config import ConfigLoader
|
||||
from control import QueueManager, RateLimiter, RetryHandler
|
||||
from core.api_client import DouyinAPIClient
|
||||
from core.video_downloader import VideoDownloader
|
||||
from storage import FileManager
|
||||
|
||||
|
||||
def _build_downloader(tmp_path):
|
||||
config = ConfigLoader()
|
||||
config.update(path=str(tmp_path))
|
||||
|
||||
file_manager = FileManager(str(tmp_path))
|
||||
cookie_manager = CookieManager(str(tmp_path / '.cookies.json'))
|
||||
api_client = DouyinAPIClient({})
|
||||
|
||||
downloader = VideoDownloader(
|
||||
config,
|
||||
api_client,
|
||||
file_manager,
|
||||
cookie_manager,
|
||||
database=None,
|
||||
rate_limiter=RateLimiter(max_per_second=5),
|
||||
retry_handler=RetryHandler(max_retries=1),
|
||||
queue_manager=QueueManager(max_workers=1),
|
||||
)
|
||||
|
||||
return downloader, api_client
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_video_downloader_skip_counts_total(tmp_path, monkeypatch):
|
||||
downloader, api_client = _build_downloader(tmp_path)
|
||||
|
||||
async def _fake_should_download(self, _):
|
||||
return False
|
||||
|
||||
downloader._should_download = _fake_should_download.__get__(downloader, VideoDownloader)
|
||||
|
||||
result = await downloader.download({'aweme_id': '123'})
|
||||
|
||||
assert result.total == 1
|
||||
assert result.skipped == 1
|
||||
assert result.success == 0
|
||||
assert result.failed == 0
|
||||
|
||||
await api_client.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_no_watermark_url_signs_with_headers(tmp_path, monkeypatch):
|
||||
downloader, api_client = _build_downloader(tmp_path)
|
||||
|
||||
signed_url = 'https://www.douyin.com/aweme/v1/play/?video_id=1&X-Bogus=signed'
|
||||
|
||||
def _fake_sign(url: str):
|
||||
return signed_url, 'UnitTestAgent/1.0'
|
||||
|
||||
monkeypatch.setattr(api_client, 'sign_url', _fake_sign)
|
||||
|
||||
aweme = {
|
||||
'aweme_id': '1',
|
||||
'video': {
|
||||
'play_addr': {
|
||||
'url_list': [
|
||||
'https://www.douyin.com/aweme/v1/play/?video_id=1&watermark=0'
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
url, headers = downloader._build_no_watermark_url(aweme)
|
||||
|
||||
assert url == signed_url
|
||||
assert headers['User-Agent'] == 'UnitTestAgent/1.0'
|
||||
assert headers['Accept'] == '*/*'
|
||||
assert headers['Referer'].startswith('https://www.douyin.com')
|
||||
|
||||
await api_client.close()
|
||||
11
DouYin/dy-downloader/tests/test_xbogus.py
Normal file
11
DouYin/dy-downloader/tests/test_xbogus.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from utils.xbogus import generate_x_bogus
|
||||
|
||||
|
||||
def test_generate_x_bogus_appends_parameter():
|
||||
base_url = "https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=123"
|
||||
signed_url, token, ua = generate_x_bogus(base_url)
|
||||
|
||||
assert signed_url.startswith(base_url)
|
||||
assert "X-Bogus=" in signed_url
|
||||
assert isinstance(token, str) and len(token) > 10
|
||||
assert isinstance(ua, str) and "Mozilla" in ua
|
||||
Reference in New Issue
Block a user