| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 8 个月前 |
Discovery 测试模块总结
概述
tests/discovery/ 目录包含了设备发现和 CSR(配置状态寄存器)解析相关的核心功能测试,主要包括应用模式(App Schema)、CSR 解析器、CSR 工具函数和根接口四个方面的测试。该模块测试了设备发现流程中的核心组件,确保 CSR 文件能够正确解析并生成可用的设备对象组数据,为设备管理提供基础支持。
源代码结构
对应的源代码位于 src/discovery/ 目录:
-
csr_parser.h / csr_parser.cpp: CSR 解析器核心实现
parse(): 主解析函数,执行完整的解析流程parse_task: 解析任务基类,实现任务链式执行match_task: 拓扑匹配任务(总线映射)rename_task: 对象重命名任务(对象名映射)append_task: 对象追加任务(Connector 预处理)arrange_task: 对象排列任务(依赖关系分析)analyze_task: 对象分析任务(对象解析和函数分发)raw_data_t: 原始数据结构,存储解析过程中的中间数据- 支持函数调用解析、属性引用/同步转换、表达式处理
-
csr_utils.h / csr_utils.cpp: CSR 工具函数实现
- 类型判断函数:
is_sync()、is_ref()、is_func_call()、is_ref_presence() - 目标解析函数:
get_sync_targets()、get_ref_targets() - 字符串替换函数:
replace_sync_objects()、replace_ref_object() - 拓扑转换函数:
convert_topology() - 属性表达式提取:
get_prop_expr() - 辅助函数:
get_class_name()、get_connector_position()、is_prop_type_integer() - Schema 集成函数:
get_instance_info()、get_property_intf() object_group_data: 对象组数据管理类(单例模式)- 对象保存和检索(按 position 和 owner 分组)
- 拓扑数据管理
- 函数对象处理
- 设备对象管理
- 生命周期管理(LifeCycleId)
- 类型判断函数:
-
app_schema.h / app_schema.cpp: 应用模式管理实现
app_schema: 应用模式单例类init(): 初始化应用路径load(): 加载 Schema 文件get_class_info(): 获取类信息(应用名、路径)get_property_intf(): 获取属性接口名get_property_type(): 获取属性类型get_property_origin_name(): 获取属性原始名称(title)
- 支持路径模板替换、上下文变量替换
-
root_interface.h / root_interface.cpp: 根接口实现
root_interface: D-Bus 根接口(bmc.dev)add_device(): 添加设备(CSR 解析 → 设备管理 → 对象组创建)remove_device(): 删除设备(设备管理 → 对象组注销)create_object_group(): 创建对象组对象
- 集成设备管理和 CSR 解析
-
object_group.h / object_group.cpp: 对象组对象实现
object_group: D-Bus 对象组对象object_group_root: 对象组根对象- 提供对象组接口(object_group_interface)
测试文件说明
1. test_app_schema.cpp - 应用模式测试
测试应用模式(App Schema)系统的核心功能,应用模式用于管理设备类定义、属性定义和路径模板,该文件包含了 54 个测试用例:
类信息查询测试(get_class_info)
-
成功场景
- 基本类信息查询(ChassisFruCtrl、FruCtrl、ChildFruCtrl)
- 路径模板替换(支持上下文变量)
- 上下文键值大小写不敏感匹配(全小写、全大写、混合大小写)
-
边界情况
- 类不存在的情况
- 空上下文的情况(返回未替换的路径模板)
- 复杂路径模板(父子关系、多级路径)
- Component 类查询
属性接口查询测试(get_property_intf)
- 查询属性所属的接口名称
- 类不存在的情况
- 属性不存在的情况
- 多接口属性的处理(返回第一个匹配的接口)
- 空接口列表的处理(Event 类)
属性类型查询测试(get_property_type)
- 查询属性的数据类型(String、U8、U16 等)
- 类不存在的情况
- 属性不存在的情况
- Func 类返回空字符串
- 多种类型的属性(allOf 中的多种类型)
属性原始名称查询测试(get_property_origin_name)
- 查询属性的原始名称(通过 title 字段)
- 带 title 的属性返回 title 值
- 不带 title 的属性返回空字符串
- 类或属性不存在的情况
Schema 加载测试(load)
-
正常加载
- 加载多个路径
- 空路径列表处理
- 通过 init 方法加载多个应用路径
-
错误处理
- 不存在的路径(记录错误但不抛异常)
- 文件作为目录处理
- 不存在的 schema 文件
- 无效的 JSON 格式
- 缺失字段处理(无 defs、无 properties、无 interfaces、无 path)
- 类型错误处理(非对象 defs、非对象 properties、非字符串 path 等)
- 非数组 allOf 和非字符串 $ref
- 空 schema 文件
单例模式测试
- 验证 get_instance 返回同一个实例
2. test_csr_parser.cpp - CSR 解析器测试
CSR 解析器是设备发现的核心组件,负责解析 CSR 文件并生成对象组数据,该文件包含了 35 个测试用例:
对象排列任务测试(arrange_task)
-
依赖关系分析
- 统计对象的引用计数
- 识别被引用对象
- 构建对象创建队列(按依赖顺序排序)
-
排序算法
- 无依赖对象优先
- 被引用对象在引用对象之前
- 多级依赖关系的正确处理
CSR 解析测试(parse)
-
基础解析
- 解析不含设备对象的 CSR 文件
- 解析含设备对象的 CSR 文件
- 对象分组(cooling、general_hardware、frudata、event 等)
- 对象属性提取和序列化
- 扩展属性处理(Bom、BoardId、AuxId 等)
-
对象组数据验证
- Owners 列表正确性
- ObjectIdentifier 正确性
- 通过 D-Bus 接口查询对象组数据
- LifeCycleId 管理
函数调用解析测试(Func Call Parsing)
-
基础函数调用
- 简单函数调用($Func_test({x: 1, y: 2}))
- 嵌套函数调用($Func_outer({nested: $Func_inner({z: 1})}))
- 混合参数(引用、同步、静态值)
- 函数调用转换为 $func: 格式
-
函数参数类型
- 引用参数(#/Object.Property)
- 同步参数(<=/Object.Property)
- 静态值参数
- 混合参数类型的函数
-
函数对象分发
- 函数对象创建和分发
- 同组件内引用转换为 $local: 格式
- 跨组件同步转换为 $sync: 格式
- 多应用函数分发(同一函数被多个应用使用)
拓扑匹配测试(Topology Matching)
-
拓扑解析
- Anchor 节点识别
- 总线映射(ManagementTopology 中的 Buses 与 Connector 中的 Buses 匹配)
- 总线数量不匹配的处理(记录警告但不抛异常)
-
拓扑数据结构
- 拓扑信息的保存和检索
- 连接器预处理(Connector 对象)
变量替换测试
- CSR 文件中的变量替换(${VariableName})
- DataVersion、FormatVersion 等变量的替换
属性引用和同步测试
-
引用属性(Reference)
- 对象引用(#/Object)
- 属性引用(#/Object.Property)
- 引用转换为 $ref: 格式(带 Service 和 Path)
-
同步属性(Sync)
- 简单同步(<=/Object.Property)
- 同步属性转换为 $sync: 格式
- 同步属性默认值处理
- 同步属性数量限制(最多 10 个)
表达式处理测试
- 管道符表达式(|> expr(...))
- 表达式中的条件逻辑
- 包含 > 符号的值转换为 $const: 格式
边界情况和错误处理
-
循环引用检测
- 对象之间的循环引用(Object_A 引用 Object_B,Object_B 引用 Object_A)
- 自引用检测(对象引用自身属性)
- 多个父对象检测(一个对象有多个 @Parent 标记)
- 循环引用不会抛出异常,但会被忽略
-
特殊对象处理
- 空对象处理(空属性对象)
- 父子关系处理(@Parent 标记)
- Framework 标记的对象(Scanner、Chip 等)
- 忽略的对象类(Accessor、Scanner、Cont、ContBin、Median)不会出现在解析结果中
-
RENAME_PROPS 处理
- 特殊类的属性重命名(SmcDfxInfo 等)
-
同步属性限制
- 同步属性数量限制(最多 10 个,超过限制会被忽略)
-
表达式处理
- 包含
>符号的值转换为$const:格式(避免与管道符表达式冲突)
- 包含
复杂场景测试
- 函数调用的复杂嵌套(多级嵌套函数调用)
- 混合引用和同步属性(同一对象同时使用引用和同步)
- 多应用对象分发(同一对象被多个应用使用)
- 同步属性默认值处理(同步属性为空时的默认值)
- 带设备对象的 CSR 解析(验证设备对象创建和 D-Bus 集成)
- 使用 test_expr.sr 进行函数解析,覆盖各种函数场景(引用参数、同步参数、混合参数)
任务链测试
-
rename_task 测试
- 变量替换功能(DataVersion、FormatVersion、SystemId、Slot 等)
- 对象名重命名(拓扑匹配后的对象名映射)
- RENAME_PROPS 处理
- 引用和同步属性中的对象名替换
-
append_task 测试
- Connector 对象预处理
- E2P 对象追加
-
parse_task 异常处理测试
- 无效 CSR 数据结构处理
- 空 ManagementTopology 处理
- ManagementTopology 中非数组类型处理
- 数字类型变量替换处理
3. test_csr_utils.cpp - CSR 工具函数测试
测试 CSR 处理过程中的工具函数,这些函数提供了 CSR 解析所需的基础功能:
类型判断函数
-
is_sync:判断是否为同步属性(<=/ 开头)
- 支持全局标记(<=/::)
- 空字符串和普通字符串的区分
-
is_ref:判断是否为引用属性(#/ 开头)
- 支持全局标记(#/::)
- 对象引用和属性引用
-
is_func_call:判断是否为函数调用($Func_ 开头)
- 正确的函数调用格式识别
- 错误格式的拒绝
-
is_ref_presence:判断是否为 Connector 的 Presence 属性引用
目标解析函数
-
get_sync_targets:解析同步属性目标
- 简单同步目标(<=/object.prop)
- 全局同步目标(<=/::object.prop)
- 多个同步目标(<=/obj1.prop1 <=/obj2.prop2)
- 带接口名的同步目标(<=/object[interface.name].prop)
- 空字符串和无效格式的处理
-
get_ref_targets:解析引用属性目标
- 对象引用(#/object)
- 属性引用(#/object.prop)
- 全局引用(#/::object)
- 带接口名的引用(#/object[interface.name].prop)
字符串替换函数
-
replace_sync_objects:替换同步属性中的对象名
- 对象名映射替换
- 全局标记的对象不替换
- 同名对象多次出现的替换
- 表达式中的对象名替换(保留管道符和表达式)
-
replace_ref_object:替换引用属性中的对象名
- 对象引用替换
- 属性引用替换
- 全局标记的对象不替换
拓扑转换函数
- convert_topology:转换拓扑结构
- 将嵌套的 Buses/Chips 结构转换为数组格式
- 多级递归处理
- Anchor 节点识别
- 空数组处理
- 无效拓扑处理(无 Anchor)
属性表达式提取函数
- get_prop_expr:提取属性值中的表达式
- 管道符表达式提取(|> expr(...))
- 多个表达式提取
- 表达式级别限制(默认最多 10 个)
- 空字符串和无表达式字符串的处理
辅助函数
-
get_class_name:从对象名提取类名(去除后缀数字)
- 正常对象名(Object_1 -> Object)
- 边界情况(Object_、_Object、Object_1_2)
-
get_connector_position:从 Connector 获取位置信息
- 整数位置转换(26 -> "1A")
- 字符串位置直接返回
- 缺失位置的处理
-
is_prop_type_integer:判断属性类型是否为整数
- 基于 schema 查询属性类型
- 多种类的属性类型判断
对象组数据管理测试(object_group_data)
-
对象保存和检索
- save_objects 和 get_objects
- 多个应用的对象分组
- 对象属性序列化(ObjectProps)
- 扩展属性序列化(ObjectExtends)
- 空对象列表处理
-
函数对象处理
- 函数对象保存和分发
- 多应用函数对象分发
- 函数对象的参数转换(local:、local:、sync:)
-
拓扑数据管理
- save_topology 和 get_topology
- 拓扑数据的保存和检索
-
Owners 管理
- get_owners 返回对象的所有者列表
- 空位置的处理
-
生命周期管理
- LifeCycleId 递增机制
- 每次保存对象时 LifeCycleId 自动递增
-
设备对象管理
- is_device_object 判断
- get_device_object 获取
- clear_device_objects 清理
-
Connector 特殊处理
- Connector 类的 SystemId 类型转换(字符串 -> 整数)
Schema 集成函数
-
get_instance_info:获取对象实例信息
- 基于 schema 获取应用名和路径
- 不存在的类的处理
- 带设备对象的实例信息获取
-
get_property_intf:获取属性接口信息
- 基于 schema 查询
- 基于 ref_sync_target 查询(优先使用接口名)
- 不存在的对象和属性的处理
对象组接口测试
-
GetObjects 方法测试
- 正常对象查询
- 空 owner 处理
- 多个对象的正确返回
-
GetTopology 方法测试
- 拓扑数据查询
- 不存在位置的查询
并发和边界测试
-
并发访问测试
- 模拟并发写入场景
- 数据一致性验证
-
边界情况测试
- 多个 owner 的对象管理
- 设备对象管理接口测试
- 清空设备对象测试
4. test_root_interface.cpp - 根接口测试
该文件定义了根接口测试的基础测试类,目前作为测试框架的基础设施使用,为未来的根接口测试预留接口。
测试统计
该测试模块共包含 137 个测试用例:
- test_app_schema.cpp: 54 个测试用例(应用模式功能)
- test_csr_parser.cpp: 35 个测试用例(CSR 解析器功能)
- test_csr_utils.cpp: 48 个测试用例(CSR 工具函数功能)
测试覆盖范围
该测试模块全面覆盖了设备发现和 CSR 解析的核心功能:
- ✅ 应用模式管理和查询(类信息、属性信息)
- ✅ CSR 文件解析和对象生成
- ✅ 对象依赖关系分析和排序
- ✅ 函数调用解析和转换
- ✅ 属性引用和同步处理
- ✅ 拓扑匹配和转换
- ✅ 变量替换和表达式处理
- ✅ 对象组数据管理
- ✅ D-Bus 集成测试
- ✅ 边界情况和错误处理
- ✅ 工具函数的正确性
测试工具和基础设施
- TestBase 继承:所有测试类继承自
mc::test::TestWithEngine,提供统一的测试环境 - 应用模式初始化:测试中初始化 app_schema,加载测试用的应用定义文件
- 对象组数据重置:每个测试用例前后重置 object_group_data,确保测试隔离
- D-Bus 集成:测试中集成了 D-Bus 通信,验证对象组接口的正确性
- 设备驱动模拟:使用 test_driver 和 mock_topology_driver 模拟设备驱动
- 测试隔离机制:
- 每个测试用例后清理对象表(多次清理确保对象被完全删除)
- 清空 func_collection 缓存(避免测试用例间相互影响)
- 移除测试驱动(确保驱动状态干净)
- 对象组数据重置(使用
object_group_data::reset_for_test()) - 临时文件清理(Schema 加载测试中创建的临时目录和文件)
运行测试
测试使用 Google Test 框架编写,可以通过 meson 构建系统运行:
meson setup builddir
meson compile -C builddir
meson test -C builddir
测试数据依赖
测试依赖于以下测试数据文件:
../tests/tests_data/csr/:CSR 测试文件目录test_expr.sr:函数表达式测试文件test_csr_with_device_objects.sr:带设备对象的 CSR 测试文件- 其他 CSR 测试文件
../tests/tests_data/apps/:应用模式定义文件目录test_devices/:测试设备应用定义目录
关键特性
任务链模式
CSR 解析器采用任务链模式(Chain of Responsibility),每个任务负责特定的解析步骤:
- parse_task 基类:提供任务执行框架(
run()、next()、run_and_next()) - 异常安全:每个任务都有异常处理,任务失败不会中断整个解析流程
- 链式执行:任务通过
next()方法链式执行,支持灵活的流程控制 - 数据共享:所有任务共享
raw_data_t数据结构,存储解析过程中的中间数据
CSR 解析流程
CSR 解析器实现了完整的解析流程(采用任务链模式):
- 拓扑匹配(match_task):匹配拓扑结构,建立总线映射(ManagementTopology.Anchor.Buses ↔ Connector.Buses)
- 对象重命名(rename_task):根据总线映射重命名对象,处理对象名映射
- 对象追加(append_task):预处理 Connector 对象,追加 E2P 对象
- 对象排列(arrange_task):分析对象依赖关系,按正确顺序排列(被引用对象优先)
- 对象分析(analyze_task):解析对象属性,处理引用/同步转换,函数对象分发
- 对象保存:将解析结果保存到 object_group_data,供对象组接口使用
函数调用解析
系统支持强大的函数调用机制(analyze_task 处理):
- 函数调用格式:
$Func_functionName({param1: value1, param2: value2}) - 参数类型:支持引用参数(#/Object.Property)、同步参数(<=/Object.Property)、静态值
- 函数对象分发:函数调用被转换为函数对象(
parsed_sr_func_object),并分发到相应的应用- 支持多应用函数分发(同一函数被多个应用使用)
- 函数对象保存在
object_group_data中,按应用分组
- 参数转换:同组件内引用转换为
$local:格式,跨组件同步转换为$sync:格式 - 嵌套函数调用:支持多级嵌套函数调用(
$Func_outer({nested: $Func_inner({z: 1})})) - 函数对象识别:通过类名判断是否为函数对象(Func 类)
对象依赖关系分析
CSR 解析器实现了智能的对象依赖关系分析(arrange_task):
- 引用计数:统计每个对象被引用的次数(
objs_ref_info.ref_count) - 依赖排序:被引用对象优先于引用对象创建(引用计数为 0 的对象优先)
- 循环检测:检测并报告对象间的循环引用(不会抛出异常,但会被忽略)
- 自引用检测:检测对象的自引用情况(对象引用自身属性)
- 多父对象检测:检测对象是否有多个父对象(多个 @Parent 标记)
- 引用对象追踪:记录每个对象被哪些对象引用(
objs_ref_info.ref_objects)
Schema 路径模板系统
应用模式支持灵活的路径模板(app_schema::get_class_info()):
- 路径模板:使用
${VariableName}语法定义路径模板 - 上下文替换:通过上下文字典(context)替换模板变量
- 支持的变量:SystemId、ManagerId、ChassisId、Id、GroupPosition 等
- 大小写不敏感:上下文键值匹配不区分大小写(全小写、全大写、混合大小写)
- 多级路径:支持父子关系的复杂路径模板
- 默认值处理:未提供的变量使用空字符串或默认值
关键数据结构
-
raw_data_t:解析过程中的原始数据结构
m_bus_map:总线名称映射(模板总线名 → connector 总线名)m_extra_buses:额外的总线列表(connector 中未匹配的总线)m_objects_queue:对象创建队列(按依赖顺序排序)m_context:上下文变量(用于变量替换)m_management_topology:管理拓扑(可选)m_objects:对象数据(可选)
-
parsed_sr_object:解析后的对象结构
app_name:应用名class_name:类名object_name:对象名path:对象路径object_props:对象属性(序列化为 JSON)extra_props:扩展属性(序列化为 JSON)ref_presence:是否为引用存在性属性
-
parsed_sr_func_object:解析后的函数对象结构
app_names:应用名列表(支持多应用)class_name:类名(Func)object_name:对象名object_props:函数属性(包含转换后的参数)
-
instance_info_t:对象实例信息
app:应用名path:对象路径framework:是否为框架对象ref_presence:是否为引用存在性属性parent:父对象名object_name:对象名references:引用列表
对象组数据管理
系统实现了完整的对象组数据管理(object_group_data 单例类):
- 对象分组:按应用(owner)对对象进行分组,每个应用拥有独立的对象列表(二层哈希表:position → owner → object_group_t)
- 对象标识:使用 ObjectIdentifier(SystemId、ManagerId、ChassisId、Position)标识对象组
- 生命周期管理:LifeCycleId 自动递增,每次保存对象时递增,追踪对象组变更历史
- 函数对象管理:函数对象被正确创建和分发到多个应用,支持多应用函数分发
- 函数参数转换:同组件内引用转换为
$local:格式,跨组件同步转换为$sync:格式
- 函数参数转换:同组件内引用转换为
- 拓扑数据管理:拓扑信息被保存和检索,支持空拓扑和不存在的拓扑查询(独立互斥锁保护)
- 扩展属性处理:对象扩展属性(extra_props)被序列化到 ObjectExtends 字段(JSON 格式)
- 特殊类型转换:Connector 类的 SystemId 从字符串自动转换为整数类型
- 空对象处理:支持保存空对象列表,不会出错
- 设备对象管理:设备对象映射(position → object_name → abstract_object*),支持设备对象查询和清理
- 线程安全:使用互斥锁保护对象组数据、拓扑数据和设备对象映射