Files
lookingWeb/tests/test_qbittorrent_downloader.py
T
cat-shark 01827224d6 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 为实例属性,与实现错配),未在本次范围
2026-08-30 12:24:26 +08:00

278 lines
9.7 KiB
Python

"""
测试 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()