Files
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

286 lines
12 KiB
Python

"""
文件上传下载功能测试 - TDD Red阶段
测试文件上传、下载、验证和管理功能。
"""
import pytest
import allure
import os
import tempfile
from typing import Any, Optional
@allure.epic("核心框架")
@allure.feature("文件上传下载功能 - TDD Red阶段")
class TestFileHandler:
"""文件处理功能测试类 - TDD Red阶段(期望失败)"""
@allure.title("测试文件上传 - TDD Red阶段")
@allure.description("验证文件上传功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.CRITICAL)
@pytest.mark.smoke
def test_file_upload(self) -> None:
"""
TDD Red阶段: 测试文件上传
预期结果:
- 能够上传文件
- 返回上传结果和文件信息
- 支持多种文件类型
"""
from core.file_handler import FileUploader
with allure.step("Step 1: 创建文件上传器"):
uploader = FileUploader(upload_dir="/tmp/test_uploads")
allure.attach("✅ 创建文件上传器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 创建测试文件"):
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write("测试文件内容")
test_file_path = f.name
allure.attach(f"✅ 创建测试文件: {test_file_path}", "步骤2", allure.attachment_type.TEXT)
with allure.step("Step 3: 上传文件"):
with open(test_file_path, 'rb') as f:
result = uploader.upload(f, filename="test.txt")
allure.attach(f"✅ 上传结果: {result}", "步骤3", allure.attachment_type.TEXT)
assert result.success is True, "文件上传应该成功"
assert result.file_id is not None, "应该有文件ID"
with allure.step("Step 4: 清理"):
os.unlink(test_file_path)
if result.file_path and os.path.exists(result.file_path):
os.unlink(result.file_path)
@allure.title("测试文件下载 - TDD Red阶段")
@allure.description("验证文件下载功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.CRITICAL)
@pytest.mark.smoke
def test_file_download(self) -> None:
"""
TDD Red阶段: 测试文件下载
预期结果:
- 能够下载已上传的文件
- 返回文件内容
- 支持断点续传
"""
from core.file_handler import FileUploader, FileDownloader
with allure.step("Step 1: 上传测试文件"):
uploader = FileUploader(upload_dir="/tmp/test_uploads")
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write("下载测试内容")
test_file_path = f.name
with open(test_file_path, 'rb') as f:
upload_result = uploader.upload(f, filename="download_test.txt")
allure.attach("✅ 上传测试文件", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 下载文件"):
# 使用同一个存储管理器
downloader = FileDownloader(storage_manager=uploader._storage)
download_result = downloader.download(upload_result.file_id)
allure.attach(f"✅ 下载结果: {download_result.success}", "步骤2", allure.attachment_type.TEXT)
assert download_result.success is True, "文件下载应该成功"
with allure.step("Step 3: 验证文件内容"):
content = download_result.content.decode('utf-8')
assert content == "下载测试内容", f"文件内容不匹配: {content}"
allure.attach(f"✅ 文件内容验证通过", "步骤3", allure.attachment_type.TEXT)
with allure.step("Step 4: 清理"):
os.unlink(test_file_path)
@allure.title("测试文件类型验证 - TDD Red阶段")
@allure.description("验证文件类型检查功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.CRITICAL)
@pytest.mark.smoke
def test_file_type_validation(self) -> None:
"""
TDD Red阶段: 测试文件类型验证
预期结果:
- 允许合法文件类型
- 拒绝非法文件类型
- 支持MIME类型检查
"""
from core.file_handler import FileUploader, FileTypeValidator
with allure.step("Step 1: 创建文件类型验证器"):
validator = FileTypeValidator(allowed_extensions=['.txt', '.pdf', '.jpg'])
allure.attach("✅ 创建文件类型验证器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 测试合法文件类型"):
is_valid = validator.validate("document.txt")
allure.attach(f"✅ txt文件验证: {is_valid}", "步骤2", allure.attachment_type.TEXT)
assert is_valid is True, "txt文件应该被允许"
with allure.step("Step 3: 测试非法文件类型"):
is_valid = validator.validate("script.exe")
allure.attach(f"✅ exe文件验证: {is_valid}", "步骤3", allure.attachment_type.TEXT)
assert is_valid is False, "exe文件应该被拒绝"
@allure.title("测试文件大小限制 - TDD Red阶段")
@allure.description("验证文件大小限制功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.NORMAL)
@pytest.mark.regression
def test_file_size_limit(self) -> None:
"""
TDD Red阶段: 测试文件大小限制
预期结果:
- 允许小于限制的文件
- 拒绝超过限制的文件
"""
from core.file_handler import FileUploader, FileSizeValidator
with allure.step("Step 1: 创建文件大小验证器"):
validator = FileSizeValidator(max_size=1024) # 1KB
allure.attach("✅ 创建文件大小验证器(max_size=1KB)", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 测试小文件"):
is_valid = validator.validate(512) # 512 bytes
allure.attach(f"✅ 512字节文件: {is_valid}", "步骤2", allure.attachment_type.TEXT)
assert is_valid is True, "小文件应该被允许"
with allure.step("Step 3: 测试大文件"):
is_valid = validator.validate(2048) # 2KB
allure.attach(f"✅ 2KB文件: {is_valid}", "步骤3", allure.attachment_type.TEXT)
assert is_valid is False, "大文件应该被拒绝"
@allure.title("测试文件名安全验证 - TDD Red阶段")
@allure.description("验证文件名安全检查功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.CRITICAL)
@pytest.mark.smoke
def test_filename_security(self) -> None:
"""
TDD Red阶段: 测试文件名安全验证
预期结果:
- 检测路径遍历攻击
- 过滤危险字符
- 生成安全文件名
"""
from core.file_handler import FilenameSanitizer
with allure.step("Step 1: 创建文件名净化器"):
sanitizer = FilenameSanitizer()
allure.attach("✅ 创建文件名净化器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 测试路径遍历攻击"):
safe_name = sanitizer.sanitize("../../../etc/passwd")
allure.attach(f"✅ 净化结果: {safe_name}", "步骤2", allure.attachment_type.TEXT)
assert ".." not in safe_name, "路径遍历应该被阻止"
with allure.step("Step 3: 测试危险字符"):
safe_name = sanitizer.sanitize("file;rm -rf /|.txt")
allure.attach(f"✅ 净化结果: {safe_name}", "步骤3", allure.attachment_type.TEXT)
assert ";" not in safe_name and "|" not in safe_name, "危险字符应该被移除"
@allure.title("测试文件存储管理 - TDD Red阶段")
@allure.description("验证文件存储管理功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.NORMAL)
@pytest.mark.regression
def test_file_storage_management(self) -> None:
"""
TDD Red阶段: 测试文件存储管理
预期结果:
- 支持多种存储后端
- 文件元数据管理
- 文件删除和清理
"""
from core.file_handler import FileStorageManager
with allure.step("Step 1: 创建存储管理器"):
manager = FileStorageManager(storage_dir="/tmp/test_storage")
allure.attach("✅ 创建存储管理器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 保存文件"):
file_id = manager.save("测试内容".encode('utf-8'), filename="test.txt")
allure.attach(f"✅ 保存文件,ID: {file_id}", "步骤2", allure.attachment_type.TEXT)
assert file_id is not None, "应该有文件ID"
with allure.step("Step 3: 获取文件"):
content = manager.get(file_id)
allure.attach(f"✅ 获取文件内容", "步骤3", allure.attachment_type.TEXT)
assert content == "测试内容".encode('utf-8'), "文件内容应该匹配"
with allure.step("Step 4: 删除文件"):
deleted = manager.delete(file_id)
allure.attach(f"✅ 删除结果: {deleted}", "步骤4", allure.attachment_type.TEXT)
assert deleted is True, "文件应该被删除"
@allure.title("测试文件批量操作 - TDD Red阶段")
@allure.description("验证文件批量操作功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.NORMAL)
@pytest.mark.regression
def test_file_batch_operations(self) -> None:
"""
TDD Red阶段: 测试文件批量操作
预期结果:
- 支持批量上传
- 支持批量删除
- 支持批量下载
"""
from core.file_handler import FileUploader
with allure.step("Step 1: 创建文件上传器"):
uploader = FileUploader(upload_dir="/tmp/test_batch")
allure.attach("✅ 创建文件上传器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 批量上传"):
files = []
for i in range(3):
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write(f"文件{i}内容")
files.append(f.name)
results = uploader.upload_batch(files)
allure.attach(f"✅ 批量上传: {len(results)}个文件", "步骤2", allure.attachment_type.TEXT)
assert len(results) == 3, "应该上传3个文件"
with allure.step("Step 3: 清理"):
for f in files:
if os.path.exists(f):
os.unlink(f)
@allure.title("测试文件元数据管理 - TDD Red阶段")
@allure.description("验证文件元数据管理功能 - 期望失败(Red)")
@allure.severity(allure.severity_level.NORMAL)
@pytest.mark.regression
def test_file_metadata(self) -> None:
"""
TDD Red阶段: 测试文件元数据管理
预期结果:
- 记录文件元数据
- 支持元数据查询
- 支持元数据更新
"""
from core.file_handler import FileStorageManager
with allure.step("Step 1: 创建存储管理器"):
manager = FileStorageManager(storage_dir="/tmp/test_metadata")
allure.attach("✅ 创建存储管理器", "步骤1", allure.attachment_type.TEXT)
with allure.step("Step 2: 保存文件带元数据"):
file_id = manager.save(
"测试内容".encode('utf-8'),
filename="test.txt",
metadata={"author": "test_user", "tags": ["test", "demo"]}
)
allure.attach(f"✅ 保存文件,ID: {file_id}", "步骤2", allure.attachment_type.TEXT)
with allure.step("Step 3: 获取元数据"):
metadata = manager.get_metadata(file_id)
allure.attach(f"✅ 元数据: {metadata}", "步骤3", allure.attachment_type.TEXT)
assert metadata is not None, "应该有元数据"
assert metadata.get("author") == "test_user", "作者信息应该匹配"
with allure.step("Step 4: 清理"):
manager.delete(file_id)