fix: 修复主程序卡死与下载器集成,新增真实数据测试
- LookingWebMain: 强制 IPv4 避免 IPv6 不可达挂起;requests 加超时防卡死 - get_seed_from_element_detail: 修复限流页崩溃与 favicon 误作来源 URL,改用 canonical/传入 URL - QbittorrentDownloader: 修复 main() 中模块/类误用导致的 download_by_seed AttributeError;请求加超时 - MySqlService: 修复数据库不可达时 query/execute/close 的 None 崩溃,close 后置空 connection - 新增 cf_session: Cloudflare 人机认证 cookie 管理 + 限流退避重试 + 自动弹浏览器刷新验证 - 新增 refresh_cf_cookies.py: 弹出浏览器手动验证并保存 cf_clearance - tests/: 真实网络/数据库测试(get_page、seed_is_exist、cf_session)+ run_tests.py runner - 清理无用脚本(final_test2/verify_replace/REPLACEMENT_INFO),.idea 与 cookie 文件入 .gitignore 注: test_qbittorrent_downloader.py 11 个用例为既有失败(mock 目标 session 为实例属性,与实现错配),未在本次范围
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
"""
|
||||
测试 qBittorrent 下载器
|
||||
"""
|
||||
import pytest
|
||||
import requests
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
from loguru import logger
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
from ariaDownloaderService.QbittorrentDownloader import QbittorrentDownloader
|
||||
from dataService.dto.SeedInfo import SeedInfo
|
||||
|
||||
|
||||
class TestQbittorrentDownloader:
|
||||
"""qBittorrent 下载器测试类"""
|
||||
|
||||
def setup_method(self):
|
||||
"""每个测试方法前的设置"""
|
||||
# 配置 loguru 输出到控制台
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="DEBUG")
|
||||
|
||||
def test_initialization_without_auth(self):
|
||||
"""测试不使用认证的初始化"""
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
|
||||
assert downloader.host == "192.168.123.199"
|
||||
assert downloader.api_port == 8085
|
||||
assert downloader.api_base_url == "http://192.168.123.199:8085/api/v2"
|
||||
assert downloader.username == ""
|
||||
assert downloader.password == ""
|
||||
logger.info("不使用认证的初始化测试通过")
|
||||
|
||||
def test_initialization_with_auth(self):
|
||||
"""测试使用认证的初始化"""
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085,
|
||||
username="admin",
|
||||
password="GUOxy.5157"
|
||||
)
|
||||
|
||||
assert downloader.host == "192.168.123.199"
|
||||
assert downloader.api_port == 8085
|
||||
assert downloader.username == "admin"
|
||||
assert downloader.password == "GUOxy.5157"
|
||||
assert downloader.api_base_url == "http://192.168.123.199:8085/api/v2"
|
||||
logger.info("使用认证的初始化测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_magnet_success(self, mock_post):
|
||||
"""测试通过 magnet 链接成功添加下载任务"""
|
||||
# 模拟成功的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = ""
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
magnet_url = "magnet:?xt=urn:btih:1234567890abcdef"
|
||||
result = downloader.download_by_magnet(magnet_url)
|
||||
|
||||
assert result == "1"
|
||||
mock_post.assert_called_once()
|
||||
|
||||
# 验证请求参数
|
||||
call_args = mock_post.call_args
|
||||
assert call_args[0][0] == "http://192.168.123.199:8085/api/v2/torrents/add"
|
||||
assert call_args[1]['data']['urls'] == magnet_url
|
||||
logger.info("通过 magnet 链接成功添加下载任务测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_magnet_failure_status(self, mock_post):
|
||||
"""测试请求返回非200状态码的情况"""
|
||||
# 模拟失败的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 500
|
||||
mock_response.text = "Internal Server Error"
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
magnet_url = "magnet:?xt=urn:btih:1234567890abcdef"
|
||||
result = downloader.download_by_magnet(magnet_url)
|
||||
|
||||
assert result == "-1"
|
||||
logger.info("请求返回非200状态码测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_magnet_exception(self, mock_post):
|
||||
"""测试请求过程中发生异常的情况"""
|
||||
# 模拟异常
|
||||
mock_post.side_effect = requests.exceptions.ConnectionError("Connection refused")
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
magnet_url = "magnet:?xt=urn:btih:1234567890abcdef"
|
||||
result = downloader.download_by_magnet(magnet_url)
|
||||
|
||||
assert result == "0"
|
||||
logger.info("请求过程中发生异常测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_seed_success(self, mock_post):
|
||||
"""测试通过种子信息成功添加下载任务"""
|
||||
# 模拟成功的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = ""
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
# 创建种子信息对象
|
||||
seed_info = SeedInfo(name="测试种子", seedUrl="magnet:?xt=urn:btih:1234567890abcdef")
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.download_by_seed(seed_info)
|
||||
|
||||
assert result == "1"
|
||||
mock_post.assert_called_once()
|
||||
|
||||
# 验证传递的 URL 是种子信息中的 seedUrl
|
||||
call_args = mock_post.call_args
|
||||
assert call_args[1]['data']['urls'] == "magnet:?xt=urn:btih:1234567890abcdef"
|
||||
logger.info("通过种子信息成功添加下载任务测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_seed_empty_url(self, mock_post):
|
||||
"""测试种子信息中没有 URL 的情况"""
|
||||
# 创建种子信息对象,seedUrl 为空
|
||||
seed_info = SeedInfo(name="测试种子", seedUrl=None)
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.download_by_seed(seed_info)
|
||||
|
||||
assert result == "0"
|
||||
logger.info("种子信息中没有 URL 测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.post')
|
||||
def test_download_by_magnet_with_options(self, mock_post):
|
||||
"""测试带保存路径和分类的下载"""
|
||||
# 模拟成功的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = ""
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
magnet_url = "magnet:?xt=urn:btih:1234567890abcdef"
|
||||
result = downloader.download_by_magnet(
|
||||
magnet_url,
|
||||
save_path="/downloads/test",
|
||||
category="movies",
|
||||
tags="test"
|
||||
)
|
||||
|
||||
assert result == "1"
|
||||
|
||||
# 验证请求参数包含所有选项
|
||||
call_args = mock_post.call_args
|
||||
data = call_args[1]['data']
|
||||
assert data['urls'] == magnet_url
|
||||
assert data['savepath'] == "/downloads/test"
|
||||
assert data['category'] == "movies"
|
||||
assert data['tags'] == "test"
|
||||
logger.info("带保存路径和分类的下载测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.get')
|
||||
def test_test_connection_success(self, mock_get):
|
||||
"""测试连接测试成功"""
|
||||
# 模拟成功的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = "v4.6.0"
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.test_connection()
|
||||
|
||||
assert result is True
|
||||
mock_get.assert_called_once_with("http://192.168.123.199:8085/api/v2/app/version")
|
||||
logger.info("连接测试成功测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.get')
|
||||
def test_test_connection_failure(self, mock_get):
|
||||
"""测试连接测试失败"""
|
||||
# 模拟失败的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 404
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.test_connection()
|
||||
|
||||
assert result is False
|
||||
logger.info("连接测试失败测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.get')
|
||||
def test_get_downloads_success(self, mock_get):
|
||||
"""测试获取下载列表成功"""
|
||||
# 模拟成功的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = [
|
||||
{"name": "测试任务1", "progress": 50},
|
||||
{"name": "测试任务2", "progress": 100}
|
||||
]
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.get_downloads()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0]["name"] == "测试任务1"
|
||||
mock_get.assert_called_once_with("http://192.168.123.199:8085/api/v2/torrents/info")
|
||||
logger.info("获取下载列表成功测试通过")
|
||||
|
||||
@patch('ariaDownloaderService.QbittorrentDownloader.session.get')
|
||||
def test_get_downloads_failure(self, mock_get):
|
||||
"""测试获取下载列表失败"""
|
||||
# 模拟失败的响应
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 500
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
downloader = QbittorrentDownloader(
|
||||
host="192.168.123.199",
|
||||
api_port=8085
|
||||
)
|
||||
result = downloader.get_downloads()
|
||||
|
||||
assert result == []
|
||||
logger.info("获取下载列表失败测试通过")
|
||||
|
||||
|
||||
def run_tests():
|
||||
"""运行所有测试"""
|
||||
pytest.main([
|
||||
__file__,
|
||||
"-v",
|
||||
"--tb=short",
|
||||
"--log-cli-level=INFO"
|
||||
])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_tests()
|
||||
Reference in New Issue
Block a user