OpenBMC 自动化测试中的多进程陷阱:从 Execute Process 返回异常到 output.xml 损坏问题分析

在 OpenBMC 测试自动化框架中,Robot Framework 经常被用于执行 BMC 功能测试、压力测试以及稳定性测试。

为了提升测试效率,openbmc-test-automation 提供了基于 Python multiprocessing 的并发执行能力,通过 Execute Process 同时启动多个测试任务,对 BMC 的 REST、SSH、IPMI 服务进行压力验证。

然而,在实际使用过程中,发现该多进程测试框架存在两个比较隐蔽的问题:

  1. 多进程执行结果返回异常,导致测试结果误判;
  2. 测试执行成功,但生成的 Robot Framework output.xml 文件损坏。

本文记录问题定位过程、根因分析以及最终解决方案。


一、问题背景

测试用例:

复制代码
复制代码
extended/test_bmc_stress_buster.robot

该测试用于验证 BMC 在高并发访问下的稳定性。

例如 IPMI stress 测试:

复制代码
复制代码
Stress BMC IPMI Server
    [Documentation]  Execute maximum allowed IPMI operation.

    ${dict}=    Execute Process
    ...    ${IPMI_BUSTER_MAX}
    ...    IPMI Check Status

    Dictionary Should Not Contain Value
    ...    ${dict}
    ...    False

其中:

  • IPMI_BUSTER_MAX 控制并发数量;
  • Execute Process 来自:
复制代码
复制代码
lib/jobs_processing.py

它会创建多个 Python 子进程,每个子进程执行 Robot keyword。

整体流程:

复制代码
复制代码
Robot Test Case

        |
        v

Execute Process

        |
        v

jobs_processing.py

        |
        v

multiprocessing.Process

        |
        v

Robot Keyword Execution

二、第一个问题:Execute Process 返回结果异常

1. 问题现象

测试执行:

复制代码
复制代码
Stress BMC IPMI Server

出现:

复制代码
复制代码
Stress BMC IPMI Server | FAIL |

One or more IPMI operations has failed.

但是实际观察 IPMI 操作:

  • 命令可以正常执行;
  • BMC 有正常响应;
  • 单独执行 keyword 可以成功。

查看返回结果:

复制代码
复制代码
${dict} =
{
    '256555': 'False',
    '256557': 'False',
    '256559': 'False'
}

最终导致:

复制代码
复制代码
Dictionary Should Not Contain Value
...    ${dict}
...    False

失败。

问题看起来像是 IPMI 执行失败,但实际并不是。


三、定位 jobs_processing.py

继续检查:

复制代码
复制代码
lib/jobs_processing.py

关键代码:

复制代码
复制代码
def execute_keyword(keyword_name, return_dict):

    pid = os.getpid()

    status = BuiltIn().run_keyword_and_return_status(keyword_name)

    return_dict[str(pid)] = str(status)

这里没有问题。

子进程执行结果:

复制代码
复制代码
True / False

可以正常写入。

继续查看:

复制代码
复制代码
def execute_process(num_process, keyword_name):

    manager = Manager()
    return_dict = manager.dict()

    ...

    return return_dict

问题出现在这里。


四、Manager.dict() 与普通 dict 的区别

Python multiprocessing 提供:

复制代码
复制代码
Manager()

用于创建多个进程之间共享的数据。

例如:

复制代码
复制代码
manager = Manager()

return_dict = manager.dict()

这个对象并不是普通 Python dictionary。

它实际上是:

复制代码
复制代码
DictProxy Object

结构类似:

复制代码
复制代码
Process A
    |
Process B
    |
Process C

        |
        v

Manager Server

        |
        v

Dict Proxy

它通过 IPC(进程间通信)访问真实数据。

因此:

复制代码
复制代码
return return_dict

返回的是:

复制代码
复制代码
multiprocessing.managers.DictProxy

而不是:

复制代码
复制代码
dict

五、解决方案

将返回值转换成普通 Python dictionary。

修改:

复制代码
复制代码
- return return_dict
+ return dict(return_dict)

修改后:

复制代码
复制代码
def execute_process(num_process, keyword_name):

    manager = Manager()
    return_dict = manager.dict()

    ...

    return dict(return_dict)

六、修改效果

修改后:

返回:

复制代码
复制代码
{
    "256555": "True",
    "256557": "True",
    "256559": "True"
}

Robot Framework 可以正常处理:

复制代码
复制代码
Dictionary Should Not Contain Value
...    ${dict}
...    False

测试结果恢复正常。


七、第二个问题:output.xml 损坏

修复返回结果问题后,又发现另一个问题。

这次测试本身:

复制代码
复制代码
PASS

例如:

复制代码
复制代码
Stress BMC IPMI Server :: Execute maximum allowed IPMI operation. | PASS |

但是测试结束后:

Robot Framework 无法解析:

复制代码
复制代码
output.xml

错误:

