08ea5fbe98
添加用户管理视图、API和状态管理文件
303 lines
14 KiB
Python
303 lines
14 KiB
Python
"""
|
|
审计日志模块测试 - TDD Red阶段
|
|
|
|
测试操作日志记录和JaVers风格的对象变更审计功能。
|
|
"""
|
|
|
|
import pytest
|
|
import allure
|
|
import time
|
|
from typing import Any, Dict, List
|
|
|
|
|
|
@allure.epic("核心框架")
|
|
@allure.feature("审计日志模块 - TDD Red阶段")
|
|
class TestAuditLog:
|
|
"""审计日志模块测试类 - TDD Red阶段(期望失败)"""
|
|
|
|
@allure.title("测试操作日志记录 - TDD Red阶段")
|
|
@allure.description("验证操作日志记录功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.CRITICAL)
|
|
@pytest.mark.smoke
|
|
def test_operation_log_recording(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试操作日志记录
|
|
|
|
预期结果:
|
|
- 能够记录操作日志
|
|
- 包含操作时间、模块、操作人等信息
|
|
- 支持查询操作日志
|
|
"""
|
|
from core.audit_log import OperationLogRecorder
|
|
|
|
with allure.step("Step 1: 创建操作日志记录器"):
|
|
recorder = OperationLogRecorder()
|
|
allure.attach("✅ 创建操作日志记录器", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 记录操作日志"):
|
|
log_entry = recorder.record(
|
|
module_name="用户管理",
|
|
operation_desc="创建用户",
|
|
operator="admin",
|
|
operator_id=1,
|
|
request_method="POST",
|
|
request_path="/api/users",
|
|
request_params='{"username": "test"}',
|
|
ip_address="192.168.1.1",
|
|
execution_time=150,
|
|
status="SUCCESS"
|
|
)
|
|
allure.attach(f"✅ 记录日志: {log_entry}", "步骤2", allure.attachment_type.TEXT)
|
|
assert log_entry is not None, "日志记录应该成功"
|
|
|
|
with allure.step("Step 3: 查询操作日志"):
|
|
logs = recorder.query_logs(module_name="用户管理")
|
|
allure.attach(f"✅ 查询结果: {len(logs)}条日志", "步骤3", allure.attachment_type.TEXT)
|
|
assert len(logs) >= 1, "应该至少有一条日志"
|
|
|
|
@allure.title("测试对象变更审计(JaVers风格) - TDD Red阶段")
|
|
@allure.description("验证对象变更审计功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.CRITICAL)
|
|
@pytest.mark.smoke
|
|
def test_object_change_audit(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试对象变更审计(JaVers风格)
|
|
|
|
预期结果:
|
|
- 能够比较两个对象的差异
|
|
- 记录变更字段和变更值
|
|
- 支持变更历史查询
|
|
"""
|
|
from core.audit_log import ObjectChangeAuditor
|
|
|
|
with allure.step("Step 1: 创建对象变更审计器"):
|
|
auditor = ObjectChangeAuditor()
|
|
allure.attach("✅ 创建对象变更审计器", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 准备测试对象"):
|
|
old_object = {
|
|
"id": 1,
|
|
"username": "zhangsan",
|
|
"email": "zhangsan@old.com",
|
|
"age": 25
|
|
}
|
|
new_object = {
|
|
"id": 1,
|
|
"username": "zhangsan",
|
|
"email": "zhangsan@new.com",
|
|
"age": 26
|
|
}
|
|
allure.attach("✅ 准备新旧对象", "步骤2", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 3: 比较对象差异"):
|
|
diff_result = auditor.compare(old_object, new_object)
|
|
allure.attach(f"✅ 差异结果: {diff_result}", "步骤3", allure.attachment_type.TEXT)
|
|
assert diff_result.has_changes is True, "应该检测到变更"
|
|
assert len(diff_result.changes) == 2, "应该检测到2处变更"
|
|
|
|
with allure.step("Step 4: 获取变更字段"):
|
|
changed_fields = auditor.get_changed_fields(old_object, new_object)
|
|
allure.attach(f"✅ 变更字段: {changed_fields}", "步骤4", allure.attachment_type.TEXT)
|
|
assert "email" in [c.field_name for c in changed_fields], "应该包含email变更"
|
|
assert "age" in [c.field_name for c in changed_fields], "应该包含age变更"
|
|
|
|
@allure.title("测试审计日志存储 - TDD Red阶段")
|
|
@allure.description("验证审计日志存储功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.NORMAL)
|
|
@pytest.mark.regression
|
|
def test_audit_log_storage(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志存储
|
|
|
|
预期结果:
|
|
- 支持内存存储
|
|
- 支持文件存储
|
|
- 支持数据库存储(模拟)
|
|
"""
|
|
from core.audit_log import AuditLogStorage, MemoryAuditStorage
|
|
|
|
with allure.step("Step 1: 创建内存存储"):
|
|
storage = MemoryAuditStorage()
|
|
allure.attach("✅ 创建内存存储", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 存储审计日志"):
|
|
log_entry = {
|
|
"id": "log_001",
|
|
"module_name": "订单管理",
|
|
"operation_desc": "创建订单",
|
|
"operator": "user1",
|
|
"timestamp": time.time()
|
|
}
|
|
storage.save(log_entry)
|
|
allure.attach("✅ 存储审计日志", "步骤2", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 3: 查询审计日志"):
|
|
logs = storage.query(module_name="订单管理")
|
|
allure.attach(f"✅ 查询结果: {len(logs)}条日志", "步骤3", allure.attachment_type.TEXT)
|
|
assert len(logs) == 1, "应该有一条日志"
|
|
assert logs[0]["operator"] == "user1", "操作人应该匹配"
|
|
|
|
@allure.title("测试审计日志过滤和搜索 - TDD Red阶段")
|
|
@allure.description("验证审计日志过滤和搜索功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.NORMAL)
|
|
@pytest.mark.regression
|
|
def test_audit_log_filtering(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志过滤和搜索
|
|
|
|
预期结果:
|
|
- 支持按时间范围过滤
|
|
- 支持按操作人过滤
|
|
- 支持按模块过滤
|
|
- 支持关键字搜索
|
|
"""
|
|
from core.audit_log import OperationLogRecorder
|
|
|
|
with allure.step("Step 1: 创建记录器并添加多条日志"):
|
|
recorder = OperationLogRecorder()
|
|
|
|
# 添加多条日志
|
|
recorder.record(module_name="用户管理", operation_desc="创建用户", operator="admin")
|
|
recorder.record(module_name="用户管理", operation_desc="删除用户", operator="admin")
|
|
recorder.record(module_name="订单管理", operation_desc="创建订单", operator="user1")
|
|
recorder.record(module_name="订单管理", operation_desc="取消订单", operator="user2")
|
|
|
|
allure.attach("✅ 添加4条测试日志", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 按模块过滤"):
|
|
user_logs = recorder.query_logs(module_name="用户管理")
|
|
allure.attach(f"✅ 用户管理日志: {len(user_logs)}条", "步骤2", allure.attachment_type.TEXT)
|
|
assert len(user_logs) == 2, "用户管理应该有2条日志"
|
|
|
|
with allure.step("Step 3: 按操作人过滤"):
|
|
admin_logs = recorder.query_logs(operator="admin")
|
|
allure.attach(f"✅ admin操作日志: {len(admin_logs)}条", "步骤3", allure.attachment_type.TEXT)
|
|
assert len(admin_logs) == 2, "admin应该有2条日志"
|
|
|
|
@allure.title("测试审计日志统计 - TDD Red阶段")
|
|
@allure.description("验证审计日志统计功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.NORMAL)
|
|
@pytest.mark.regression
|
|
def test_audit_log_statistics(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志统计
|
|
|
|
预期结果:
|
|
- 统计操作次数
|
|
- 统计各模块操作分布
|
|
- 统计操作成功率
|
|
"""
|
|
from core.audit_log import OperationLogRecorder, AuditStatistics
|
|
|
|
with allure.step("Step 1: 创建记录器并添加日志"):
|
|
recorder = OperationLogRecorder()
|
|
recorder.record(module_name="用户管理", operation_desc="创建用户", operator="admin", status="SUCCESS")
|
|
recorder.record(module_name="用户管理", operation_desc="删除用户", operator="admin", status="SUCCESS")
|
|
recorder.record(module_name="订单管理", operation_desc="创建订单", operator="user1", status="FAILURE")
|
|
allure.attach("✅ 添加3条测试日志", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 获取统计信息"):
|
|
stats = recorder.get_statistics()
|
|
allure.attach(f"✅ 统计信息: {stats}", "步骤2", allure.attachment_type.TEXT)
|
|
assert stats.total_operations == 3, "总操作数应该是3"
|
|
assert stats.success_count == 2, "成功数应该是2"
|
|
assert stats.failure_count == 1, "失败数应该是1"
|
|
|
|
@allure.title("测试审计日志导出 - TDD Red阶段")
|
|
@allure.description("验证审计日志导出功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.NORMAL)
|
|
@pytest.mark.regression
|
|
def test_audit_log_export(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志导出
|
|
|
|
预期结果:
|
|
- 支持导出为JSON
|
|
- 支持导出为CSV
|
|
- 支持按条件导出
|
|
"""
|
|
from core.audit_log import OperationLogRecorder, AuditLogExporter
|
|
|
|
with allure.step("Step 1: 创建记录器并添加日志"):
|
|
recorder = OperationLogRecorder()
|
|
recorder.record(module_name="用户管理", operation_desc="创建用户", operator="admin")
|
|
recorder.record(module_name="用户管理", operation_desc="更新用户", operator="admin")
|
|
allure.attach("✅ 添加2条测试日志", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 导出为JSON"):
|
|
exporter = AuditLogExporter(recorder)
|
|
json_data = exporter.export_to_json(module_name="用户管理")
|
|
allure.attach(f"✅ JSON导出: {len(json_data)}字符", "步骤2", allure.attachment_type.TEXT)
|
|
assert len(json_data) > 0, "JSON数据不应该为空"
|
|
assert "用户管理" in json_data, "JSON应该包含模块信息"
|
|
|
|
@allure.title("测试审计日志清理 - TDD Red阶段")
|
|
@allure.description("验证审计日志清理功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.NORMAL)
|
|
@pytest.mark.regression
|
|
def test_audit_log_cleanup(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志清理
|
|
|
|
预期结果:
|
|
- 支持按时间清理
|
|
- 支持按数量限制
|
|
- 支持归档旧日志
|
|
"""
|
|
from core.audit_log import OperationLogRecorder
|
|
|
|
with allure.step("Step 1: 创建记录器并添加日志"):
|
|
recorder = OperationLogRecorder()
|
|
for i in range(10):
|
|
recorder.record(module_name="测试模块", operation_desc=f"操作{i}", operator="system")
|
|
allure.attach("✅ 添加10条测试日志", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 验证日志数量"):
|
|
all_logs = recorder.query_logs()
|
|
allure.attach(f"✅ 当前日志数: {len(all_logs)}", "步骤2", allure.attachment_type.TEXT)
|
|
assert len(all_logs) == 10, "应该有10条日志"
|
|
|
|
with allure.step("Step 3: 清理旧日志"):
|
|
deleted_count = recorder.cleanup(max_keep=5)
|
|
allure.attach(f"✅ 清理日志数: {deleted_count}", "步骤3", allure.attachment_type.TEXT)
|
|
|
|
remaining_logs = recorder.query_logs()
|
|
allure.attach(f"✅ 剩余日志数: {len(remaining_logs)}", "步骤3", allure.attachment_type.TEXT)
|
|
assert len(remaining_logs) <= 5, "剩余日志应该不超过5条"
|
|
|
|
@allure.title("测试审计日志装饰器 - TDD Red阶段")
|
|
@allure.description("验证审计日志装饰器功能 - 期望失败(Red)")
|
|
@allure.severity(allure.severity_level.CRITICAL)
|
|
@pytest.mark.smoke
|
|
def test_audit_log_decorator(self) -> None:
|
|
"""
|
|
TDD Red阶段: 测试审计日志装饰器
|
|
|
|
预期结果:
|
|
- 支持函数装饰器自动记录
|
|
- 捕获函数参数和返回值
|
|
- 记录执行时间和异常
|
|
"""
|
|
from core.audit_log import AuditLogRecorder, audit_log
|
|
|
|
with allure.step("Step 1: 创建记录器"):
|
|
recorder = AuditLogRecorder()
|
|
allure.attach("✅ 创建审计日志记录器", "步骤1", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 2: 定义带装饰器的函数"):
|
|
@audit_log(recorder, module_name="测试模块", operation_desc="测试操作")
|
|
def test_function(user_id: int, action: str) -> Dict[str, Any]:
|
|
return {"user_id": user_id, "action": action, "result": "success"}
|
|
|
|
allure.attach("✅ 定义带装饰器的函数", "步骤2", allure.attachment_type.TEXT)
|
|
|
|
with allure.step("Step 3: 执行函数"):
|
|
result = test_function(user_id=1, action="create")
|
|
allure.attach(f"✅ 函数执行结果: {result}", "步骤3", allure.attachment_type.TEXT)
|
|
assert result["result"] == "success", "函数应该正常执行"
|
|
|
|
with allure.step("Step 4: 验证日志记录"):
|
|
logs = recorder.query_logs(module_name="测试模块")
|
|
allure.attach(f"✅ 记录的日志数: {len(logs)}", "步骤4", allure.attachment_type.TEXT)
|
|
assert len(logs) >= 1, "应该至少有一条日志"
|