deep-risk/backend/tests/services/risk_detection/engine/test_execution_plan.py
2025-12-14 20:08:27 +08:00

538 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
执行计划器单元测试
"""
import pytest
from unittest.mock import Mock, MagicMock
from datetime import datetime
from app.models.risk_detection import DetectionRule
from app.services.risk_detection.engine.execution_plan import (
ExecutionMode,
ExecutionNode,
ExecutionStage,
ExecutionPlan,
ExecutionPlanner,
ExecutionPlanBuilder,
)
class TestExecutionMode:
"""执行模式枚举测试"""
def test_execution_mode_values(self):
"""测试执行模式值"""
assert ExecutionMode.SEQUENTIAL == "sequential"
assert ExecutionMode.PARALLEL == "parallel"
assert ExecutionMode.HYBRID == "hybrid"
class TestExecutionNode:
"""执行节点测试"""
def test_init(self):
"""测试节点初始化"""
rule = Mock(spec=DetectionRule)
rule.rule_id = "rule_1"
node = ExecutionNode(
node_id="node_1",
rule_id="rule_1",
rule=rule,
level=0,
dependencies=["node_0"],
dependents=["node_2"]
)
assert node.node_id == "node_1"
assert node.rule_id == "rule_1"
assert node.rule == rule
assert node.level == 0
assert node.dependencies == ["node_0"]
assert node.dependents == ["node_2"]
def test_to_dict(self):
"""测试转换为字典"""
rule = Mock(spec=DetectionRule)
rule.rule_id = "rule_1"
rule.rule_name = "规则1"
rule.algorithm_code = "ALGO_1"
node = ExecutionNode(
node_id="node_1",
rule_id="rule_1",
rule=rule,
level=1,
dependencies=["node_0"],
dependents=["node_2"]
)
result = node.to_dict()
assert result["node_id"] == "node_1"
assert result["rule_id"] == "rule_1"
assert result["algorithm_code"] == "ALGO_1"
assert result["algorithm_name"] == "规则1"
assert result["level"] == 1
assert result["dependencies"] == ["node_0"]
assert result["dependents"] == ["node_2"]
class TestExecutionStage:
"""执行阶段测试"""
def setup_method(self):
"""每个测试方法前执行"""
self.rule = Mock(spec=DetectionRule)
self.rule.rule_id = "rule_1"
self.node = ExecutionNode(
node_id="node_1",
rule_id="rule_1",
rule=self.rule,
level=0
)
def test_init(self):
"""测试阶段初始化"""
stage = ExecutionStage(
stage_id="stage_1",
stage_name="阶段1",
nodes=[self.node],
execution_mode=ExecutionMode.PARALLEL,
level=0,
depends_on=["stage_0"]
)
assert stage.stage_id == "stage_1"
assert stage.stage_name == "阶段1"
assert stage.nodes == [self.node]
assert stage.execution_mode == ExecutionMode.PARALLEL
assert stage.level == 0
assert stage.depends_on == ["stage_0"]
def test_rules_property(self):
"""测试rules属性"""
stage = ExecutionStage(
stage_id="stage_1",
stage_name="阶段1",
nodes=[self.node],
execution_mode=ExecutionMode.PARALLEL
)
assert stage.rules == [self.rule]
def test_rule_count_property(self):
"""测试rule_count属性"""
stage = ExecutionStage(
stage_id="stage_1",
stage_name="阶段1",
nodes=[self.node],
execution_mode=ExecutionMode.PARALLEL
)
assert stage.rule_count == 1
def test_to_dict(self):
"""测试转换为字典"""
stage = ExecutionStage(
stage_id="stage_1",
stage_name="阶段1",
nodes=[self.node],
execution_mode=ExecutionMode.PARALLEL,
level=0,
depends_on=["stage_0"]
)
result = stage.to_dict()
assert result["stage_id"] == "stage_1"
assert result["stage_name"] == "阶段1"
assert result["level"] == 0
assert result["execution_mode"] == "parallel"
assert result["rule_count"] == 1
assert result["depends_on"] == ["stage_0"]
assert len(result["nodes"]) == 1
class TestExecutionPlan:
"""执行计划测试"""
def setup_method(self):
"""每个测试方法前执行"""
self.rule = Mock(spec=DetectionRule)
self.rule.rule_id = "rule_1"
self.node = ExecutionNode(
node_id="node_1",
rule_id="rule_1",
rule=self.rule,
level=0
)
self.stage = ExecutionStage(
stage_id="stage_1",
stage_name="阶段1",
nodes=[self.node],
execution_mode=ExecutionMode.PARALLEL
)
def test_init(self):
"""测试计划初始化"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage],
execution_mode=ExecutionMode.HYBRID,
total_rules=1,
max_level=0
)
assert plan.plan_id == "plan_1"
assert plan.task_id == "task_1"
assert plan.entity_id == "entity_1"
assert plan.entity_type == "type_1"
assert plan.period == "2024-01"
assert plan.stages == [self.stage]
assert plan.execution_mode == ExecutionMode.HYBRID
assert plan.total_rules == 1
assert plan.max_level == 0
def test_get_stage(self):
"""测试获取阶段"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage]
)
stage = plan.get_stage("stage_1")
assert stage == self.stage
stage = plan.get_stage("nonexistent")
assert stage is None
def test_get_stages_by_level(self):
"""测试按层级获取阶段"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage]
)
stages = plan.get_stages_by_level(0)
assert stages == [self.stage]
def test_get_next_stage_no_completed(self):
"""测试获取下一个阶段(无已完成)"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage]
)
next_stage = plan.get_next_stage([])
assert next_stage == self.stage
def test_get_next_stage_with_completed(self):
"""测试获取下一个阶段(有已完成)"""
stage2 = ExecutionStage(
stage_id="stage_2",
stage_name="阶段2",
nodes=[],
execution_mode=ExecutionMode.PARALLEL,
depends_on=["stage_1"]
)
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage, stage2]
)
# stage_1未完成stage_2不能执行
next_stage = plan.get_next_stage([])
assert next_stage == self.stage
# stage_1已完成stage_2可以执行
next_stage = plan.get_next_stage(["stage_1"])
assert next_stage == stage2
def test_get_execution_summary(self):
"""测试获取执行摘要"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage],
execution_mode=ExecutionMode.HYBRID,
total_rules=1,
max_level=0
)
summary = plan.get_execution_summary()
assert summary["plan_id"] == "plan_1"
assert summary["task_id"] == "task_1"
assert summary["entity_id"] == "entity_1"
assert summary["entity_type"] == "type_1"
assert summary["period"] == "2024-01"
assert summary["execution_mode"] == "hybrid"
assert summary["total_stages"] == 1
assert summary["total_rules"] == 1
assert summary["max_level"] == 0
assert summary["stages_per_level"] == {0: 1}
assert summary["max_parallelism"] == 1
def test_to_dict(self):
"""测试转换为字典"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[self.stage],
execution_mode=ExecutionMode.HYBRID,
total_rules=1,
max_level=0
)
result = plan.to_dict()
assert result["plan_id"] == "plan_1"
assert result["task_id"] == "task_1"
assert result["entity_id"] == "entity_1"
assert result["entity_type"] == "type_1"
assert result["period"] == "2024-01"
assert result["execution_mode"] == "hybrid"
assert result["total_stages"] == 1
assert result["total_rules"] == 1
assert result["max_level"] == 0
assert len(result["stages"]) == 1
assert "summary" in result
assert "created_at" in result
class TestExecutionPlanner:
"""执行计划器测试"""
def setup_method(self):
"""每个测试方法前执行"""
self.planner = ExecutionPlanner()
# 创建模拟规则
self.rule1 = Mock(spec=DetectionRule)
self.rule1.rule_id = "rule_1"
self.rule1.algorithm_code = "ALGO_1"
self.rule2 = Mock(spec=DetectionRule)
self.rule2.rule_id = "rule_2"
self.rule2.algorithm_code = "ALGO_2"
def test_init(self):
"""测试初始化"""
assert self.planner is not None
assert self.planner.dependency_resolver is not None
def test_create_sequential_plan(self):
"""测试创建串行执行计划"""
rules = [self.rule1, self.rule2]
plan = self.planner._create_sequential_plan(
"task_1", "entity_1", "type_1", "2024-01", rules
)
assert plan.task_id == "task_1"
assert plan.entity_id == "entity_1"
assert plan.entity_type == "type_1"
assert plan.period == "2024-01"
assert plan.execution_mode == ExecutionMode.SEQUENTIAL
assert plan.total_rules == 2
assert plan.max_level == 0
assert len(plan.stages) == 1
stage = plan.stages[0]
assert stage.execution_mode == ExecutionMode.SEQUENTIAL
assert stage.rule_count == 2
assert len(stage.nodes) == 2
def test_create_parallel_plan(self):
"""测试创建并行执行计划"""
rules = [self.rule1, self.rule2]
plan = self.planner._create_parallel_plan(
"task_1", "entity_1", "type_1", "2024-01", rules
)
assert plan.task_id == "task_1"
assert plan.execution_mode == ExecutionMode.PARALLEL
assert plan.total_rules == 2
assert len(plan.stages) == 1
stage = plan.stages[0]
assert stage.execution_mode == ExecutionMode.PARALLEL
assert len(stage.nodes) == 2
def test_create_hybrid_plan(self):
"""测试创建混合执行计划"""
rules = [self.rule1, self.rule2]
# 模拟无依赖的情况
plan = self.planner._create_hybrid_plan(
"task_1", "entity_1", "type_1", "2024-01", rules
)
assert plan.task_id == "task_1"
assert plan.execution_mode == ExecutionMode.HYBRID
assert plan.total_rules == 2
def test_create_plan_sequential_mode(self):
"""测试创建执行计划(串行模式)"""
rules = [self.rule1, self.rule2]
plan = self.planner.create_plan(
"task_1", "entity_1", "type_1", "2024-01", rules,
ExecutionMode.SEQUENTIAL
)
assert plan.execution_mode == ExecutionMode.SEQUENTIAL
def test_create_plan_parallel_mode(self):
"""测试创建执行计划(并行模式)"""
rules = [self.rule1, self.rule2]
plan = self.planner.create_plan(
"task_1", "entity_1", "type_1", "2024-01", rules,
ExecutionMode.PARALLEL
)
assert plan.execution_mode == ExecutionMode.PARALLEL
def test_create_plan_hybrid_mode(self):
"""测试创建执行计划(混合模式)"""
rules = [self.rule1, self.rule2]
plan = self.planner.create_plan(
"task_1", "entity_1", "type_1", "2024-01", rules,
ExecutionMode.HYBRID
)
assert plan.execution_mode == ExecutionMode.HYBRID
def test_optimize_plan(self):
"""测试优化执行计划"""
plan = ExecutionPlan(
plan_id="plan_1",
task_id="task_1",
entity_id="entity_1",
entity_type="type_1",
period="2024-01",
stages=[]
)
optimized = self.planner.optimize_plan(plan)
# 目前优化方法返回原计划
assert optimized == plan
class TestExecutionPlanBuilder:
"""执行计划构建器测试"""
def setup_method(self):
"""每个测试方法前执行"""
self.builder = ExecutionPlanBuilder(
"task_1", "entity_1", "type_1", "2024-01"
)
self.rule = Mock(spec=DetectionRule)
self.rule.rule_id = "rule_1"
self.node = ExecutionNode(
node_id="node_1",
rule_id="rule_1",
rule=self.rule
)
def test_init(self):
"""测试初始化"""
assert self.builder.task_id == "task_1"
assert self.builder.entity_id == "entity_1"
assert self.builder.entity_type == "type_1"
assert self.builder.period == "2024-01"
assert self.builder.stages == []
def test_add_stage(self):
"""测试添加阶段"""
result = self.builder.add_stage(
"阶段1",
[self.node],
ExecutionMode.PARALLEL,
[]
)
# 返回自身,支持链式调用
assert result == self.builder
# 阶段已添加
assert len(self.builder.stages) == 1
stage = self.builder.stages[0]
assert stage.stage_id == "stage_0"
assert stage.stage_name == "阶段1"
assert stage.nodes == [self.node]
assert stage.execution_mode == ExecutionMode.PARALLEL
assert stage.level == 0
assert stage.depends_on == []
def test_add_stage_with_dependencies(self):
"""测试添加带依赖的阶段"""
self.builder.add_stage("阶段1", [self.node])
self.builder.add_stage(
"阶段2",
[self.node],
ExecutionMode.PARALLEL,
["stage_0"]
)
assert len(self.builder.stages) == 2
stage2 = self.builder.stages[1]
assert stage2.stage_id == "stage_1"
assert stage2.level == 1
assert stage2.depends_on == ["stage_0"]
def test_build(self):
"""测试构建执行计划"""
self.builder.add_stage("阶段1", [self.node])
plan = self.builder.build()
assert plan.plan_id == "plan_task_1"
assert plan.task_id == "task_1"
assert plan.entity_id == "entity_1"
assert plan.entity_type == "type_1"
assert plan.period == "2024-01"
assert plan.execution_mode == ExecutionMode.HYBRID
assert plan.total_rules == 1
assert plan.max_level == 0
assert len(plan.stages) == 1