复制代码
复制代码
[ ERROR ] Reading XML source 'output.xml' failed:

ParseError:
XML or text declaration not at start of entity

八、分析损坏的 output.xml

打开:

复制代码
复制代码
output.xml

发现:

文件中出现重复 XML 声明:

复制代码
复制代码
<?xml version="1.0" encoding="UTF-8"?>

<robot>

...

<?xml version="1.0" encoding="UTF-8"?>

<robot>

正常 XML:

复制代码
复制代码
XML declaration
        |
        v
<robot>
        |
        v
test cases

而异常 XML:

复制代码
复制代码
XML declaration
        |
        v
<robot>
        |
        v
XML declaration
        |
        v
<robot>

因此 XML parser 报错。


九、为什么直接执行 ipmitool 没问题?

原测试:

复制代码
复制代码
Run IPMI Standard Command
...    chassis status

执行路径:

复制代码
复制代码
Robot keyword

        |

Run IPMI Standard Command

        |

IPMI library

        |

ipmitool

替换为:

复制代码
复制代码
${cmd}=    Catenate
...    ipmitool
...    chassis status


Run And Return Rc And Output
...    ${cmd}

执行:

复制代码
复制代码
Robot

 |

Shell

 |

ipmitool

测试通过:

  • IPMI 操作成功;
  • output.xml 正常。

说明:

问题并不是 IPMI 命令本身。

更可能与:

  • Robot keyword 调用方式;
  • 多进程执行;
  • keyword 输出处理;

有关。


十、Workaround

将:

复制代码
复制代码
Run IPMI Standard Command
...    chassis status

替换:

复制代码
复制代码
IPMI Check Status
    ${cmd}=    Catenate
    ...    ipmitool
    ...    -I lanplus
    ...    -C ${IPMI_CIPHER_LEVEL}
    ...    -N 3
    ...    -p ${IPMI_PORT}
    ...    -U ${OPENBMC_USERNAME}
    ...    -P ${OPENBMC_PASSWORD}
    ...    -H ${OPENBMC_HOST}
    ...    chassis status

    ${rc}    ${output}=    
    ...    Run And Return Rc And Output
    ...    ${cmd}

    Should Be Equal As Integers
    ...    ${rc}
    ...    0

十一、经验总结

1. multiprocessing 返回对象要注意类型

在 Python multiprocessing 中:

复制代码
复制代码
Manager().dict()

不是:

复制代码
复制代码
dict

而是:

复制代码
复制代码
DictProxy

跨框架传递时,最好转换:

复制代码
复制代码
dict(proxy)

避免调用方无法正确处理。


2. 自动化框架问题不一定来自测试目标

本次问题初看像:

复制代码
复制代码
IPMI stress失败

实际上:

第一个问题:

复制代码
复制代码
multiprocessing result handling

第二个问题:

复制代码
复制代码
Robot output generation

测试目标 BMC/IPMI 本身没有问题。


3. PASS 不代表测试链路完整成功

Robot Framework 流程:

复制代码
复制代码
Test Execution

        |

        v

Generate output.xml

        |

        v

Generate log/report

任何一步失败都会影响 CI。

因此:

复制代码
复制代码
Test PASS

不一定代表:

复制代码
复制代码
Automation Pipeline PASS

十二、总结

本次 OpenBMC stress 测试问题最终发现两个独立问题:

问题 位置 解决方式
Execute Process 返回结果异常 jobs_processing.py return dict(return_dict)
output.xml 损坏 Robot 执行链路 使用直接 ipmitool workaround

其中第一个问题已经通过代码修改解决;第二个问题仍需要进一步分析 Robot Framework 多进程执行和输出处理机制。

这类问题说明,在复杂自动化测试框架中,测试框架自身的稳定性与被测对象稳定性同样重要。

相关推荐
饕餮争锋1 小时前
PATH路径列表介绍
java·linux·服务器
V158897262011 小时前
从滴滴模式看机器人租赁:撮合型租赁平台开发源码的调度系统设计思路
linux·前端·机器人
可乐鸡翅yeah_1 小时前
M3U8测试流使用指南,流媒体开发自测与环境校验标准化方案
网络·ffmpeg·音视频·m3u8·m3u8在线·音视频在线播放
伯恩bourne1 小时前
Qdrant 快速入门 :数据模型介绍
服务器·数据库·人工智能
z落落1 小时前
C#简易聊天室(服务器+客户端)
运维·服务器·c#
代码村新手1 小时前
Linux-vim的使用和配置
linux
爱喝水的鱼丶1 小时前
SAP-ABAP: BAdI 开发规范与避坑指南:10 类典型错误与运维方案
运维·性能优化·sap·abap·增强·经验交流·开发交流
CDN3601 小时前
CDN 回源负载均衡实战:解决多源站回源流量不均、源站单点故障,出海业务配置指南
运维·负载均衡
吴声子夜歌1 小时前
编写Shell脚本——启动项目
linux·运维·shell