feat(admin): 添加用户管理相关文件

添加用户管理视图、API和状态管理文件
This commit is contained in:
张翔
2026-03-28 14:37:29 +08:00
commit 08ea5fbe98
1643 changed files with 255646 additions and 0 deletions
@@ -0,0 +1,302 @@
"""
审计日志模块测试 - 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, "应该至少有一条日志"